s4-smbtorture: add ndr test for nbt_netlogon_packet to avoid future regressions.
[Samba/gebeck_regimport.git] / source3 / smbd / reply.c
blob7dd3260f0b05532a992cc26b447b9070c45835c5
1 /*
2 Unix SMB/CIFS implementation.
3 Main SMB reply routines
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Andrew Bartlett 2001
6 Copyright (C) Jeremy Allison 1992-2007.
7 Copyright (C) Volker Lendecke 2007
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 This file handles most of the reply_ calls that the server
24 makes to handle specific protocols
27 #include "includes.h"
28 #include "system/filesys.h"
29 #include "printing.h"
30 #include "smbd/smbd.h"
31 #include "smbd/globals.h"
32 #include "fake_file.h"
33 #include "rpc_client/rpc_client.h"
34 #include "../librpc/gen_ndr/ndr_spoolss_c.h"
35 #include "rpc_client/cli_spoolss.h"
36 #include "rpc_client/init_spoolss.h"
37 #include "rpc_server/rpc_ncacn_np.h"
38 #include "libcli/security/security.h"
39 #include "libsmb/nmblib.h"
40 #include "auth.h"
41 #include "smbprofile.h"
42 #include "../lib/tsocket/tsocket.h"
44 /****************************************************************************
45 Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
46 path or anything including wildcards.
47 We're assuming here that '/' is not the second byte in any multibyte char
48 set (a safe assumption). '\\' *may* be the second byte in a multibyte char
49 set.
50 ****************************************************************************/
52 /* Custom version for processing POSIX paths. */
53 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
55 static NTSTATUS check_path_syntax_internal(char *path,
56 bool posix_path,
57 bool *p_last_component_contains_wcard)
59 char *d = path;
60 const char *s = path;
61 NTSTATUS ret = NT_STATUS_OK;
62 bool start_of_name_component = True;
63 bool stream_started = false;
65 *p_last_component_contains_wcard = False;
67 while (*s) {
68 if (stream_started) {
69 switch (*s) {
70 case '/':
71 case '\\':
72 return NT_STATUS_OBJECT_NAME_INVALID;
73 case ':':
74 if (s[1] == '\0') {
75 return NT_STATUS_OBJECT_NAME_INVALID;
77 if (strchr_m(&s[1], ':')) {
78 return NT_STATUS_OBJECT_NAME_INVALID;
80 break;
84 if ((*s == ':') && !posix_path && !stream_started) {
85 if (*p_last_component_contains_wcard) {
86 return NT_STATUS_OBJECT_NAME_INVALID;
88 /* Stream names allow more characters than file names.
89 We're overloading posix_path here to allow a wider
90 range of characters. If stream_started is true this
91 is still a Windows path even if posix_path is true.
92 JRA.
94 stream_started = true;
95 start_of_name_component = false;
96 posix_path = true;
98 if (s[1] == '\0') {
99 return NT_STATUS_OBJECT_NAME_INVALID;
103 if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
105 * Safe to assume is not the second part of a mb char
106 * as this is handled below.
108 /* Eat multiple '/' or '\\' */
109 while (IS_PATH_SEP(*s,posix_path)) {
110 s++;
112 if ((d != path) && (*s != '\0')) {
113 /* We only care about non-leading or trailing '/' or '\\' */
114 *d++ = '/';
117 start_of_name_component = True;
118 /* New component. */
119 *p_last_component_contains_wcard = False;
120 continue;
123 if (start_of_name_component) {
124 if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
125 /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
128 * No mb char starts with '.' so we're safe checking the directory separator here.
131 /* If we just added a '/' - delete it */
132 if ((d > path) && (*(d-1) == '/')) {
133 *(d-1) = '\0';
134 d--;
137 /* Are we at the start ? Can't go back further if so. */
138 if (d <= path) {
139 ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
140 break;
142 /* Go back one level... */
143 /* We know this is safe as '/' cannot be part of a mb sequence. */
144 /* NOTE - if this assumption is invalid we are not in good shape... */
145 /* Decrement d first as d points to the *next* char to write into. */
146 for (d--; d > path; d--) {
147 if (*d == '/')
148 break;
150 s += 2; /* Else go past the .. */
151 /* We're still at the start of a name component, just the previous one. */
152 continue;
154 } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
155 if (posix_path) {
156 /* Eat the '.' */
157 s++;
158 continue;
164 if (!(*s & 0x80)) {
165 if (!posix_path) {
166 if (*s <= 0x1f || *s == '|') {
167 return NT_STATUS_OBJECT_NAME_INVALID;
169 switch (*s) {
170 case '*':
171 case '?':
172 case '<':
173 case '>':
174 case '"':
175 *p_last_component_contains_wcard = True;
176 break;
177 default:
178 break;
181 *d++ = *s++;
182 } else {
183 size_t siz;
184 /* Get the size of the next MB character. */
185 next_codepoint(s,&siz);
186 switch(siz) {
187 case 5:
188 *d++ = *s++;
189 /*fall through*/
190 case 4:
191 *d++ = *s++;
192 /*fall through*/
193 case 3:
194 *d++ = *s++;
195 /*fall through*/
196 case 2:
197 *d++ = *s++;
198 /*fall through*/
199 case 1:
200 *d++ = *s++;
201 break;
202 default:
203 DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
204 *d = '\0';
205 return NT_STATUS_INVALID_PARAMETER;
208 start_of_name_component = False;
211 *d = '\0';
213 return ret;
216 /****************************************************************************
217 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
218 No wildcards allowed.
219 ****************************************************************************/
221 NTSTATUS check_path_syntax(char *path)
223 bool ignore;
224 return check_path_syntax_internal(path, False, &ignore);
227 /****************************************************************************
228 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
229 Wildcards allowed - p_contains_wcard returns true if the last component contained
230 a wildcard.
231 ****************************************************************************/
233 NTSTATUS check_path_syntax_wcard(char *path, bool *p_contains_wcard)
235 return check_path_syntax_internal(path, False, p_contains_wcard);
238 /****************************************************************************
239 Check the path for a POSIX client.
240 We're assuming here that '/' is not the second byte in any multibyte char
241 set (a safe assumption).
242 ****************************************************************************/
244 NTSTATUS check_path_syntax_posix(char *path)
246 bool ignore;
247 return check_path_syntax_internal(path, True, &ignore);
250 /****************************************************************************
251 Pull a string and check the path allowing a wilcard - provide for error return.
252 ****************************************************************************/
254 size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
255 const char *base_ptr,
256 uint16 smb_flags2,
257 char **pp_dest,
258 const char *src,
259 size_t src_len,
260 int flags,
261 NTSTATUS *err,
262 bool *contains_wcard)
264 size_t ret;
266 *pp_dest = NULL;
268 ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
269 src_len, flags);
271 if (!*pp_dest) {
272 *err = NT_STATUS_INVALID_PARAMETER;
273 return ret;
276 *contains_wcard = False;
278 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
280 * For a DFS path the function parse_dfs_path()
281 * will do the path processing, just make a copy.
283 *err = NT_STATUS_OK;
284 return ret;
287 if (lp_posix_pathnames()) {
288 *err = check_path_syntax_posix(*pp_dest);
289 } else {
290 *err = check_path_syntax_wcard(*pp_dest, contains_wcard);
293 return ret;
296 /****************************************************************************
297 Pull a string and check the path - provide for error return.
298 ****************************************************************************/
300 size_t srvstr_get_path(TALLOC_CTX *ctx,
301 const char *base_ptr,
302 uint16 smb_flags2,
303 char **pp_dest,
304 const char *src,
305 size_t src_len,
306 int flags,
307 NTSTATUS *err)
309 bool ignore;
310 return srvstr_get_path_wcard(ctx, base_ptr, smb_flags2, pp_dest, src,
311 src_len, flags, err, &ignore);
314 size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req,
315 char **pp_dest, const char *src, int flags,
316 NTSTATUS *err, bool *contains_wcard)
318 return srvstr_get_path_wcard(mem_ctx, (const char *)req->inbuf, req->flags2,
319 pp_dest, src, smbreq_bufrem(req, src),
320 flags, err, contains_wcard);
323 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
324 char **pp_dest, const char *src, int flags,
325 NTSTATUS *err)
327 bool ignore;
328 return srvstr_get_path_req_wcard(mem_ctx, req, pp_dest, src,
329 flags, err, &ignore);
332 /****************************************************************************
333 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
334 ****************************************************************************/
336 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
337 files_struct *fsp)
339 if ((fsp == NULL) || (conn == NULL)) {
340 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
341 return False;
343 if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
344 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
345 return False;
347 return True;
350 /****************************************************************************
351 Check if we have a correct fsp pointing to a file.
352 ****************************************************************************/
354 bool check_fsp(connection_struct *conn, struct smb_request *req,
355 files_struct *fsp)
357 if (!check_fsp_open(conn, req, fsp)) {
358 return False;
360 if (fsp->is_directory) {
361 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
362 return False;
364 if (fsp->fh->fd == -1) {
365 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
366 return False;
368 fsp->num_smb_operations++;
369 return True;
372 /****************************************************************************
373 Check if we have a correct fsp pointing to a quota fake file. Replacement for
374 the CHECK_NTQUOTA_HANDLE_OK macro.
375 ****************************************************************************/
377 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
378 files_struct *fsp)
380 if (!check_fsp_open(conn, req, fsp)) {
381 return false;
384 if (fsp->is_directory) {
385 return false;
388 if (fsp->fake_file_handle == NULL) {
389 return false;
392 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
393 return false;
396 if (fsp->fake_file_handle->private_data == NULL) {
397 return false;
400 return true;
403 static bool netbios_session_retarget(struct smbd_server_connection *sconn,
404 const char *name, int name_type)
406 char *trim_name;
407 char *trim_name_type;
408 const char *retarget_parm;
409 char *retarget;
410 char *p;
411 int retarget_type = 0x20;
412 int retarget_port = 139;
413 struct sockaddr_storage retarget_addr;
414 struct sockaddr_in *in_addr;
415 bool ret = false;
416 uint8_t outbuf[10];
418 if (get_socket_port(sconn->sock) != 139) {
419 return false;
422 trim_name = talloc_strdup(talloc_tos(), name);
423 if (trim_name == NULL) {
424 goto fail;
426 trim_char(trim_name, ' ', ' ');
428 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
429 name_type);
430 if (trim_name_type == NULL) {
431 goto fail;
434 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
435 trim_name_type, NULL);
436 if (retarget_parm == NULL) {
437 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
438 trim_name, NULL);
440 if (retarget_parm == NULL) {
441 goto fail;
444 retarget = talloc_strdup(trim_name, retarget_parm);
445 if (retarget == NULL) {
446 goto fail;
449 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
451 p = strchr(retarget, ':');
452 if (p != NULL) {
453 *p++ = '\0';
454 retarget_port = atoi(p);
457 p = strchr_m(retarget, '#');
458 if (p != NULL) {
459 *p++ = '\0';
460 if (sscanf(p, "%x", &retarget_type) != 1) {
461 goto fail;
465 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
466 if (!ret) {
467 DEBUG(10, ("could not resolve %s\n", retarget));
468 goto fail;
471 if (retarget_addr.ss_family != AF_INET) {
472 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
473 goto fail;
476 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
478 _smb_setlen(outbuf, 6);
479 SCVAL(outbuf, 0, 0x84);
480 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
481 *(uint16_t *)(outbuf+8) = htons(retarget_port);
483 if (!srv_send_smb(sconn, (char *)outbuf, false, 0, false,
484 NULL)) {
485 exit_server_cleanly("netbios_session_retarget: srv_send_smb "
486 "failed.");
489 ret = true;
490 fail:
491 TALLOC_FREE(trim_name);
492 return ret;
495 static void reply_called_name_not_present(char *outbuf)
497 smb_setlen(outbuf, 1);
498 SCVAL(outbuf, 0, 0x83);
499 SCVAL(outbuf, 4, 0x82);
502 /****************************************************************************
503 Reply to a (netbios-level) special message.
504 ****************************************************************************/
506 void reply_special(struct smbd_server_connection *sconn, char *inbuf, size_t inbuf_size)
508 int msg_type = CVAL(inbuf,0);
509 int msg_flags = CVAL(inbuf,1);
511 * We only really use 4 bytes of the outbuf, but for the smb_setlen
512 * calculation & friends (srv_send_smb uses that) we need the full smb
513 * header.
515 char outbuf[smb_size];
517 memset(outbuf, '\0', sizeof(outbuf));
519 smb_setlen(outbuf,0);
521 switch (msg_type) {
522 case NBSSrequest: /* session request */
524 /* inbuf_size is guarenteed to be at least 4. */
525 fstring name1,name2;
526 int name_type1, name_type2;
527 int name_len1, name_len2;
529 *name1 = *name2 = 0;
531 if (sconn->nbt.got_session) {
532 exit_server_cleanly("multiple session request not permitted");
535 SCVAL(outbuf,0,NBSSpositive);
536 SCVAL(outbuf,3,0);
538 /* inbuf_size is guaranteed to be at least 4. */
539 name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
540 if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
541 DEBUG(0,("Invalid name length in session request\n"));
542 reply_called_name_not_present(outbuf);
543 break;
545 name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
546 if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
547 DEBUG(0,("Invalid name length in session request\n"));
548 reply_called_name_not_present(outbuf);
549 break;
552 name_type1 = name_extract((unsigned char *)inbuf,
553 inbuf_size,(unsigned int)4,name1);
554 name_type2 = name_extract((unsigned char *)inbuf,
555 inbuf_size,(unsigned int)(4 + name_len1),name2);
557 if (name_type1 == -1 || name_type2 == -1) {
558 DEBUG(0,("Invalid name type in session request\n"));
559 reply_called_name_not_present(outbuf);
560 break;
563 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
564 name1, name_type1, name2, name_type2));
566 if (netbios_session_retarget(sconn, name1, name_type1)) {
567 exit_server_cleanly("retargeted client");
571 * Windows NT/2k uses "*SMBSERVER" and XP uses
572 * "*SMBSERV" arrggg!!!
574 if (strequal(name1, "*SMBSERVER ")
575 || strequal(name1, "*SMBSERV ")) {
576 char *raddr;
578 raddr = tsocket_address_inet_addr_string(sconn->remote_address,
579 talloc_tos());
580 if (raddr == NULL) {
581 exit_server_cleanly("could not allocate raddr");
584 fstrcpy(name1, raddr);
587 set_local_machine_name(name1, True);
588 set_remote_machine_name(name2, True);
590 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
591 get_local_machine_name(), get_remote_machine_name(),
592 name_type2));
594 if (name_type2 == 'R') {
595 /* We are being asked for a pathworks session ---
596 no thanks! */
597 reply_called_name_not_present(outbuf);
598 break;
601 /* only add the client's machine name to the list
602 of possibly valid usernames if we are operating
603 in share mode security */
604 if (lp_security() == SEC_SHARE) {
605 add_session_user(sconn, get_remote_machine_name());
608 reload_services(sconn->msg_ctx, sconn->sock, True);
609 reopen_logs();
611 sconn->nbt.got_session = true;
612 break;
615 case 0x89: /* session keepalive request
616 (some old clients produce this?) */
617 SCVAL(outbuf,0,NBSSkeepalive);
618 SCVAL(outbuf,3,0);
619 break;
621 case NBSSpositive: /* positive session response */
622 case NBSSnegative: /* negative session response */
623 case NBSSretarget: /* retarget session response */
624 DEBUG(0,("Unexpected session response\n"));
625 break;
627 case NBSSkeepalive: /* session keepalive */
628 default:
629 return;
632 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
633 msg_type, msg_flags));
635 srv_send_smb(sconn, outbuf, false, 0, false, NULL);
637 if (CVAL(outbuf, 0) != 0x82) {
638 exit_server_cleanly("invalid netbios session");
640 return;
643 /****************************************************************************
644 Reply to a tcon.
645 conn POINTER CAN BE NULL HERE !
646 ****************************************************************************/
648 void reply_tcon(struct smb_request *req)
650 connection_struct *conn = req->conn;
651 const char *service;
652 char *service_buf = NULL;
653 char *password = NULL;
654 char *dev = NULL;
655 int pwlen=0;
656 NTSTATUS nt_status;
657 const char *p;
658 DATA_BLOB password_blob;
659 TALLOC_CTX *ctx = talloc_tos();
660 struct smbd_server_connection *sconn = req->sconn;
662 START_PROFILE(SMBtcon);
664 if (req->buflen < 4) {
665 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
666 END_PROFILE(SMBtcon);
667 return;
670 p = (const char *)req->buf + 1;
671 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
672 p += 1;
673 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
674 p += pwlen+1;
675 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
676 p += 1;
678 if (service_buf == NULL || password == NULL || dev == NULL) {
679 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
680 END_PROFILE(SMBtcon);
681 return;
683 p = strrchr_m(service_buf,'\\');
684 if (p) {
685 service = p+1;
686 } else {
687 service = service_buf;
690 password_blob = data_blob(password, pwlen+1);
692 conn = make_connection(sconn,service,password_blob,dev,
693 req->vuid,&nt_status);
694 req->conn = conn;
696 data_blob_clear_free(&password_blob);
698 if (!conn) {
699 reply_nterror(req, nt_status);
700 END_PROFILE(SMBtcon);
701 return;
704 reply_outbuf(req, 2, 0);
705 SSVAL(req->outbuf,smb_vwv0,sconn->smb1.negprot.max_recv);
706 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
707 SSVAL(req->outbuf,smb_tid,conn->cnum);
709 DEBUG(3,("tcon service=%s cnum=%d\n",
710 service, conn->cnum));
712 END_PROFILE(SMBtcon);
713 return;
716 /****************************************************************************
717 Reply to a tcon and X.
718 conn POINTER CAN BE NULL HERE !
719 ****************************************************************************/
721 void reply_tcon_and_X(struct smb_request *req)
723 connection_struct *conn = req->conn;
724 const char *service = NULL;
725 DATA_BLOB password;
726 TALLOC_CTX *ctx = talloc_tos();
727 /* what the cleint thinks the device is */
728 char *client_devicetype = NULL;
729 /* what the server tells the client the share represents */
730 const char *server_devicetype;
731 NTSTATUS nt_status;
732 int passlen;
733 char *path = NULL;
734 const char *p, *q;
735 uint16 tcon_flags;
736 struct smbd_server_connection *sconn = req->sconn;
738 START_PROFILE(SMBtconX);
740 if (req->wct < 4) {
741 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
742 END_PROFILE(SMBtconX);
743 return;
746 passlen = SVAL(req->vwv+3, 0);
747 tcon_flags = SVAL(req->vwv+2, 0);
749 /* we might have to close an old one */
750 if ((tcon_flags & 0x1) && conn) {
751 close_cnum(conn,req->vuid);
752 req->conn = NULL;
753 conn = NULL;
756 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
757 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
758 END_PROFILE(SMBtconX);
759 return;
762 if (sconn->smb1.negprot.encrypted_passwords) {
763 password = data_blob_talloc(talloc_tos(), req->buf, passlen);
764 if (lp_security() == SEC_SHARE) {
766 * Security = share always has a pad byte
767 * after the password.
769 p = (const char *)req->buf + passlen + 1;
770 } else {
771 p = (const char *)req->buf + passlen;
773 } else {
774 password = data_blob_talloc(talloc_tos(), req->buf, passlen+1);
775 /* Ensure correct termination */
776 password.data[passlen]=0;
777 p = (const char *)req->buf + passlen + 1;
780 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
782 if (path == NULL) {
783 data_blob_clear_free(&password);
784 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
785 END_PROFILE(SMBtconX);
786 return;
790 * the service name can be either: \\server\share
791 * or share directly like on the DELL PowerVault 705
793 if (*path=='\\') {
794 q = strchr_m(path+2,'\\');
795 if (!q) {
796 data_blob_clear_free(&password);
797 reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
798 END_PROFILE(SMBtconX);
799 return;
801 service = q+1;
802 } else {
803 service = path;
806 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
807 &client_devicetype, p,
808 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
810 if (client_devicetype == NULL) {
811 data_blob_clear_free(&password);
812 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
813 END_PROFILE(SMBtconX);
814 return;
817 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
819 conn = make_connection(sconn, service, password, client_devicetype,
820 req->vuid, &nt_status);
821 req->conn =conn;
823 data_blob_clear_free(&password);
825 if (!conn) {
826 reply_nterror(req, nt_status);
827 END_PROFILE(SMBtconX);
828 return;
831 if ( IS_IPC(conn) )
832 server_devicetype = "IPC";
833 else if ( IS_PRINT(conn) )
834 server_devicetype = "LPT1:";
835 else
836 server_devicetype = "A:";
838 if (get_Protocol() < PROTOCOL_NT1) {
839 reply_outbuf(req, 2, 0);
840 if (message_push_string(&req->outbuf, server_devicetype,
841 STR_TERMINATE|STR_ASCII) == -1) {
842 reply_nterror(req, NT_STATUS_NO_MEMORY);
843 END_PROFILE(SMBtconX);
844 return;
846 } else {
847 /* NT sets the fstype of IPC$ to the null string */
848 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
850 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
851 /* Return permissions. */
852 uint32 perm1 = 0;
853 uint32 perm2 = 0;
855 reply_outbuf(req, 7, 0);
857 if (IS_IPC(conn)) {
858 perm1 = FILE_ALL_ACCESS;
859 perm2 = FILE_ALL_ACCESS;
860 } else {
861 perm1 = conn->share_access;
864 SIVAL(req->outbuf, smb_vwv3, perm1);
865 SIVAL(req->outbuf, smb_vwv5, perm2);
866 } else {
867 reply_outbuf(req, 3, 0);
870 if ((message_push_string(&req->outbuf, server_devicetype,
871 STR_TERMINATE|STR_ASCII) == -1)
872 || (message_push_string(&req->outbuf, fstype,
873 STR_TERMINATE) == -1)) {
874 reply_nterror(req, NT_STATUS_NO_MEMORY);
875 END_PROFILE(SMBtconX);
876 return;
879 /* what does setting this bit do? It is set by NT4 and
880 may affect the ability to autorun mounted cdroms */
881 SSVAL(req->outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS|
882 (lp_csc_policy(SNUM(conn)) << 2));
884 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
885 DEBUG(2,("Serving %s as a Dfs root\n",
886 lp_servicename(SNUM(conn)) ));
887 SSVAL(req->outbuf, smb_vwv2,
888 SMB_SHARE_IN_DFS | SVAL(req->outbuf, smb_vwv2));
893 DEBUG(3,("tconX service=%s \n",
894 service));
896 /* set the incoming and outgoing tid to the just created one */
897 SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
898 SSVAL(req->outbuf,smb_tid,conn->cnum);
900 END_PROFILE(SMBtconX);
902 req->tid = conn->cnum;
903 chain_reply(req);
904 return;
907 /****************************************************************************
908 Reply to an unknown type.
909 ****************************************************************************/
911 void reply_unknown_new(struct smb_request *req, uint8 type)
913 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
914 smb_fn_name(type), type, type));
915 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
916 return;
919 /****************************************************************************
920 Reply to an ioctl.
921 conn POINTER CAN BE NULL HERE !
922 ****************************************************************************/
924 void reply_ioctl(struct smb_request *req)
926 connection_struct *conn = req->conn;
927 uint16 device;
928 uint16 function;
929 uint32 ioctl_code;
930 int replysize;
931 char *p;
933 START_PROFILE(SMBioctl);
935 if (req->wct < 3) {
936 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
937 END_PROFILE(SMBioctl);
938 return;
941 device = SVAL(req->vwv+1, 0);
942 function = SVAL(req->vwv+2, 0);
943 ioctl_code = (device << 16) + function;
945 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
947 switch (ioctl_code) {
948 case IOCTL_QUERY_JOB_INFO:
949 replysize = 32;
950 break;
951 default:
952 reply_force_doserror(req, ERRSRV, ERRnosupport);
953 END_PROFILE(SMBioctl);
954 return;
957 reply_outbuf(req, 8, replysize+1);
958 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
959 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
960 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
961 p = smb_buf(req->outbuf);
962 memset(p, '\0', replysize+1); /* valgrind-safe. */
963 p += 1; /* Allow for alignment */
965 switch (ioctl_code) {
966 case IOCTL_QUERY_JOB_INFO:
968 files_struct *fsp = file_fsp(
969 req, SVAL(req->vwv+0, 0));
970 if (!fsp) {
971 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
972 END_PROFILE(SMBioctl);
973 return;
975 /* Job number */
976 if (fsp->print_file) {
977 SSVAL(p, 0, fsp->print_file->rap_jobid);
978 } else {
979 SSVAL(p, 0, 0);
981 srvstr_push((char *)req->outbuf, req->flags2, p+2,
982 lp_netbios_name(), 15,
983 STR_TERMINATE|STR_ASCII);
984 if (conn) {
985 srvstr_push((char *)req->outbuf, req->flags2,
986 p+18, lp_servicename(SNUM(conn)),
987 13, STR_TERMINATE|STR_ASCII);
988 } else {
989 memset(p+18, 0, 13);
991 break;
995 END_PROFILE(SMBioctl);
996 return;
999 /****************************************************************************
1000 Strange checkpath NTSTATUS mapping.
1001 ****************************************************************************/
1003 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
1005 /* Strange DOS error code semantics only for checkpath... */
1006 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
1007 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
1008 /* We need to map to ERRbadpath */
1009 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1012 return status;
1015 /****************************************************************************
1016 Reply to a checkpath.
1017 ****************************************************************************/
1019 void reply_checkpath(struct smb_request *req)
1021 connection_struct *conn = req->conn;
1022 struct smb_filename *smb_fname = NULL;
1023 char *name = NULL;
1024 NTSTATUS status;
1025 TALLOC_CTX *ctx = talloc_tos();
1027 START_PROFILE(SMBcheckpath);
1029 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
1030 STR_TERMINATE, &status);
1032 if (!NT_STATUS_IS_OK(status)) {
1033 status = map_checkpath_error(req->flags2, status);
1034 reply_nterror(req, status);
1035 END_PROFILE(SMBcheckpath);
1036 return;
1039 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1041 status = filename_convert(ctx,
1042 conn,
1043 req->flags2 & FLAGS2_DFS_PATHNAMES,
1044 name,
1046 NULL,
1047 &smb_fname);
1049 if (!NT_STATUS_IS_OK(status)) {
1050 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1051 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1052 ERRSRV, ERRbadpath);
1053 END_PROFILE(SMBcheckpath);
1054 return;
1056 goto path_err;
1059 if (!VALID_STAT(smb_fname->st) &&
1060 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1061 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1062 smb_fname_str_dbg(smb_fname), strerror(errno)));
1063 status = map_nt_error_from_unix(errno);
1064 goto path_err;
1067 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1068 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1069 ERRDOS, ERRbadpath);
1070 goto out;
1073 reply_outbuf(req, 0, 0);
1075 path_err:
1076 /* We special case this - as when a Windows machine
1077 is parsing a path is steps through the components
1078 one at a time - if a component fails it expects
1079 ERRbadpath, not ERRbadfile.
1081 status = map_checkpath_error(req->flags2, status);
1082 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1084 * Windows returns different error codes if
1085 * the parent directory is valid but not the
1086 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1087 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1088 * if the path is invalid.
1090 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1091 ERRDOS, ERRbadpath);
1092 goto out;
1095 reply_nterror(req, status);
1097 out:
1098 TALLOC_FREE(smb_fname);
1099 END_PROFILE(SMBcheckpath);
1100 return;
1103 /****************************************************************************
1104 Reply to a getatr.
1105 ****************************************************************************/
1107 void reply_getatr(struct smb_request *req)
1109 connection_struct *conn = req->conn;
1110 struct smb_filename *smb_fname = NULL;
1111 char *fname = NULL;
1112 int mode=0;
1113 SMB_OFF_T size=0;
1114 time_t mtime=0;
1115 const char *p;
1116 NTSTATUS status;
1117 TALLOC_CTX *ctx = talloc_tos();
1118 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1120 START_PROFILE(SMBgetatr);
1122 p = (const char *)req->buf + 1;
1123 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1124 if (!NT_STATUS_IS_OK(status)) {
1125 reply_nterror(req, status);
1126 goto out;
1129 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1130 under WfWg - weird! */
1131 if (*fname == '\0') {
1132 mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1133 if (!CAN_WRITE(conn)) {
1134 mode |= FILE_ATTRIBUTE_READONLY;
1136 size = 0;
1137 mtime = 0;
1138 } else {
1139 status = filename_convert(ctx,
1140 conn,
1141 req->flags2 & FLAGS2_DFS_PATHNAMES,
1142 fname,
1144 NULL,
1145 &smb_fname);
1146 if (!NT_STATUS_IS_OK(status)) {
1147 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1148 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1149 ERRSRV, ERRbadpath);
1150 goto out;
1152 reply_nterror(req, status);
1153 goto out;
1155 if (!VALID_STAT(smb_fname->st) &&
1156 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1157 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1158 smb_fname_str_dbg(smb_fname),
1159 strerror(errno)));
1160 reply_nterror(req, map_nt_error_from_unix(errno));
1161 goto out;
1164 mode = dos_mode(conn, smb_fname);
1165 size = smb_fname->st.st_ex_size;
1167 if (ask_sharemode) {
1168 struct timespec write_time_ts;
1169 struct file_id fileid;
1171 ZERO_STRUCT(write_time_ts);
1172 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1173 get_file_infos(fileid, 0, NULL, &write_time_ts);
1174 if (!null_timespec(write_time_ts)) {
1175 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1179 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1180 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1181 size = 0;
1185 reply_outbuf(req, 10, 0);
1187 SSVAL(req->outbuf,smb_vwv0,mode);
1188 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1189 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1190 } else {
1191 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1193 SIVAL(req->outbuf,smb_vwv3,(uint32)size);
1195 if (get_Protocol() >= PROTOCOL_NT1) {
1196 SSVAL(req->outbuf, smb_flg2,
1197 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1200 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1201 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1203 out:
1204 TALLOC_FREE(smb_fname);
1205 TALLOC_FREE(fname);
1206 END_PROFILE(SMBgetatr);
1207 return;
1210 /****************************************************************************
1211 Reply to a setatr.
1212 ****************************************************************************/
1214 void reply_setatr(struct smb_request *req)
1216 struct smb_file_time ft;
1217 connection_struct *conn = req->conn;
1218 struct smb_filename *smb_fname = NULL;
1219 char *fname = NULL;
1220 int mode;
1221 time_t mtime;
1222 const char *p;
1223 NTSTATUS status;
1224 TALLOC_CTX *ctx = talloc_tos();
1226 START_PROFILE(SMBsetatr);
1228 ZERO_STRUCT(ft);
1230 if (req->wct < 2) {
1231 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1232 goto out;
1235 p = (const char *)req->buf + 1;
1236 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1237 if (!NT_STATUS_IS_OK(status)) {
1238 reply_nterror(req, status);
1239 goto out;
1242 status = filename_convert(ctx,
1243 conn,
1244 req->flags2 & FLAGS2_DFS_PATHNAMES,
1245 fname,
1247 NULL,
1248 &smb_fname);
1249 if (!NT_STATUS_IS_OK(status)) {
1250 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1251 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1252 ERRSRV, ERRbadpath);
1253 goto out;
1255 reply_nterror(req, status);
1256 goto out;
1259 if (smb_fname->base_name[0] == '.' &&
1260 smb_fname->base_name[1] == '\0') {
1262 * Not sure here is the right place to catch this
1263 * condition. Might be moved to somewhere else later -- vl
1265 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1266 goto out;
1269 mode = SVAL(req->vwv+0, 0);
1270 mtime = srv_make_unix_date3(req->vwv+1);
1272 if (mode != FILE_ATTRIBUTE_NORMAL) {
1273 if (VALID_STAT_OF_DIR(smb_fname->st))
1274 mode |= FILE_ATTRIBUTE_DIRECTORY;
1275 else
1276 mode &= ~FILE_ATTRIBUTE_DIRECTORY;
1278 status = check_access(conn, NULL, smb_fname,
1279 FILE_WRITE_ATTRIBUTES);
1280 if (!NT_STATUS_IS_OK(status)) {
1281 reply_nterror(req, status);
1282 goto out;
1285 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1286 false) != 0) {
1287 reply_nterror(req, map_nt_error_from_unix(errno));
1288 goto out;
1292 ft.mtime = convert_time_t_to_timespec(mtime);
1293 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1294 if (!NT_STATUS_IS_OK(status)) {
1295 reply_nterror(req, status);
1296 goto out;
1299 reply_outbuf(req, 0, 0);
1301 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1302 mode));
1303 out:
1304 TALLOC_FREE(smb_fname);
1305 END_PROFILE(SMBsetatr);
1306 return;
1309 /****************************************************************************
1310 Reply to a dskattr.
1311 ****************************************************************************/
1313 void reply_dskattr(struct smb_request *req)
1315 connection_struct *conn = req->conn;
1316 uint64_t dfree,dsize,bsize;
1317 START_PROFILE(SMBdskattr);
1319 if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (uint64_t)-1) {
1320 reply_nterror(req, map_nt_error_from_unix(errno));
1321 END_PROFILE(SMBdskattr);
1322 return;
1325 reply_outbuf(req, 5, 0);
1327 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1328 double total_space, free_space;
1329 /* we need to scale this to a number that DOS6 can handle. We
1330 use floating point so we can handle large drives on systems
1331 that don't have 64 bit integers
1333 we end up displaying a maximum of 2G to DOS systems
1335 total_space = dsize * (double)bsize;
1336 free_space = dfree * (double)bsize;
1338 dsize = (uint64_t)((total_space+63*512) / (64*512));
1339 dfree = (uint64_t)((free_space+63*512) / (64*512));
1341 if (dsize > 0xFFFF) dsize = 0xFFFF;
1342 if (dfree > 0xFFFF) dfree = 0xFFFF;
1344 SSVAL(req->outbuf,smb_vwv0,dsize);
1345 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1346 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1347 SSVAL(req->outbuf,smb_vwv3,dfree);
1348 } else {
1349 SSVAL(req->outbuf,smb_vwv0,dsize);
1350 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1351 SSVAL(req->outbuf,smb_vwv2,512);
1352 SSVAL(req->outbuf,smb_vwv3,dfree);
1355 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1357 END_PROFILE(SMBdskattr);
1358 return;
1362 * Utility function to split the filename from the directory.
1364 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1365 char **fname_dir_out,
1366 char **fname_mask_out)
1368 const char *p = NULL;
1369 char *fname_dir = NULL;
1370 char *fname_mask = NULL;
1372 p = strrchr_m(fname_in, '/');
1373 if (!p) {
1374 fname_dir = talloc_strdup(ctx, ".");
1375 fname_mask = talloc_strdup(ctx, fname_in);
1376 } else {
1377 fname_dir = talloc_strndup(ctx, fname_in,
1378 PTR_DIFF(p, fname_in));
1379 fname_mask = talloc_strdup(ctx, p+1);
1382 if (!fname_dir || !fname_mask) {
1383 TALLOC_FREE(fname_dir);
1384 TALLOC_FREE(fname_mask);
1385 return NT_STATUS_NO_MEMORY;
1388 *fname_dir_out = fname_dir;
1389 *fname_mask_out = fname_mask;
1390 return NT_STATUS_OK;
1393 /****************************************************************************
1394 Reply to a search.
1395 Can be called from SMBsearch, SMBffirst or SMBfunique.
1396 ****************************************************************************/
1398 void reply_search(struct smb_request *req)
1400 connection_struct *conn = req->conn;
1401 char *path = NULL;
1402 const char *mask = NULL;
1403 char *directory = NULL;
1404 struct smb_filename *smb_fname = NULL;
1405 char *fname = NULL;
1406 SMB_OFF_T size;
1407 uint32 mode;
1408 struct timespec date;
1409 uint32 dirtype;
1410 unsigned int numentries = 0;
1411 unsigned int maxentries = 0;
1412 bool finished = False;
1413 const char *p;
1414 int status_len;
1415 char status[21];
1416 int dptr_num= -1;
1417 bool check_descend = False;
1418 bool expect_close = False;
1419 NTSTATUS nt_status;
1420 bool mask_contains_wcard = False;
1421 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1422 TALLOC_CTX *ctx = talloc_tos();
1423 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1424 struct dptr_struct *dirptr = NULL;
1425 struct smbd_server_connection *sconn = req->sconn;
1427 START_PROFILE(SMBsearch);
1429 if (req->wct < 2) {
1430 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1431 goto out;
1434 if (lp_posix_pathnames()) {
1435 reply_unknown_new(req, req->cmd);
1436 goto out;
1439 /* If we were called as SMBffirst then we must expect close. */
1440 if(req->cmd == SMBffirst) {
1441 expect_close = True;
1444 reply_outbuf(req, 1, 3);
1445 maxentries = SVAL(req->vwv+0, 0);
1446 dirtype = SVAL(req->vwv+1, 0);
1447 p = (const char *)req->buf + 1;
1448 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1449 &nt_status, &mask_contains_wcard);
1450 if (!NT_STATUS_IS_OK(nt_status)) {
1451 reply_nterror(req, nt_status);
1452 goto out;
1455 p++;
1456 status_len = SVAL(p, 0);
1457 p += 2;
1459 /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1461 if (status_len == 0) {
1462 nt_status = filename_convert(ctx, conn,
1463 req->flags2 & FLAGS2_DFS_PATHNAMES,
1464 path,
1465 UCF_ALWAYS_ALLOW_WCARD_LCOMP,
1466 &mask_contains_wcard,
1467 &smb_fname);
1468 if (!NT_STATUS_IS_OK(nt_status)) {
1469 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1470 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1471 ERRSRV, ERRbadpath);
1472 goto out;
1474 reply_nterror(req, nt_status);
1475 goto out;
1478 directory = smb_fname->base_name;
1480 p = strrchr_m(directory,'/');
1481 if ((p != NULL) && (*directory != '/')) {
1482 mask = p + 1;
1483 directory = talloc_strndup(ctx, directory,
1484 PTR_DIFF(p, directory));
1485 } else {
1486 mask = directory;
1487 directory = talloc_strdup(ctx,".");
1490 if (!directory) {
1491 reply_nterror(req, NT_STATUS_NO_MEMORY);
1492 goto out;
1495 memset((char *)status,'\0',21);
1496 SCVAL(status,0,(dirtype & 0x1F));
1498 nt_status = dptr_create(conn,
1499 NULL, /* fsp */
1500 directory,
1501 True,
1502 expect_close,
1503 req->smbpid,
1504 mask,
1505 mask_contains_wcard,
1506 dirtype,
1507 &dirptr);
1508 if (!NT_STATUS_IS_OK(nt_status)) {
1509 reply_nterror(req, nt_status);
1510 goto out;
1512 dptr_num = dptr_dnum(dirptr);
1513 } else {
1514 int status_dirtype;
1515 const char *dirpath;
1517 memcpy(status,p,21);
1518 status_dirtype = CVAL(status,0) & 0x1F;
1519 if (status_dirtype != (dirtype & 0x1F)) {
1520 dirtype = status_dirtype;
1523 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1524 if (!dirptr) {
1525 goto SearchEmpty;
1527 dirpath = dptr_path(sconn, dptr_num);
1528 directory = talloc_strdup(ctx, dirpath);
1529 if (!directory) {
1530 reply_nterror(req, NT_STATUS_NO_MEMORY);
1531 goto out;
1534 mask = dptr_wcard(sconn, dptr_num);
1535 if (!mask) {
1536 goto SearchEmpty;
1539 * For a 'continue' search we have no string. So
1540 * check from the initial saved string.
1542 mask_contains_wcard = ms_has_wild(mask);
1543 dirtype = dptr_attr(sconn, dptr_num);
1546 DEBUG(4,("dptr_num is %d\n",dptr_num));
1548 /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
1549 dptr_init_search_op(dirptr);
1551 if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1552 char buf[DIR_STRUCT_SIZE];
1553 memcpy(buf,status,21);
1554 if (!make_dir_struct(ctx,buf,"???????????",volume_label(SNUM(conn)),
1555 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1556 reply_nterror(req, NT_STATUS_NO_MEMORY);
1557 goto out;
1559 dptr_fill(sconn, buf+12,dptr_num);
1560 if (dptr_zero(buf+12) && (status_len==0)) {
1561 numentries = 1;
1562 } else {
1563 numentries = 0;
1565 if (message_push_blob(&req->outbuf,
1566 data_blob_const(buf, sizeof(buf)))
1567 == -1) {
1568 reply_nterror(req, NT_STATUS_NO_MEMORY);
1569 goto out;
1571 } else {
1572 unsigned int i;
1573 maxentries = MIN(
1574 maxentries,
1575 ((BUFFER_SIZE -
1576 ((uint8 *)smb_buf(req->outbuf) + 3 - req->outbuf))
1577 /DIR_STRUCT_SIZE));
1579 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1580 directory,lp_dontdescend(SNUM(conn))));
1581 if (in_list(directory, lp_dontdescend(SNUM(conn)),True)) {
1582 check_descend = True;
1585 for (i=numentries;(i<maxentries) && !finished;i++) {
1586 finished = !get_dir_entry(ctx,
1587 dirptr,
1588 mask,
1589 dirtype,
1590 &fname,
1591 &size,
1592 &mode,
1593 &date,
1594 check_descend,
1595 ask_sharemode);
1596 if (!finished) {
1597 char buf[DIR_STRUCT_SIZE];
1598 memcpy(buf,status,21);
1599 if (!make_dir_struct(ctx,
1600 buf,
1601 mask,
1602 fname,
1603 size,
1604 mode,
1605 convert_timespec_to_time_t(date),
1606 !allow_long_path_components)) {
1607 reply_nterror(req, NT_STATUS_NO_MEMORY);
1608 goto out;
1610 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1611 break;
1613 if (message_push_blob(&req->outbuf,
1614 data_blob_const(buf, sizeof(buf)))
1615 == -1) {
1616 reply_nterror(req, NT_STATUS_NO_MEMORY);
1617 goto out;
1619 numentries++;
1624 SearchEmpty:
1626 /* If we were called as SMBffirst with smb_search_id == NULL
1627 and no entries were found then return error and close dirptr
1628 (X/Open spec) */
1630 if (numentries == 0) {
1631 dptr_close(sconn, &dptr_num);
1632 } else if(expect_close && status_len == 0) {
1633 /* Close the dptr - we know it's gone */
1634 dptr_close(sconn, &dptr_num);
1637 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1638 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1639 dptr_close(sconn, &dptr_num);
1642 if ((numentries == 0) && !mask_contains_wcard) {
1643 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1644 goto out;
1647 SSVAL(req->outbuf,smb_vwv0,numentries);
1648 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1649 SCVAL(smb_buf(req->outbuf),0,5);
1650 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1652 /* The replies here are never long name. */
1653 SSVAL(req->outbuf, smb_flg2,
1654 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1655 if (!allow_long_path_components) {
1656 SSVAL(req->outbuf, smb_flg2,
1657 SVAL(req->outbuf, smb_flg2)
1658 & (~FLAGS2_LONG_PATH_COMPONENTS));
1661 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
1662 SSVAL(req->outbuf, smb_flg2,
1663 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
1665 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
1666 smb_fn_name(req->cmd),
1667 mask,
1668 directory,
1669 dirtype,
1670 numentries,
1671 maxentries ));
1672 out:
1673 TALLOC_FREE(directory);
1674 TALLOC_FREE(smb_fname);
1675 END_PROFILE(SMBsearch);
1676 return;
1679 /****************************************************************************
1680 Reply to a fclose (stop directory search).
1681 ****************************************************************************/
1683 void reply_fclose(struct smb_request *req)
1685 int status_len;
1686 char status[21];
1687 int dptr_num= -2;
1688 const char *p;
1689 char *path = NULL;
1690 NTSTATUS err;
1691 bool path_contains_wcard = False;
1692 TALLOC_CTX *ctx = talloc_tos();
1693 struct smbd_server_connection *sconn = req->sconn;
1695 START_PROFILE(SMBfclose);
1697 if (lp_posix_pathnames()) {
1698 reply_unknown_new(req, req->cmd);
1699 END_PROFILE(SMBfclose);
1700 return;
1703 p = (const char *)req->buf + 1;
1704 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1705 &err, &path_contains_wcard);
1706 if (!NT_STATUS_IS_OK(err)) {
1707 reply_nterror(req, err);
1708 END_PROFILE(SMBfclose);
1709 return;
1711 p++;
1712 status_len = SVAL(p,0);
1713 p += 2;
1715 if (status_len == 0) {
1716 reply_force_doserror(req, ERRSRV, ERRsrverror);
1717 END_PROFILE(SMBfclose);
1718 return;
1721 memcpy(status,p,21);
1723 if(dptr_fetch(sconn, status+12,&dptr_num)) {
1724 /* Close the dptr - we know it's gone */
1725 dptr_close(sconn, &dptr_num);
1728 reply_outbuf(req, 1, 0);
1729 SSVAL(req->outbuf,smb_vwv0,0);
1731 DEBUG(3,("search close\n"));
1733 END_PROFILE(SMBfclose);
1734 return;
1737 /****************************************************************************
1738 Reply to an open.
1739 ****************************************************************************/
1741 void reply_open(struct smb_request *req)
1743 connection_struct *conn = req->conn;
1744 struct smb_filename *smb_fname = NULL;
1745 char *fname = NULL;
1746 uint32 fattr=0;
1747 SMB_OFF_T size = 0;
1748 time_t mtime=0;
1749 int info;
1750 files_struct *fsp;
1751 int oplock_request;
1752 int deny_mode;
1753 uint32 dos_attr;
1754 uint32 access_mask;
1755 uint32 share_mode;
1756 uint32 create_disposition;
1757 uint32 create_options = 0;
1758 uint32_t private_flags = 0;
1759 NTSTATUS status;
1760 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1761 TALLOC_CTX *ctx = talloc_tos();
1763 START_PROFILE(SMBopen);
1765 if (req->wct < 2) {
1766 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1767 goto out;
1770 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1771 deny_mode = SVAL(req->vwv+0, 0);
1772 dos_attr = SVAL(req->vwv+1, 0);
1774 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
1775 STR_TERMINATE, &status);
1776 if (!NT_STATUS_IS_OK(status)) {
1777 reply_nterror(req, status);
1778 goto out;
1781 status = filename_convert(ctx,
1782 conn,
1783 req->flags2 & FLAGS2_DFS_PATHNAMES,
1784 fname,
1786 NULL,
1787 &smb_fname);
1788 if (!NT_STATUS_IS_OK(status)) {
1789 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1790 reply_botherror(req,
1791 NT_STATUS_PATH_NOT_COVERED,
1792 ERRSRV, ERRbadpath);
1793 goto out;
1795 reply_nterror(req, status);
1796 goto out;
1799 if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode,
1800 OPENX_FILE_EXISTS_OPEN, &access_mask,
1801 &share_mode, &create_disposition,
1802 &create_options, &private_flags)) {
1803 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1804 goto out;
1807 status = SMB_VFS_CREATE_FILE(
1808 conn, /* conn */
1809 req, /* req */
1810 0, /* root_dir_fid */
1811 smb_fname, /* fname */
1812 access_mask, /* access_mask */
1813 share_mode, /* share_access */
1814 create_disposition, /* create_disposition*/
1815 create_options, /* create_options */
1816 dos_attr, /* file_attributes */
1817 oplock_request, /* oplock_request */
1818 0, /* allocation_size */
1819 private_flags,
1820 NULL, /* sd */
1821 NULL, /* ea_list */
1822 &fsp, /* result */
1823 &info); /* pinfo */
1825 if (!NT_STATUS_IS_OK(status)) {
1826 if (open_was_deferred(req->sconn, req->mid)) {
1827 /* We have re-scheduled this call. */
1828 goto out;
1830 reply_openerror(req, status);
1831 goto out;
1834 size = smb_fname->st.st_ex_size;
1835 fattr = dos_mode(conn, smb_fname);
1837 /* Deal with other possible opens having a modified
1838 write time. JRA. */
1839 if (ask_sharemode) {
1840 struct timespec write_time_ts;
1842 ZERO_STRUCT(write_time_ts);
1843 get_file_infos(fsp->file_id, 0, NULL, &write_time_ts);
1844 if (!null_timespec(write_time_ts)) {
1845 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1849 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1851 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
1852 DEBUG(3,("attempt to open a directory %s\n",
1853 fsp_str_dbg(fsp)));
1854 close_file(req, fsp, ERROR_CLOSE);
1855 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
1856 ERRDOS, ERRnoaccess);
1857 goto out;
1860 reply_outbuf(req, 7, 0);
1861 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
1862 SSVAL(req->outbuf,smb_vwv1,fattr);
1863 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1864 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
1865 } else {
1866 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
1868 SIVAL(req->outbuf,smb_vwv4,(uint32)size);
1869 SSVAL(req->outbuf,smb_vwv6,deny_mode);
1871 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1872 SCVAL(req->outbuf,smb_flg,
1873 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1876 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1877 SCVAL(req->outbuf,smb_flg,
1878 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1880 out:
1881 TALLOC_FREE(smb_fname);
1882 END_PROFILE(SMBopen);
1883 return;
1886 /****************************************************************************
1887 Reply to an open and X.
1888 ****************************************************************************/
1890 void reply_open_and_X(struct smb_request *req)
1892 connection_struct *conn = req->conn;
1893 struct smb_filename *smb_fname = NULL;
1894 char *fname = NULL;
1895 uint16 open_flags;
1896 int deny_mode;
1897 uint32 smb_attr;
1898 /* Breakout the oplock request bits so we can set the
1899 reply bits separately. */
1900 int ex_oplock_request;
1901 int core_oplock_request;
1902 int oplock_request;
1903 #if 0
1904 int smb_sattr = SVAL(req->vwv+4, 0);
1905 uint32 smb_time = make_unix_date3(req->vwv+6);
1906 #endif
1907 int smb_ofun;
1908 uint32 fattr=0;
1909 int mtime=0;
1910 int smb_action = 0;
1911 files_struct *fsp;
1912 NTSTATUS status;
1913 uint64_t allocation_size;
1914 ssize_t retval = -1;
1915 uint32 access_mask;
1916 uint32 share_mode;
1917 uint32 create_disposition;
1918 uint32 create_options = 0;
1919 uint32_t private_flags = 0;
1920 TALLOC_CTX *ctx = talloc_tos();
1922 START_PROFILE(SMBopenX);
1924 if (req->wct < 15) {
1925 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1926 goto out;
1929 open_flags = SVAL(req->vwv+2, 0);
1930 deny_mode = SVAL(req->vwv+3, 0);
1931 smb_attr = SVAL(req->vwv+5, 0);
1932 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
1933 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1934 oplock_request = ex_oplock_request | core_oplock_request;
1935 smb_ofun = SVAL(req->vwv+8, 0);
1936 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
1938 /* If it's an IPC, pass off the pipe handler. */
1939 if (IS_IPC(conn)) {
1940 if (lp_nt_pipe_support()) {
1941 reply_open_pipe_and_X(conn, req);
1942 } else {
1943 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
1945 goto out;
1948 /* XXXX we need to handle passed times, sattr and flags */
1949 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
1950 STR_TERMINATE, &status);
1951 if (!NT_STATUS_IS_OK(status)) {
1952 reply_nterror(req, status);
1953 goto out;
1956 status = filename_convert(ctx,
1957 conn,
1958 req->flags2 & FLAGS2_DFS_PATHNAMES,
1959 fname,
1961 NULL,
1962 &smb_fname);
1963 if (!NT_STATUS_IS_OK(status)) {
1964 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1965 reply_botherror(req,
1966 NT_STATUS_PATH_NOT_COVERED,
1967 ERRSRV, ERRbadpath);
1968 goto out;
1970 reply_nterror(req, status);
1971 goto out;
1974 if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode,
1975 smb_ofun,
1976 &access_mask, &share_mode,
1977 &create_disposition,
1978 &create_options,
1979 &private_flags)) {
1980 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1981 goto out;
1984 status = SMB_VFS_CREATE_FILE(
1985 conn, /* conn */
1986 req, /* req */
1987 0, /* root_dir_fid */
1988 smb_fname, /* fname */
1989 access_mask, /* access_mask */
1990 share_mode, /* share_access */
1991 create_disposition, /* create_disposition*/
1992 create_options, /* create_options */
1993 smb_attr, /* file_attributes */
1994 oplock_request, /* oplock_request */
1995 0, /* allocation_size */
1996 private_flags,
1997 NULL, /* sd */
1998 NULL, /* ea_list */
1999 &fsp, /* result */
2000 &smb_action); /* pinfo */
2002 if (!NT_STATUS_IS_OK(status)) {
2003 if (open_was_deferred(req->sconn, req->mid)) {
2004 /* We have re-scheduled this call. */
2005 goto out;
2007 reply_openerror(req, status);
2008 goto out;
2011 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2012 if the file is truncated or created. */
2013 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2014 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2015 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2016 close_file(req, fsp, ERROR_CLOSE);
2017 reply_nterror(req, NT_STATUS_DISK_FULL);
2018 goto out;
2020 retval = vfs_set_filelen(fsp, (SMB_OFF_T)allocation_size);
2021 if (retval < 0) {
2022 close_file(req, fsp, ERROR_CLOSE);
2023 reply_nterror(req, NT_STATUS_DISK_FULL);
2024 goto out;
2026 status = vfs_stat_fsp(fsp);
2027 if (!NT_STATUS_IS_OK(status)) {
2028 close_file(req, fsp, ERROR_CLOSE);
2029 reply_nterror(req, status);
2030 goto out;
2034 fattr = dos_mode(conn, fsp->fsp_name);
2035 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2036 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2037 close_file(req, fsp, ERROR_CLOSE);
2038 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2039 goto out;
2042 /* If the caller set the extended oplock request bit
2043 and we granted one (by whatever means) - set the
2044 correct bit for extended oplock reply.
2047 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2048 smb_action |= EXTENDED_OPLOCK_GRANTED;
2051 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2052 smb_action |= EXTENDED_OPLOCK_GRANTED;
2055 /* If the caller set the core oplock request bit
2056 and we granted one (by whatever means) - set the
2057 correct bit for core oplock reply.
2060 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2061 reply_outbuf(req, 19, 0);
2062 } else {
2063 reply_outbuf(req, 15, 0);
2066 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2067 SCVAL(req->outbuf, smb_flg,
2068 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2071 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2072 SCVAL(req->outbuf, smb_flg,
2073 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2076 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2077 SSVAL(req->outbuf,smb_vwv3,fattr);
2078 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2079 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2080 } else {
2081 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2083 SIVAL(req->outbuf,smb_vwv6,(uint32)fsp->fsp_name->st.st_ex_size);
2084 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2085 SSVAL(req->outbuf,smb_vwv11,smb_action);
2087 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2088 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2091 chain_reply(req);
2092 out:
2093 TALLOC_FREE(smb_fname);
2094 END_PROFILE(SMBopenX);
2095 return;
2098 /****************************************************************************
2099 Reply to a SMBulogoffX.
2100 ****************************************************************************/
2102 void reply_ulogoffX(struct smb_request *req)
2104 struct smbd_server_connection *sconn = req->sconn;
2105 user_struct *vuser;
2107 START_PROFILE(SMBulogoffX);
2109 vuser = get_valid_user_struct(sconn, req->vuid);
2111 if(vuser == NULL) {
2112 DEBUG(3,("ulogoff, vuser id %d does not map to user.\n",
2113 req->vuid));
2116 /* in user level security we are supposed to close any files
2117 open by this user */
2118 if ((vuser != NULL) && (lp_security() != SEC_SHARE)) {
2119 file_close_user(sconn, req->vuid);
2122 invalidate_vuid(sconn, req->vuid);
2124 reply_outbuf(req, 2, 0);
2126 DEBUG( 3, ( "ulogoffX vuid=%d\n", req->vuid ) );
2128 END_PROFILE(SMBulogoffX);
2129 req->vuid = UID_FIELD_INVALID;
2130 chain_reply(req);
2133 /****************************************************************************
2134 Reply to a mknew or a create.
2135 ****************************************************************************/
2137 void reply_mknew(struct smb_request *req)
2139 connection_struct *conn = req->conn;
2140 struct smb_filename *smb_fname = NULL;
2141 char *fname = NULL;
2142 uint32 fattr = 0;
2143 struct smb_file_time ft;
2144 files_struct *fsp;
2145 int oplock_request = 0;
2146 NTSTATUS status;
2147 uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2148 uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2149 uint32 create_disposition;
2150 uint32 create_options = 0;
2151 TALLOC_CTX *ctx = talloc_tos();
2153 START_PROFILE(SMBcreate);
2154 ZERO_STRUCT(ft);
2156 if (req->wct < 3) {
2157 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2158 goto out;
2161 fattr = SVAL(req->vwv+0, 0);
2162 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2164 /* mtime. */
2165 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2167 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2168 STR_TERMINATE, &status);
2169 if (!NT_STATUS_IS_OK(status)) {
2170 reply_nterror(req, status);
2171 goto out;
2174 status = filename_convert(ctx,
2175 conn,
2176 req->flags2 & FLAGS2_DFS_PATHNAMES,
2177 fname,
2179 NULL,
2180 &smb_fname);
2181 if (!NT_STATUS_IS_OK(status)) {
2182 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2183 reply_botherror(req,
2184 NT_STATUS_PATH_NOT_COVERED,
2185 ERRSRV, ERRbadpath);
2186 goto out;
2188 reply_nterror(req, status);
2189 goto out;
2192 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2193 DEBUG(0,("Attempt to create file (%s) with volid set - "
2194 "please report this\n",
2195 smb_fname_str_dbg(smb_fname)));
2198 if(req->cmd == SMBmknew) {
2199 /* We should fail if file exists. */
2200 create_disposition = FILE_CREATE;
2201 } else {
2202 /* Create if file doesn't exist, truncate if it does. */
2203 create_disposition = FILE_OVERWRITE_IF;
2206 status = SMB_VFS_CREATE_FILE(
2207 conn, /* conn */
2208 req, /* req */
2209 0, /* root_dir_fid */
2210 smb_fname, /* fname */
2211 access_mask, /* access_mask */
2212 share_mode, /* share_access */
2213 create_disposition, /* create_disposition*/
2214 create_options, /* create_options */
2215 fattr, /* file_attributes */
2216 oplock_request, /* oplock_request */
2217 0, /* allocation_size */
2218 0, /* private_flags */
2219 NULL, /* sd */
2220 NULL, /* ea_list */
2221 &fsp, /* result */
2222 NULL); /* pinfo */
2224 if (!NT_STATUS_IS_OK(status)) {
2225 if (open_was_deferred(req->sconn, req->mid)) {
2226 /* We have re-scheduled this call. */
2227 goto out;
2229 reply_openerror(req, status);
2230 goto out;
2233 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2234 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2235 if (!NT_STATUS_IS_OK(status)) {
2236 END_PROFILE(SMBcreate);
2237 goto out;
2240 reply_outbuf(req, 1, 0);
2241 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2243 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2244 SCVAL(req->outbuf,smb_flg,
2245 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2248 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2249 SCVAL(req->outbuf,smb_flg,
2250 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2253 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2254 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2255 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2256 (unsigned int)fattr));
2258 out:
2259 TALLOC_FREE(smb_fname);
2260 END_PROFILE(SMBcreate);
2261 return;
2264 /****************************************************************************
2265 Reply to a create temporary file.
2266 ****************************************************************************/
2268 void reply_ctemp(struct smb_request *req)
2270 connection_struct *conn = req->conn;
2271 struct smb_filename *smb_fname = NULL;
2272 char *fname = NULL;
2273 uint32 fattr;
2274 files_struct *fsp;
2275 int oplock_request;
2276 int tmpfd;
2277 char *s;
2278 NTSTATUS status;
2279 TALLOC_CTX *ctx = talloc_tos();
2281 START_PROFILE(SMBctemp);
2283 if (req->wct < 3) {
2284 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2285 goto out;
2288 fattr = SVAL(req->vwv+0, 0);
2289 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2291 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
2292 STR_TERMINATE, &status);
2293 if (!NT_STATUS_IS_OK(status)) {
2294 reply_nterror(req, status);
2295 goto out;
2297 if (*fname) {
2298 fname = talloc_asprintf(ctx,
2299 "%s/TMXXXXXX",
2300 fname);
2301 } else {
2302 fname = talloc_strdup(ctx, "TMXXXXXX");
2305 if (!fname) {
2306 reply_nterror(req, NT_STATUS_NO_MEMORY);
2307 goto out;
2310 status = filename_convert(ctx, conn,
2311 req->flags2 & FLAGS2_DFS_PATHNAMES,
2312 fname,
2314 NULL,
2315 &smb_fname);
2316 if (!NT_STATUS_IS_OK(status)) {
2317 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2318 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2319 ERRSRV, ERRbadpath);
2320 goto out;
2322 reply_nterror(req, status);
2323 goto out;
2326 tmpfd = mkstemp(smb_fname->base_name);
2327 if (tmpfd == -1) {
2328 reply_nterror(req, map_nt_error_from_unix(errno));
2329 goto out;
2332 SMB_VFS_STAT(conn, smb_fname);
2334 /* We should fail if file does not exist. */
2335 status = SMB_VFS_CREATE_FILE(
2336 conn, /* conn */
2337 req, /* req */
2338 0, /* root_dir_fid */
2339 smb_fname, /* fname */
2340 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2341 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2342 FILE_OPEN, /* create_disposition*/
2343 0, /* create_options */
2344 fattr, /* file_attributes */
2345 oplock_request, /* oplock_request */
2346 0, /* allocation_size */
2347 0, /* private_flags */
2348 NULL, /* sd */
2349 NULL, /* ea_list */
2350 &fsp, /* result */
2351 NULL); /* pinfo */
2353 /* close fd from mkstemp() */
2354 close(tmpfd);
2356 if (!NT_STATUS_IS_OK(status)) {
2357 if (open_was_deferred(req->sconn, req->mid)) {
2358 /* We have re-scheduled this call. */
2359 goto out;
2361 reply_openerror(req, status);
2362 goto out;
2365 reply_outbuf(req, 1, 0);
2366 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2368 /* the returned filename is relative to the directory */
2369 s = strrchr_m(fsp->fsp_name->base_name, '/');
2370 if (!s) {
2371 s = fsp->fsp_name->base_name;
2372 } else {
2373 s++;
2376 #if 0
2377 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2378 thing in the byte section. JRA */
2379 SSVALS(p, 0, -1); /* what is this? not in spec */
2380 #endif
2381 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2382 == -1) {
2383 reply_nterror(req, NT_STATUS_NO_MEMORY);
2384 goto out;
2387 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2388 SCVAL(req->outbuf, smb_flg,
2389 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2392 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2393 SCVAL(req->outbuf, smb_flg,
2394 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2397 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2398 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2399 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2400 out:
2401 TALLOC_FREE(smb_fname);
2402 END_PROFILE(SMBctemp);
2403 return;
2406 /*******************************************************************
2407 Check if a user is allowed to rename a file.
2408 ********************************************************************/
2410 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2411 uint16 dirtype)
2413 if (!CAN_WRITE(conn)) {
2414 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2417 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
2418 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2419 /* Only bother to read the DOS attribute if we might deny the
2420 rename on the grounds of attribute missmatch. */
2421 uint32_t fmode = dos_mode(conn, fsp->fsp_name);
2422 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2423 return NT_STATUS_NO_SUCH_FILE;
2427 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2428 if (fsp->posix_open) {
2429 return NT_STATUS_OK;
2432 /* If no pathnames are open below this
2433 directory, allow the rename. */
2435 if (file_find_subpath(fsp)) {
2436 return NT_STATUS_ACCESS_DENIED;
2438 return NT_STATUS_OK;
2441 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2442 return NT_STATUS_OK;
2445 return NT_STATUS_ACCESS_DENIED;
2448 /*******************************************************************
2449 * unlink a file with all relevant access checks
2450 *******************************************************************/
2452 static NTSTATUS do_unlink(connection_struct *conn,
2453 struct smb_request *req,
2454 struct smb_filename *smb_fname,
2455 uint32 dirtype)
2457 uint32 fattr;
2458 files_struct *fsp;
2459 uint32 dirtype_orig = dirtype;
2460 NTSTATUS status;
2461 int ret;
2462 bool posix_paths = lp_posix_pathnames();
2464 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2465 smb_fname_str_dbg(smb_fname),
2466 dirtype));
2468 if (!CAN_WRITE(conn)) {
2469 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2472 if (posix_paths) {
2473 ret = SMB_VFS_LSTAT(conn, smb_fname);
2474 } else {
2475 ret = SMB_VFS_STAT(conn, smb_fname);
2477 if (ret != 0) {
2478 return map_nt_error_from_unix(errno);
2481 fattr = dos_mode(conn, smb_fname);
2483 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2484 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
2487 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
2488 if (!dirtype) {
2489 return NT_STATUS_NO_SUCH_FILE;
2492 if (!dir_check_ftype(conn, fattr, dirtype)) {
2493 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2494 return NT_STATUS_FILE_IS_A_DIRECTORY;
2496 return NT_STATUS_NO_SUCH_FILE;
2499 if (dirtype_orig & 0x8000) {
2500 /* These will never be set for POSIX. */
2501 return NT_STATUS_NO_SUCH_FILE;
2504 #if 0
2505 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2506 return NT_STATUS_FILE_IS_A_DIRECTORY;
2509 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2510 return NT_STATUS_NO_SUCH_FILE;
2513 if (dirtype & 0xFF00) {
2514 /* These will never be set for POSIX. */
2515 return NT_STATUS_NO_SUCH_FILE;
2518 dirtype &= 0xFF;
2519 if (!dirtype) {
2520 return NT_STATUS_NO_SUCH_FILE;
2523 /* Can't delete a directory. */
2524 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2525 return NT_STATUS_FILE_IS_A_DIRECTORY;
2527 #endif
2529 #if 0 /* JRATEST */
2530 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
2531 return NT_STATUS_OBJECT_NAME_INVALID;
2532 #endif /* JRATEST */
2534 /* On open checks the open itself will check the share mode, so
2535 don't do it here as we'll get it wrong. */
2537 status = SMB_VFS_CREATE_FILE
2538 (conn, /* conn */
2539 req, /* req */
2540 0, /* root_dir_fid */
2541 smb_fname, /* fname */
2542 DELETE_ACCESS, /* access_mask */
2543 FILE_SHARE_NONE, /* share_access */
2544 FILE_OPEN, /* create_disposition*/
2545 FILE_NON_DIRECTORY_FILE, /* create_options */
2546 /* file_attributes */
2547 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2548 FILE_ATTRIBUTE_NORMAL,
2549 0, /* oplock_request */
2550 0, /* allocation_size */
2551 0, /* private_flags */
2552 NULL, /* sd */
2553 NULL, /* ea_list */
2554 &fsp, /* result */
2555 NULL); /* pinfo */
2557 if (!NT_STATUS_IS_OK(status)) {
2558 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2559 nt_errstr(status)));
2560 return status;
2563 status = can_set_delete_on_close(fsp, fattr);
2564 if (!NT_STATUS_IS_OK(status)) {
2565 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2566 "(%s)\n",
2567 smb_fname_str_dbg(smb_fname),
2568 nt_errstr(status)));
2569 close_file(req, fsp, NORMAL_CLOSE);
2570 return status;
2573 /* The set is across all open files on this dev/inode pair. */
2574 if (!set_delete_on_close(fsp, True, conn->session_info->unix_token)) {
2575 close_file(req, fsp, NORMAL_CLOSE);
2576 return NT_STATUS_ACCESS_DENIED;
2579 return close_file(req, fsp, NORMAL_CLOSE);
2582 /****************************************************************************
2583 The guts of the unlink command, split out so it may be called by the NT SMB
2584 code.
2585 ****************************************************************************/
2587 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2588 uint32 dirtype, struct smb_filename *smb_fname,
2589 bool has_wild)
2591 char *fname_dir = NULL;
2592 char *fname_mask = NULL;
2593 int count=0;
2594 NTSTATUS status = NT_STATUS_OK;
2595 TALLOC_CTX *ctx = talloc_tos();
2597 /* Split up the directory from the filename/mask. */
2598 status = split_fname_dir_mask(ctx, smb_fname->base_name,
2599 &fname_dir, &fname_mask);
2600 if (!NT_STATUS_IS_OK(status)) {
2601 goto out;
2605 * We should only check the mangled cache
2606 * here if unix_convert failed. This means
2607 * that the path in 'mask' doesn't exist
2608 * on the file system and so we need to look
2609 * for a possible mangle. This patch from
2610 * Tine Smukavec <valentin.smukavec@hermes.si>.
2613 if (!VALID_STAT(smb_fname->st) &&
2614 mangle_is_mangled(fname_mask, conn->params)) {
2615 char *new_mask = NULL;
2616 mangle_lookup_name_from_8_3(ctx, fname_mask,
2617 &new_mask, conn->params);
2618 if (new_mask) {
2619 TALLOC_FREE(fname_mask);
2620 fname_mask = new_mask;
2624 if (!has_wild) {
2627 * Only one file needs to be unlinked. Append the mask back
2628 * onto the directory.
2630 TALLOC_FREE(smb_fname->base_name);
2631 if (ISDOT(fname_dir)) {
2632 /* Ensure we use canonical names on open. */
2633 smb_fname->base_name = talloc_asprintf(smb_fname,
2634 "%s",
2635 fname_mask);
2636 } else {
2637 smb_fname->base_name = talloc_asprintf(smb_fname,
2638 "%s/%s",
2639 fname_dir,
2640 fname_mask);
2642 if (!smb_fname->base_name) {
2643 status = NT_STATUS_NO_MEMORY;
2644 goto out;
2646 if (dirtype == 0) {
2647 dirtype = FILE_ATTRIBUTE_NORMAL;
2650 status = check_name(conn, smb_fname->base_name);
2651 if (!NT_STATUS_IS_OK(status)) {
2652 goto out;
2655 status = do_unlink(conn, req, smb_fname, dirtype);
2656 if (!NT_STATUS_IS_OK(status)) {
2657 goto out;
2660 count++;
2661 } else {
2662 struct smb_Dir *dir_hnd = NULL;
2663 long offset = 0;
2664 const char *dname = NULL;
2665 char *talloced = NULL;
2667 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
2668 status = NT_STATUS_OBJECT_NAME_INVALID;
2669 goto out;
2672 if (strequal(fname_mask,"????????.???")) {
2673 TALLOC_FREE(fname_mask);
2674 fname_mask = talloc_strdup(ctx, "*");
2675 if (!fname_mask) {
2676 status = NT_STATUS_NO_MEMORY;
2677 goto out;
2681 status = check_name(conn, fname_dir);
2682 if (!NT_STATUS_IS_OK(status)) {
2683 goto out;
2686 dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask,
2687 dirtype);
2688 if (dir_hnd == NULL) {
2689 status = map_nt_error_from_unix(errno);
2690 goto out;
2693 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2694 the pattern matches against the long name, otherwise the short name
2695 We don't implement this yet XXXX
2698 status = NT_STATUS_NO_SUCH_FILE;
2700 while ((dname = ReadDirName(dir_hnd, &offset,
2701 &smb_fname->st, &talloced))) {
2702 TALLOC_CTX *frame = talloc_stackframe();
2704 if (!is_visible_file(conn, fname_dir, dname,
2705 &smb_fname->st, true)) {
2706 TALLOC_FREE(frame);
2707 TALLOC_FREE(talloced);
2708 continue;
2711 /* Quick check for "." and ".." */
2712 if (ISDOT(dname) || ISDOTDOT(dname)) {
2713 TALLOC_FREE(frame);
2714 TALLOC_FREE(talloced);
2715 continue;
2718 if(!mask_match(dname, fname_mask,
2719 conn->case_sensitive)) {
2720 TALLOC_FREE(frame);
2721 TALLOC_FREE(talloced);
2722 continue;
2725 TALLOC_FREE(smb_fname->base_name);
2726 if (ISDOT(fname_dir)) {
2727 /* Ensure we use canonical names on open. */
2728 smb_fname->base_name =
2729 talloc_asprintf(smb_fname, "%s",
2730 dname);
2731 } else {
2732 smb_fname->base_name =
2733 talloc_asprintf(smb_fname, "%s/%s",
2734 fname_dir, dname);
2737 if (!smb_fname->base_name) {
2738 TALLOC_FREE(dir_hnd);
2739 status = NT_STATUS_NO_MEMORY;
2740 TALLOC_FREE(frame);
2741 TALLOC_FREE(talloced);
2742 goto out;
2745 status = check_name(conn, smb_fname->base_name);
2746 if (!NT_STATUS_IS_OK(status)) {
2747 TALLOC_FREE(dir_hnd);
2748 TALLOC_FREE(frame);
2749 TALLOC_FREE(talloced);
2750 goto out;
2753 status = do_unlink(conn, req, smb_fname, dirtype);
2754 if (!NT_STATUS_IS_OK(status)) {
2755 TALLOC_FREE(frame);
2756 TALLOC_FREE(talloced);
2757 continue;
2760 count++;
2761 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
2762 smb_fname->base_name));
2764 TALLOC_FREE(frame);
2765 TALLOC_FREE(talloced);
2767 TALLOC_FREE(dir_hnd);
2770 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
2771 status = map_nt_error_from_unix(errno);
2774 out:
2775 TALLOC_FREE(fname_dir);
2776 TALLOC_FREE(fname_mask);
2777 return status;
2780 /****************************************************************************
2781 Reply to a unlink
2782 ****************************************************************************/
2784 void reply_unlink(struct smb_request *req)
2786 connection_struct *conn = req->conn;
2787 char *name = NULL;
2788 struct smb_filename *smb_fname = NULL;
2789 uint32 dirtype;
2790 NTSTATUS status;
2791 bool path_contains_wcard = False;
2792 TALLOC_CTX *ctx = talloc_tos();
2794 START_PROFILE(SMBunlink);
2796 if (req->wct < 1) {
2797 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2798 goto out;
2801 dirtype = SVAL(req->vwv+0, 0);
2803 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
2804 STR_TERMINATE, &status,
2805 &path_contains_wcard);
2806 if (!NT_STATUS_IS_OK(status)) {
2807 reply_nterror(req, status);
2808 goto out;
2811 status = filename_convert(ctx, conn,
2812 req->flags2 & FLAGS2_DFS_PATHNAMES,
2813 name,
2814 UCF_COND_ALLOW_WCARD_LCOMP,
2815 &path_contains_wcard,
2816 &smb_fname);
2817 if (!NT_STATUS_IS_OK(status)) {
2818 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2819 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2820 ERRSRV, ERRbadpath);
2821 goto out;
2823 reply_nterror(req, status);
2824 goto out;
2827 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
2829 status = unlink_internals(conn, req, dirtype, smb_fname,
2830 path_contains_wcard);
2831 if (!NT_STATUS_IS_OK(status)) {
2832 if (open_was_deferred(req->sconn, req->mid)) {
2833 /* We have re-scheduled this call. */
2834 goto out;
2836 reply_nterror(req, status);
2837 goto out;
2840 reply_outbuf(req, 0, 0);
2841 out:
2842 TALLOC_FREE(smb_fname);
2843 END_PROFILE(SMBunlink);
2844 return;
2847 /****************************************************************************
2848 Fail for readbraw.
2849 ****************************************************************************/
2851 static void fail_readraw(void)
2853 const char *errstr = talloc_asprintf(talloc_tos(),
2854 "FAIL ! reply_readbraw: socket write fail (%s)",
2855 strerror(errno));
2856 if (!errstr) {
2857 errstr = "";
2859 exit_server_cleanly(errstr);
2862 /****************************************************************************
2863 Fake (read/write) sendfile. Returns -1 on read or write fail.
2864 ****************************************************************************/
2866 ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos, size_t nread)
2868 size_t bufsize;
2869 size_t tosend = nread;
2870 char *buf;
2872 if (nread == 0) {
2873 return 0;
2876 bufsize = MIN(nread, 65536);
2878 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
2879 return -1;
2882 while (tosend > 0) {
2883 ssize_t ret;
2884 size_t cur_read;
2886 if (tosend > bufsize) {
2887 cur_read = bufsize;
2888 } else {
2889 cur_read = tosend;
2891 ret = read_file(fsp,buf,startpos,cur_read);
2892 if (ret == -1) {
2893 SAFE_FREE(buf);
2894 return -1;
2897 /* If we had a short read, fill with zeros. */
2898 if (ret < cur_read) {
2899 memset(buf + ret, '\0', cur_read - ret);
2902 if (write_data(fsp->conn->sconn->sock, buf, cur_read)
2903 != cur_read) {
2904 char addr[INET6_ADDRSTRLEN];
2906 * Try and give an error message saying what
2907 * client failed.
2909 DEBUG(0, ("write_data failed for client %s. "
2910 "Error %s\n",
2911 get_peer_addr(fsp->conn->sconn->sock, addr,
2912 sizeof(addr)),
2913 strerror(errno)));
2914 SAFE_FREE(buf);
2915 return -1;
2917 tosend -= cur_read;
2918 startpos += cur_read;
2921 SAFE_FREE(buf);
2922 return (ssize_t)nread;
2925 /****************************************************************************
2926 Deal with the case of sendfile reading less bytes from the file than
2927 requested. Fill with zeros (all we can do).
2928 ****************************************************************************/
2930 void sendfile_short_send(files_struct *fsp,
2931 ssize_t nread,
2932 size_t headersize,
2933 size_t smb_maxcnt)
2935 #define SHORT_SEND_BUFSIZE 1024
2936 if (nread < headersize) {
2937 DEBUG(0,("sendfile_short_send: sendfile failed to send "
2938 "header for file %s (%s). Terminating\n",
2939 fsp_str_dbg(fsp), strerror(errno)));
2940 exit_server_cleanly("sendfile_short_send failed");
2943 nread -= headersize;
2945 if (nread < smb_maxcnt) {
2946 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
2947 if (!buf) {
2948 exit_server_cleanly("sendfile_short_send: "
2949 "malloc failed");
2952 DEBUG(0,("sendfile_short_send: filling truncated file %s "
2953 "with zeros !\n", fsp_str_dbg(fsp)));
2955 while (nread < smb_maxcnt) {
2957 * We asked for the real file size and told sendfile
2958 * to not go beyond the end of the file. But it can
2959 * happen that in between our fstat call and the
2960 * sendfile call the file was truncated. This is very
2961 * bad because we have already announced the larger
2962 * number of bytes to the client.
2964 * The best we can do now is to send 0-bytes, just as
2965 * a read from a hole in a sparse file would do.
2967 * This should happen rarely enough that I don't care
2968 * about efficiency here :-)
2970 size_t to_write;
2972 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
2973 if (write_data(fsp->conn->sconn->sock, buf, to_write)
2974 != to_write) {
2975 char addr[INET6_ADDRSTRLEN];
2977 * Try and give an error message saying what
2978 * client failed.
2980 DEBUG(0, ("write_data failed for client %s. "
2981 "Error %s\n",
2982 get_peer_addr(
2983 fsp->conn->sconn->sock, addr,
2984 sizeof(addr)),
2985 strerror(errno)));
2986 exit_server_cleanly("sendfile_short_send: "
2987 "write_data failed");
2989 nread += to_write;
2991 SAFE_FREE(buf);
2995 /****************************************************************************
2996 Return a readbraw error (4 bytes of zero).
2997 ****************************************************************************/
2999 static void reply_readbraw_error(struct smbd_server_connection *sconn)
3001 char header[4];
3003 SIVAL(header,0,0);
3005 smbd_lock_socket(sconn);
3006 if (write_data(sconn->sock,header,4) != 4) {
3007 char addr[INET6_ADDRSTRLEN];
3009 * Try and give an error message saying what
3010 * client failed.
3012 DEBUG(0, ("write_data failed for client %s. "
3013 "Error %s\n",
3014 get_peer_addr(sconn->sock, addr, sizeof(addr)),
3015 strerror(errno)));
3017 fail_readraw();
3019 smbd_unlock_socket(sconn);
3022 /****************************************************************************
3023 Use sendfile in readbraw.
3024 ****************************************************************************/
3026 static void send_file_readbraw(connection_struct *conn,
3027 struct smb_request *req,
3028 files_struct *fsp,
3029 SMB_OFF_T startpos,
3030 size_t nread,
3031 ssize_t mincount)
3033 struct smbd_server_connection *sconn = req->sconn;
3034 char *outbuf = NULL;
3035 ssize_t ret=0;
3038 * We can only use sendfile on a non-chained packet
3039 * but we can use on a non-oplocked file. tridge proved this
3040 * on a train in Germany :-). JRA.
3041 * reply_readbraw has already checked the length.
3044 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3045 (fsp->wcp == NULL) &&
3046 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3047 ssize_t sendfile_read = -1;
3048 char header[4];
3049 DATA_BLOB header_blob;
3051 _smb_setlen(header,nread);
3052 header_blob = data_blob_const(header, 4);
3054 sendfile_read = SMB_VFS_SENDFILE(sconn->sock, fsp,
3055 &header_blob, startpos,
3056 nread);
3057 if (sendfile_read == -1) {
3058 /* Returning ENOSYS means no data at all was sent.
3059 * Do this as a normal read. */
3060 if (errno == ENOSYS) {
3061 goto normal_readbraw;
3065 * Special hack for broken Linux with no working sendfile. If we
3066 * return EINTR we sent the header but not the rest of the data.
3067 * Fake this up by doing read/write calls.
3069 if (errno == EINTR) {
3070 /* Ensure we don't do this again. */
3071 set_use_sendfile(SNUM(conn), False);
3072 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3074 if (fake_sendfile(fsp, startpos, nread) == -1) {
3075 DEBUG(0,("send_file_readbraw: "
3076 "fake_sendfile failed for "
3077 "file %s (%s).\n",
3078 fsp_str_dbg(fsp),
3079 strerror(errno)));
3080 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3082 return;
3085 DEBUG(0,("send_file_readbraw: sendfile failed for "
3086 "file %s (%s). Terminating\n",
3087 fsp_str_dbg(fsp), strerror(errno)));
3088 exit_server_cleanly("send_file_readbraw sendfile failed");
3089 } else if (sendfile_read == 0) {
3091 * Some sendfile implementations return 0 to indicate
3092 * that there was a short read, but nothing was
3093 * actually written to the socket. In this case,
3094 * fallback to the normal read path so the header gets
3095 * the correct byte count.
3097 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3098 "bytes falling back to the normal read: "
3099 "%s\n", fsp_str_dbg(fsp)));
3100 goto normal_readbraw;
3103 /* Deal with possible short send. */
3104 if (sendfile_read != 4+nread) {
3105 sendfile_short_send(fsp, sendfile_read, 4, nread);
3107 return;
3110 normal_readbraw:
3112 outbuf = talloc_array(NULL, char, nread+4);
3113 if (!outbuf) {
3114 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3115 (unsigned)(nread+4)));
3116 reply_readbraw_error(sconn);
3117 return;
3120 if (nread > 0) {
3121 ret = read_file(fsp,outbuf+4,startpos,nread);
3122 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3123 if (ret < mincount)
3124 ret = 0;
3125 #else
3126 if (ret < nread)
3127 ret = 0;
3128 #endif
3131 _smb_setlen(outbuf,ret);
3132 if (write_data(sconn->sock, outbuf, 4+ret) != 4+ret) {
3133 char addr[INET6_ADDRSTRLEN];
3135 * Try and give an error message saying what
3136 * client failed.
3138 DEBUG(0, ("write_data failed for client %s. "
3139 "Error %s\n",
3140 get_peer_addr(fsp->conn->sconn->sock, addr,
3141 sizeof(addr)),
3142 strerror(errno)));
3144 fail_readraw();
3147 TALLOC_FREE(outbuf);
3150 /****************************************************************************
3151 Reply to a readbraw (core+ protocol).
3152 ****************************************************************************/
3154 void reply_readbraw(struct smb_request *req)
3156 connection_struct *conn = req->conn;
3157 struct smbd_server_connection *sconn = req->sconn;
3158 ssize_t maxcount,mincount;
3159 size_t nread = 0;
3160 SMB_OFF_T startpos;
3161 files_struct *fsp;
3162 struct lock_struct lock;
3163 SMB_OFF_T size = 0;
3165 START_PROFILE(SMBreadbraw);
3167 if (srv_is_signing_active(sconn) ||
3168 is_encrypted_packet(sconn, req->inbuf)) {
3169 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3170 "raw reads/writes are disallowed.");
3173 if (req->wct < 8) {
3174 reply_readbraw_error(sconn);
3175 END_PROFILE(SMBreadbraw);
3176 return;
3179 if (sconn->smb1.echo_handler.trusted_fde) {
3180 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3181 "'async smb echo handler = yes'\n"));
3182 reply_readbraw_error(sconn);
3183 END_PROFILE(SMBreadbraw);
3184 return;
3188 * Special check if an oplock break has been issued
3189 * and the readraw request croses on the wire, we must
3190 * return a zero length response here.
3193 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3196 * We have to do a check_fsp by hand here, as
3197 * we must always return 4 zero bytes on error,
3198 * not a NTSTATUS.
3201 if (!fsp || !conn || conn != fsp->conn ||
3202 req->vuid != fsp->vuid ||
3203 fsp->is_directory || fsp->fh->fd == -1) {
3205 * fsp could be NULL here so use the value from the packet. JRA.
3207 DEBUG(3,("reply_readbraw: fnum %d not valid "
3208 "- cache prime?\n",
3209 (int)SVAL(req->vwv+0, 0)));
3210 reply_readbraw_error(sconn);
3211 END_PROFILE(SMBreadbraw);
3212 return;
3215 /* Do a "by hand" version of CHECK_READ. */
3216 if (!(fsp->can_read ||
3217 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3218 (fsp->access_mask & FILE_EXECUTE)))) {
3219 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3220 (int)SVAL(req->vwv+0, 0)));
3221 reply_readbraw_error(sconn);
3222 END_PROFILE(SMBreadbraw);
3223 return;
3226 flush_write_cache(fsp, READRAW_FLUSH);
3228 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3229 if(req->wct == 10) {
3231 * This is a large offset (64 bit) read.
3233 #ifdef LARGE_SMB_OFF_T
3235 startpos |= (((SMB_OFF_T)IVAL(req->vwv+8, 0)) << 32);
3237 #else /* !LARGE_SMB_OFF_T */
3240 * Ensure we haven't been sent a >32 bit offset.
3243 if(IVAL(req->vwv+8, 0) != 0) {
3244 DEBUG(0,("reply_readbraw: large offset "
3245 "(%x << 32) used and we don't support "
3246 "64 bit offsets.\n",
3247 (unsigned int)IVAL(req->vwv+8, 0) ));
3248 reply_readbraw_error(sconn);
3249 END_PROFILE(SMBreadbraw);
3250 return;
3253 #endif /* LARGE_SMB_OFF_T */
3255 if(startpos < 0) {
3256 DEBUG(0,("reply_readbraw: negative 64 bit "
3257 "readraw offset (%.0f) !\n",
3258 (double)startpos ));
3259 reply_readbraw_error(sconn);
3260 END_PROFILE(SMBreadbraw);
3261 return;
3265 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3266 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3268 /* ensure we don't overrun the packet size */
3269 maxcount = MIN(65535,maxcount);
3271 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3272 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3273 &lock);
3275 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3276 reply_readbraw_error(sconn);
3277 END_PROFILE(SMBreadbraw);
3278 return;
3281 if (fsp_stat(fsp) == 0) {
3282 size = fsp->fsp_name->st.st_ex_size;
3285 if (startpos >= size) {
3286 nread = 0;
3287 } else {
3288 nread = MIN(maxcount,(size - startpos));
3291 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3292 if (nread < mincount)
3293 nread = 0;
3294 #endif
3296 DEBUG( 3, ( "reply_readbraw: fnum=%d start=%.0f max=%lu "
3297 "min=%lu nread=%lu\n",
3298 fsp->fnum, (double)startpos,
3299 (unsigned long)maxcount,
3300 (unsigned long)mincount,
3301 (unsigned long)nread ) );
3303 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3305 DEBUG(5,("reply_readbraw finished\n"));
3307 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3309 END_PROFILE(SMBreadbraw);
3310 return;
3313 #undef DBGC_CLASS
3314 #define DBGC_CLASS DBGC_LOCKING
3316 /****************************************************************************
3317 Reply to a lockread (core+ protocol).
3318 ****************************************************************************/
3320 void reply_lockread(struct smb_request *req)
3322 connection_struct *conn = req->conn;
3323 ssize_t nread = -1;
3324 char *data;
3325 SMB_OFF_T startpos;
3326 size_t numtoread;
3327 NTSTATUS status;
3328 files_struct *fsp;
3329 struct byte_range_lock *br_lck = NULL;
3330 char *p = NULL;
3331 struct smbd_server_connection *sconn = req->sconn;
3333 START_PROFILE(SMBlockread);
3335 if (req->wct < 5) {
3336 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3337 END_PROFILE(SMBlockread);
3338 return;
3341 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3343 if (!check_fsp(conn, req, fsp)) {
3344 END_PROFILE(SMBlockread);
3345 return;
3348 if (!CHECK_READ(fsp,req)) {
3349 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3350 END_PROFILE(SMBlockread);
3351 return;
3354 numtoread = SVAL(req->vwv+1, 0);
3355 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3357 numtoread = MIN(BUFFER_SIZE - (smb_size + 3*2 + 3), numtoread);
3359 reply_outbuf(req, 5, numtoread + 3);
3361 data = smb_buf(req->outbuf) + 3;
3364 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3365 * protocol request that predates the read/write lock concept.
3366 * Thus instead of asking for a read lock here we need to ask
3367 * for a write lock. JRA.
3368 * Note that the requested lock size is unaffected by max_recv.
3371 br_lck = do_lock(req->sconn->msg_ctx,
3372 fsp,
3373 (uint64_t)req->smbpid,
3374 (uint64_t)numtoread,
3375 (uint64_t)startpos,
3376 WRITE_LOCK,
3377 WINDOWS_LOCK,
3378 False, /* Non-blocking lock. */
3379 &status,
3380 NULL,
3381 NULL);
3382 TALLOC_FREE(br_lck);
3384 if (NT_STATUS_V(status)) {
3385 reply_nterror(req, status);
3386 END_PROFILE(SMBlockread);
3387 return;
3391 * However the requested READ size IS affected by max_recv. Insanity.... JRA.
3394 if (numtoread > sconn->smb1.negprot.max_recv) {
3395 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \
3396 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3397 (unsigned int)numtoread,
3398 (unsigned int)sconn->smb1.negprot.max_recv));
3399 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3401 nread = read_file(fsp,data,startpos,numtoread);
3403 if (nread < 0) {
3404 reply_nterror(req, map_nt_error_from_unix(errno));
3405 END_PROFILE(SMBlockread);
3406 return;
3409 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3411 SSVAL(req->outbuf,smb_vwv0,nread);
3412 SSVAL(req->outbuf,smb_vwv5,nread+3);
3413 p = smb_buf(req->outbuf);
3414 SCVAL(p,0,0); /* pad byte. */
3415 SSVAL(p,1,nread);
3417 DEBUG(3,("lockread fnum=%d num=%d nread=%d\n",
3418 fsp->fnum, (int)numtoread, (int)nread));
3420 END_PROFILE(SMBlockread);
3421 return;
3424 #undef DBGC_CLASS
3425 #define DBGC_CLASS DBGC_ALL
3427 /****************************************************************************
3428 Reply to a read.
3429 ****************************************************************************/
3431 void reply_read(struct smb_request *req)
3433 connection_struct *conn = req->conn;
3434 size_t numtoread;
3435 ssize_t nread = 0;
3436 char *data;
3437 SMB_OFF_T startpos;
3438 int outsize = 0;
3439 files_struct *fsp;
3440 struct lock_struct lock;
3441 struct smbd_server_connection *sconn = req->sconn;
3443 START_PROFILE(SMBread);
3445 if (req->wct < 3) {
3446 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3447 END_PROFILE(SMBread);
3448 return;
3451 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3453 if (!check_fsp(conn, req, fsp)) {
3454 END_PROFILE(SMBread);
3455 return;
3458 if (!CHECK_READ(fsp,req)) {
3459 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3460 END_PROFILE(SMBread);
3461 return;
3464 numtoread = SVAL(req->vwv+1, 0);
3465 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3467 numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
3470 * The requested read size cannot be greater than max_recv. JRA.
3472 if (numtoread > sconn->smb1.negprot.max_recv) {
3473 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \
3474 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3475 (unsigned int)numtoread,
3476 (unsigned int)sconn->smb1.negprot.max_recv));
3477 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3480 reply_outbuf(req, 5, numtoread+3);
3482 data = smb_buf(req->outbuf) + 3;
3484 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3485 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3486 &lock);
3488 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3489 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3490 END_PROFILE(SMBread);
3491 return;
3494 if (numtoread > 0)
3495 nread = read_file(fsp,data,startpos,numtoread);
3497 if (nread < 0) {
3498 reply_nterror(req, map_nt_error_from_unix(errno));
3499 goto strict_unlock;
3502 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3504 SSVAL(req->outbuf,smb_vwv0,nread);
3505 SSVAL(req->outbuf,smb_vwv5,nread+3);
3506 SCVAL(smb_buf(req->outbuf),0,1);
3507 SSVAL(smb_buf(req->outbuf),1,nread);
3509 DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
3510 fsp->fnum, (int)numtoread, (int)nread ) );
3512 strict_unlock:
3513 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3515 END_PROFILE(SMBread);
3516 return;
3519 /****************************************************************************
3520 Setup readX header.
3521 ****************************************************************************/
3523 static int setup_readX_header(struct smb_request *req, char *outbuf,
3524 size_t smb_maxcnt)
3526 int outsize;
3527 char *data;
3529 outsize = srv_set_message(outbuf,12,smb_maxcnt,False);
3530 data = smb_buf(outbuf);
3532 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3534 SCVAL(outbuf,smb_vwv0,0xFF);
3535 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3536 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3537 SSVAL(outbuf,smb_vwv6,
3538 req_wct_ofs(req)
3539 + 1 /* the wct field */
3540 + 12 * sizeof(uint16_t) /* vwv */
3541 + 2); /* the buflen field */
3542 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3543 SSVAL(outbuf,smb_vwv11,smb_maxcnt);
3544 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3545 _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
3546 return outsize;
3549 /****************************************************************************
3550 Reply to a read and X - possibly using sendfile.
3551 ****************************************************************************/
3553 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3554 files_struct *fsp, SMB_OFF_T startpos,
3555 size_t smb_maxcnt)
3557 ssize_t nread = -1;
3558 struct lock_struct lock;
3559 int saved_errno = 0;
3561 if(fsp_stat(fsp) == -1) {
3562 reply_nterror(req, map_nt_error_from_unix(errno));
3563 return;
3566 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3567 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3568 &lock);
3570 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3571 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3572 return;
3575 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3576 (startpos > fsp->fsp_name->st.st_ex_size)
3577 || (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3579 * We already know that we would do a short read, so don't
3580 * try the sendfile() path.
3582 goto nosendfile_read;
3586 * We can only use sendfile on a non-chained packet
3587 * but we can use on a non-oplocked file. tridge proved this
3588 * on a train in Germany :-). JRA.
3591 if (!req_is_in_chain(req) &&
3592 !is_encrypted_packet(req->sconn, req->inbuf) &&
3593 (fsp->base_fsp == NULL) &&
3594 (fsp->wcp == NULL) &&
3595 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3596 uint8 headerbuf[smb_size + 12 * 2];
3597 DATA_BLOB header;
3600 * Set up the packet header before send. We
3601 * assume here the sendfile will work (get the
3602 * correct amount of data).
3605 header = data_blob_const(headerbuf, sizeof(headerbuf));
3607 construct_reply_common_req(req, (char *)headerbuf);
3608 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3610 nread = SMB_VFS_SENDFILE(req->sconn->sock, fsp, &header,
3611 startpos, smb_maxcnt);
3612 if (nread == -1) {
3613 /* Returning ENOSYS means no data at all was sent.
3614 Do this as a normal read. */
3615 if (errno == ENOSYS) {
3616 goto normal_read;
3620 * Special hack for broken Linux with no working sendfile. If we
3621 * return EINTR we sent the header but not the rest of the data.
3622 * Fake this up by doing read/write calls.
3625 if (errno == EINTR) {
3626 /* Ensure we don't do this again. */
3627 set_use_sendfile(SNUM(conn), False);
3628 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3629 nread = fake_sendfile(fsp, startpos,
3630 smb_maxcnt);
3631 if (nread == -1) {
3632 DEBUG(0,("send_file_readX: "
3633 "fake_sendfile failed for "
3634 "file %s (%s).\n",
3635 fsp_str_dbg(fsp),
3636 strerror(errno)));
3637 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3639 DEBUG( 3, ( "send_file_readX: fake_sendfile fnum=%d max=%d nread=%d\n",
3640 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3641 /* No outbuf here means successful sendfile. */
3642 goto strict_unlock;
3645 DEBUG(0,("send_file_readX: sendfile failed for file "
3646 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3647 strerror(errno)));
3648 exit_server_cleanly("send_file_readX sendfile failed");
3649 } else if (nread == 0) {
3651 * Some sendfile implementations return 0 to indicate
3652 * that there was a short read, but nothing was
3653 * actually written to the socket. In this case,
3654 * fallback to the normal read path so the header gets
3655 * the correct byte count.
3657 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
3658 "falling back to the normal read: %s\n",
3659 fsp_str_dbg(fsp)));
3660 goto normal_read;
3663 DEBUG( 3, ( "send_file_readX: sendfile fnum=%d max=%d nread=%d\n",
3664 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3666 /* Deal with possible short send. */
3667 if (nread != smb_maxcnt + sizeof(headerbuf)) {
3668 sendfile_short_send(fsp, nread, sizeof(headerbuf), smb_maxcnt);
3670 /* No outbuf here means successful sendfile. */
3671 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
3672 SMB_PERFCOUNT_END(&req->pcd);
3673 goto strict_unlock;
3676 normal_read:
3678 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3679 uint8 headerbuf[smb_size + 2*12];
3681 construct_reply_common_req(req, (char *)headerbuf);
3682 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3684 /* Send out the header. */
3685 if (write_data(req->sconn->sock, (char *)headerbuf,
3686 sizeof(headerbuf)) != sizeof(headerbuf)) {
3688 char addr[INET6_ADDRSTRLEN];
3690 * Try and give an error message saying what
3691 * client failed.
3693 DEBUG(0, ("write_data failed for client %s. "
3694 "Error %s\n",
3695 get_peer_addr(req->sconn->sock, addr,
3696 sizeof(addr)),
3697 strerror(errno)));
3699 DEBUG(0,("send_file_readX: write_data failed for file "
3700 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3701 strerror(errno)));
3702 exit_server_cleanly("send_file_readX sendfile failed");
3704 nread = fake_sendfile(fsp, startpos, smb_maxcnt);
3705 if (nread == -1) {
3706 DEBUG(0,("send_file_readX: fake_sendfile failed for "
3707 "file %s (%s).\n", fsp_str_dbg(fsp),
3708 strerror(errno)));
3709 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3711 goto strict_unlock;
3714 nosendfile_read:
3716 reply_outbuf(req, 12, smb_maxcnt);
3718 nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt);
3719 saved_errno = errno;
3721 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3723 if (nread < 0) {
3724 reply_nterror(req, map_nt_error_from_unix(saved_errno));
3725 return;
3728 setup_readX_header(req, (char *)req->outbuf, nread);
3730 DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
3731 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3733 chain_reply(req);
3734 return;
3736 strict_unlock:
3737 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3738 TALLOC_FREE(req->outbuf);
3739 return;
3742 /****************************************************************************
3743 Reply to a read and X.
3744 ****************************************************************************/
3746 void reply_read_and_X(struct smb_request *req)
3748 struct smbd_server_connection *sconn = req->sconn;
3749 connection_struct *conn = req->conn;
3750 files_struct *fsp;
3751 SMB_OFF_T startpos;
3752 size_t smb_maxcnt;
3753 bool big_readX = False;
3754 #if 0
3755 size_t smb_mincnt = SVAL(req->vwv+6, 0);
3756 #endif
3758 START_PROFILE(SMBreadX);
3760 if ((req->wct != 10) && (req->wct != 12)) {
3761 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3762 return;
3765 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
3766 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3767 smb_maxcnt = SVAL(req->vwv+5, 0);
3769 /* If it's an IPC, pass off the pipe handler. */
3770 if (IS_IPC(conn)) {
3771 reply_pipe_read_and_X(req);
3772 END_PROFILE(SMBreadX);
3773 return;
3776 if (!check_fsp(conn, req, fsp)) {
3777 END_PROFILE(SMBreadX);
3778 return;
3781 if (!CHECK_READ(fsp,req)) {
3782 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3783 END_PROFILE(SMBreadX);
3784 return;
3787 if ((sconn->smb1.unix_info.client_cap_low & CIFS_UNIX_LARGE_READ_CAP) ||
3788 (get_remote_arch() == RA_SAMBA)) {
3790 * This is Samba only behavior (up to Samba 3.6)!
3792 * Windows 2008 R2 ignores the upper_size,
3793 * so we do unless unix extentions are active
3794 * or "smbclient" is talking to us.
3796 size_t upper_size = SVAL(req->vwv+7, 0);
3797 smb_maxcnt |= (upper_size<<16);
3798 if (upper_size > 1) {
3799 /* Can't do this on a chained packet. */
3800 if ((CVAL(req->vwv+0, 0) != 0xFF)) {
3801 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3802 END_PROFILE(SMBreadX);
3803 return;
3805 /* We currently don't do this on signed or sealed data. */
3806 if (srv_is_signing_active(req->sconn) ||
3807 is_encrypted_packet(req->sconn, req->inbuf)) {
3808 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3809 END_PROFILE(SMBreadX);
3810 return;
3812 /* Is there room in the reply for this data ? */
3813 if (smb_maxcnt > (0xFFFFFF - (smb_size -4 + 12*2))) {
3814 reply_nterror(req,
3815 NT_STATUS_INVALID_PARAMETER);
3816 END_PROFILE(SMBreadX);
3817 return;
3819 big_readX = True;
3823 if (req->wct == 12) {
3824 #ifdef LARGE_SMB_OFF_T
3826 * This is a large offset (64 bit) read.
3828 startpos |= (((SMB_OFF_T)IVAL(req->vwv+10, 0)) << 32);
3830 #else /* !LARGE_SMB_OFF_T */
3833 * Ensure we haven't been sent a >32 bit offset.
3836 if(IVAL(req->vwv+10, 0) != 0) {
3837 DEBUG(0,("reply_read_and_X - large offset (%x << 32) "
3838 "used and we don't support 64 bit offsets.\n",
3839 (unsigned int)IVAL(req->vwv+10, 0) ));
3840 END_PROFILE(SMBreadX);
3841 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3842 return;
3845 #endif /* LARGE_SMB_OFF_T */
3849 if (!big_readX) {
3850 NTSTATUS status = schedule_aio_read_and_X(conn,
3851 req,
3852 fsp,
3853 startpos,
3854 smb_maxcnt);
3855 if (NT_STATUS_IS_OK(status)) {
3856 /* Read scheduled - we're done. */
3857 goto out;
3859 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
3860 /* Real error - report to client. */
3861 END_PROFILE(SMBreadX);
3862 reply_nterror(req, status);
3863 return;
3865 /* NT_STATUS_RETRY - fall back to sync read. */
3868 smbd_lock_socket(req->sconn);
3869 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
3870 smbd_unlock_socket(req->sconn);
3872 out:
3873 END_PROFILE(SMBreadX);
3874 return;
3877 /****************************************************************************
3878 Error replies to writebraw must have smb_wct == 1. Fix this up.
3879 ****************************************************************************/
3881 void error_to_writebrawerr(struct smb_request *req)
3883 uint8 *old_outbuf = req->outbuf;
3885 reply_outbuf(req, 1, 0);
3887 memcpy(req->outbuf, old_outbuf, smb_size);
3888 TALLOC_FREE(old_outbuf);
3891 /****************************************************************************
3892 Read 4 bytes of a smb packet and return the smb length of the packet.
3893 Store the result in the buffer. This version of the function will
3894 never return a session keepalive (length of zero).
3895 Timeout is in milliseconds.
3896 ****************************************************************************/
3898 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
3899 size_t *len)
3901 uint8_t msgtype = NBSSkeepalive;
3903 while (msgtype == NBSSkeepalive) {
3904 NTSTATUS status;
3906 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
3907 len);
3908 if (!NT_STATUS_IS_OK(status)) {
3909 char addr[INET6_ADDRSTRLEN];
3910 /* Try and give an error message
3911 * saying what client failed. */
3912 DEBUG(0, ("read_fd_with_timeout failed for "
3913 "client %s read error = %s.\n",
3914 get_peer_addr(fd,addr,sizeof(addr)),
3915 nt_errstr(status)));
3916 return status;
3919 msgtype = CVAL(inbuf, 0);
3922 DEBUG(10,("read_smb_length: got smb length of %lu\n",
3923 (unsigned long)len));
3925 return NT_STATUS_OK;
3928 /****************************************************************************
3929 Reply to a writebraw (core+ or LANMAN1.0 protocol).
3930 ****************************************************************************/
3932 void reply_writebraw(struct smb_request *req)
3934 connection_struct *conn = req->conn;
3935 char *buf = NULL;
3936 ssize_t nwritten=0;
3937 ssize_t total_written=0;
3938 size_t numtowrite=0;
3939 size_t tcount;
3940 SMB_OFF_T startpos;
3941 const char *data=NULL;
3942 bool write_through;
3943 files_struct *fsp;
3944 struct lock_struct lock;
3945 NTSTATUS status;
3947 START_PROFILE(SMBwritebraw);
3950 * If we ever reply with an error, it must have the SMB command
3951 * type of SMBwritec, not SMBwriteBraw, as this tells the client
3952 * we're finished.
3954 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
3956 if (srv_is_signing_active(req->sconn)) {
3957 END_PROFILE(SMBwritebraw);
3958 exit_server_cleanly("reply_writebraw: SMB signing is active - "
3959 "raw reads/writes are disallowed.");
3962 if (req->wct < 12) {
3963 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3964 error_to_writebrawerr(req);
3965 END_PROFILE(SMBwritebraw);
3966 return;
3969 if (req->sconn->smb1.echo_handler.trusted_fde) {
3970 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
3971 "'async smb echo handler = yes'\n"));
3972 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3973 error_to_writebrawerr(req);
3974 END_PROFILE(SMBwritebraw);
3975 return;
3978 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3979 if (!check_fsp(conn, req, fsp)) {
3980 error_to_writebrawerr(req);
3981 END_PROFILE(SMBwritebraw);
3982 return;
3985 if (!CHECK_WRITE(fsp)) {
3986 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3987 error_to_writebrawerr(req);
3988 END_PROFILE(SMBwritebraw);
3989 return;
3992 tcount = IVAL(req->vwv+1, 0);
3993 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3994 write_through = BITSETW(req->vwv+7,0);
3996 /* We have to deal with slightly different formats depending
3997 on whether we are using the core+ or lanman1.0 protocol */
3999 if(get_Protocol() <= PROTOCOL_COREPLUS) {
4000 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
4001 data = smb_buf_const(req->inbuf);
4002 } else {
4003 numtowrite = SVAL(req->vwv+10, 0);
4004 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
4007 /* Ensure we don't write bytes past the end of this packet. */
4008 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
4009 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4010 error_to_writebrawerr(req);
4011 END_PROFILE(SMBwritebraw);
4012 return;
4015 if (!fsp->print_file) {
4016 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4017 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4018 &lock);
4020 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4021 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4022 error_to_writebrawerr(req);
4023 END_PROFILE(SMBwritebraw);
4024 return;
4028 if (numtowrite>0) {
4029 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4032 DEBUG(3,("reply_writebraw: initial write fnum=%d start=%.0f num=%d "
4033 "wrote=%d sync=%d\n",
4034 fsp->fnum, (double)startpos, (int)numtowrite,
4035 (int)nwritten, (int)write_through));
4037 if (nwritten < (ssize_t)numtowrite) {
4038 reply_nterror(req, NT_STATUS_DISK_FULL);
4039 error_to_writebrawerr(req);
4040 goto strict_unlock;
4043 total_written = nwritten;
4045 /* Allocate a buffer of 64k + length. */
4046 buf = talloc_array(NULL, char, 65540);
4047 if (!buf) {
4048 reply_nterror(req, NT_STATUS_NO_MEMORY);
4049 error_to_writebrawerr(req);
4050 goto strict_unlock;
4053 /* Return a SMBwritebraw message to the redirector to tell
4054 * it to send more bytes */
4056 memcpy(buf, req->inbuf, smb_size);
4057 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4058 SCVAL(buf,smb_com,SMBwritebraw);
4059 SSVALS(buf,smb_vwv0,0xFFFF);
4060 show_msg(buf);
4061 if (!srv_send_smb(req->sconn,
4062 buf,
4063 false, 0, /* no signing */
4064 IS_CONN_ENCRYPTED(conn),
4065 &req->pcd)) {
4066 exit_server_cleanly("reply_writebraw: srv_send_smb "
4067 "failed.");
4070 /* Now read the raw data into the buffer and write it */
4071 status = read_smb_length(req->sconn->sock, buf, SMB_SECONDARY_WAIT,
4072 &numtowrite);
4073 if (!NT_STATUS_IS_OK(status)) {
4074 exit_server_cleanly("secondary writebraw failed");
4077 /* Set up outbuf to return the correct size */
4078 reply_outbuf(req, 1, 0);
4080 if (numtowrite != 0) {
4082 if (numtowrite > 0xFFFF) {
4083 DEBUG(0,("reply_writebraw: Oversize secondary write "
4084 "raw requested (%u). Terminating\n",
4085 (unsigned int)numtowrite ));
4086 exit_server_cleanly("secondary writebraw failed");
4089 if (tcount > nwritten+numtowrite) {
4090 DEBUG(3,("reply_writebraw: Client overestimated the "
4091 "write %d %d %d\n",
4092 (int)tcount,(int)nwritten,(int)numtowrite));
4095 status = read_data(req->sconn->sock, buf+4, numtowrite);
4097 if (!NT_STATUS_IS_OK(status)) {
4098 char addr[INET6_ADDRSTRLEN];
4099 /* Try and give an error message
4100 * saying what client failed. */
4101 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4102 "raw read failed (%s) for client %s. "
4103 "Terminating\n", nt_errstr(status),
4104 get_peer_addr(req->sconn->sock, addr,
4105 sizeof(addr))));
4106 exit_server_cleanly("secondary writebraw failed");
4109 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4110 if (nwritten == -1) {
4111 TALLOC_FREE(buf);
4112 reply_nterror(req, map_nt_error_from_unix(errno));
4113 error_to_writebrawerr(req);
4114 goto strict_unlock;
4117 if (nwritten < (ssize_t)numtowrite) {
4118 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4119 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4122 if (nwritten > 0) {
4123 total_written += nwritten;
4127 TALLOC_FREE(buf);
4128 SSVAL(req->outbuf,smb_vwv0,total_written);
4130 status = sync_file(conn, fsp, write_through);
4131 if (!NT_STATUS_IS_OK(status)) {
4132 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4133 fsp_str_dbg(fsp), nt_errstr(status)));
4134 reply_nterror(req, status);
4135 error_to_writebrawerr(req);
4136 goto strict_unlock;
4139 DEBUG(3,("reply_writebraw: secondart write fnum=%d start=%.0f num=%d "
4140 "wrote=%d\n",
4141 fsp->fnum, (double)startpos, (int)numtowrite,
4142 (int)total_written));
4144 if (!fsp->print_file) {
4145 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4148 /* We won't return a status if write through is not selected - this
4149 * follows what WfWg does */
4150 END_PROFILE(SMBwritebraw);
4152 if (!write_through && total_written==tcount) {
4154 #if RABBIT_PELLET_FIX
4156 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4157 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4158 * JRA.
4160 if (!send_keepalive(req->sconn->sock)) {
4161 exit_server_cleanly("reply_writebraw: send of "
4162 "keepalive failed");
4164 #endif
4165 TALLOC_FREE(req->outbuf);
4167 return;
4169 strict_unlock:
4170 if (!fsp->print_file) {
4171 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4174 END_PROFILE(SMBwritebraw);
4175 return;
4178 #undef DBGC_CLASS
4179 #define DBGC_CLASS DBGC_LOCKING
4181 /****************************************************************************
4182 Reply to a writeunlock (core+).
4183 ****************************************************************************/
4185 void reply_writeunlock(struct smb_request *req)
4187 connection_struct *conn = req->conn;
4188 ssize_t nwritten = -1;
4189 size_t numtowrite;
4190 SMB_OFF_T startpos;
4191 const char *data;
4192 NTSTATUS status = NT_STATUS_OK;
4193 files_struct *fsp;
4194 struct lock_struct lock;
4195 int saved_errno = 0;
4197 START_PROFILE(SMBwriteunlock);
4199 if (req->wct < 5) {
4200 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4201 END_PROFILE(SMBwriteunlock);
4202 return;
4205 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4207 if (!check_fsp(conn, req, fsp)) {
4208 END_PROFILE(SMBwriteunlock);
4209 return;
4212 if (!CHECK_WRITE(fsp)) {
4213 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4214 END_PROFILE(SMBwriteunlock);
4215 return;
4218 numtowrite = SVAL(req->vwv+1, 0);
4219 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4220 data = (const char *)req->buf + 3;
4222 if (!fsp->print_file && numtowrite > 0) {
4223 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4224 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4225 &lock);
4227 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4228 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4229 END_PROFILE(SMBwriteunlock);
4230 return;
4234 /* The special X/Open SMB protocol handling of
4235 zero length writes is *NOT* done for
4236 this call */
4237 if(numtowrite == 0) {
4238 nwritten = 0;
4239 } else {
4240 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4241 saved_errno = errno;
4244 status = sync_file(conn, fsp, False /* write through */);
4245 if (!NT_STATUS_IS_OK(status)) {
4246 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4247 fsp_str_dbg(fsp), nt_errstr(status)));
4248 reply_nterror(req, status);
4249 goto strict_unlock;
4252 if(nwritten < 0) {
4253 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4254 goto strict_unlock;
4257 if((nwritten < numtowrite) && (numtowrite != 0)) {
4258 reply_nterror(req, NT_STATUS_DISK_FULL);
4259 goto strict_unlock;
4262 if (numtowrite && !fsp->print_file) {
4263 status = do_unlock(req->sconn->msg_ctx,
4264 fsp,
4265 (uint64_t)req->smbpid,
4266 (uint64_t)numtowrite,
4267 (uint64_t)startpos,
4268 WINDOWS_LOCK);
4270 if (NT_STATUS_V(status)) {
4271 reply_nterror(req, status);
4272 goto strict_unlock;
4276 reply_outbuf(req, 1, 0);
4278 SSVAL(req->outbuf,smb_vwv0,nwritten);
4280 DEBUG(3,("writeunlock fnum=%d num=%d wrote=%d\n",
4281 fsp->fnum, (int)numtowrite, (int)nwritten));
4283 strict_unlock:
4284 if (numtowrite && !fsp->print_file) {
4285 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4288 END_PROFILE(SMBwriteunlock);
4289 return;
4292 #undef DBGC_CLASS
4293 #define DBGC_CLASS DBGC_ALL
4295 /****************************************************************************
4296 Reply to a write.
4297 ****************************************************************************/
4299 void reply_write(struct smb_request *req)
4301 connection_struct *conn = req->conn;
4302 size_t numtowrite;
4303 ssize_t nwritten = -1;
4304 SMB_OFF_T startpos;
4305 const char *data;
4306 files_struct *fsp;
4307 struct lock_struct lock;
4308 NTSTATUS status;
4309 int saved_errno = 0;
4311 START_PROFILE(SMBwrite);
4313 if (req->wct < 5) {
4314 END_PROFILE(SMBwrite);
4315 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4316 return;
4319 /* If it's an IPC, pass off the pipe handler. */
4320 if (IS_IPC(conn)) {
4321 reply_pipe_write(req);
4322 END_PROFILE(SMBwrite);
4323 return;
4326 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4328 if (!check_fsp(conn, req, fsp)) {
4329 END_PROFILE(SMBwrite);
4330 return;
4333 if (!CHECK_WRITE(fsp)) {
4334 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4335 END_PROFILE(SMBwrite);
4336 return;
4339 numtowrite = SVAL(req->vwv+1, 0);
4340 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4341 data = (const char *)req->buf + 3;
4343 if (!fsp->print_file) {
4344 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4345 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4346 &lock);
4348 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4349 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4350 END_PROFILE(SMBwrite);
4351 return;
4356 * X/Open SMB protocol says that if smb_vwv1 is
4357 * zero then the file size should be extended or
4358 * truncated to the size given in smb_vwv[2-3].
4361 if(numtowrite == 0) {
4363 * This is actually an allocate call, and set EOF. JRA.
4365 nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos);
4366 if (nwritten < 0) {
4367 reply_nterror(req, NT_STATUS_DISK_FULL);
4368 goto strict_unlock;
4370 nwritten = vfs_set_filelen(fsp, (SMB_OFF_T)startpos);
4371 if (nwritten < 0) {
4372 reply_nterror(req, NT_STATUS_DISK_FULL);
4373 goto strict_unlock;
4375 trigger_write_time_update_immediate(fsp);
4376 } else {
4377 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4380 status = sync_file(conn, fsp, False);
4381 if (!NT_STATUS_IS_OK(status)) {
4382 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4383 fsp_str_dbg(fsp), nt_errstr(status)));
4384 reply_nterror(req, status);
4385 goto strict_unlock;
4388 if(nwritten < 0) {
4389 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4390 goto strict_unlock;
4393 if((nwritten == 0) && (numtowrite != 0)) {
4394 reply_nterror(req, NT_STATUS_DISK_FULL);
4395 goto strict_unlock;
4398 reply_outbuf(req, 1, 0);
4400 SSVAL(req->outbuf,smb_vwv0,nwritten);
4402 if (nwritten < (ssize_t)numtowrite) {
4403 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4404 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4407 DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten));
4409 strict_unlock:
4410 if (!fsp->print_file) {
4411 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4414 END_PROFILE(SMBwrite);
4415 return;
4418 /****************************************************************************
4419 Ensure a buffer is a valid writeX for recvfile purposes.
4420 ****************************************************************************/
4422 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4423 (2*14) + /* word count (including bcc) */ \
4424 1 /* pad byte */)
4426 bool is_valid_writeX_buffer(struct smbd_server_connection *sconn,
4427 const uint8_t *inbuf)
4429 size_t numtowrite;
4430 connection_struct *conn = NULL;
4431 unsigned int doff = 0;
4432 size_t len = smb_len_large(inbuf);
4434 if (is_encrypted_packet(sconn, inbuf)) {
4435 /* Can't do this on encrypted
4436 * connections. */
4437 return false;
4440 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4441 return false;
4444 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4445 CVAL(inbuf,smb_wct) != 14) {
4446 DEBUG(10,("is_valid_writeX_buffer: chained or "
4447 "invalid word length.\n"));
4448 return false;
4451 conn = conn_find(sconn, SVAL(inbuf, smb_tid));
4452 if (conn == NULL) {
4453 DEBUG(10,("is_valid_writeX_buffer: bad tid\n"));
4454 return false;
4456 if (IS_IPC(conn)) {
4457 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4458 return false;
4460 if (IS_PRINT(conn)) {
4461 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4462 return false;
4464 doff = SVAL(inbuf,smb_vwv11);
4466 numtowrite = SVAL(inbuf,smb_vwv10);
4468 if (len > doff && len - doff > 0xFFFF) {
4469 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4472 if (numtowrite == 0) {
4473 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4474 return false;
4477 /* Ensure the sizes match up. */
4478 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4479 /* no pad byte...old smbclient :-( */
4480 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4481 (unsigned int)doff,
4482 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4483 return false;
4486 if (len - doff != numtowrite) {
4487 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4488 "len = %u, doff = %u, numtowrite = %u\n",
4489 (unsigned int)len,
4490 (unsigned int)doff,
4491 (unsigned int)numtowrite ));
4492 return false;
4495 DEBUG(10,("is_valid_writeX_buffer: true "
4496 "len = %u, doff = %u, numtowrite = %u\n",
4497 (unsigned int)len,
4498 (unsigned int)doff,
4499 (unsigned int)numtowrite ));
4501 return true;
4504 /****************************************************************************
4505 Reply to a write and X.
4506 ****************************************************************************/
4508 void reply_write_and_X(struct smb_request *req)
4510 connection_struct *conn = req->conn;
4511 files_struct *fsp;
4512 struct lock_struct lock;
4513 SMB_OFF_T startpos;
4514 size_t numtowrite;
4515 bool write_through;
4516 ssize_t nwritten;
4517 unsigned int smb_doff;
4518 unsigned int smblen;
4519 const char *data;
4520 NTSTATUS status;
4521 int saved_errno = 0;
4523 START_PROFILE(SMBwriteX);
4525 if ((req->wct != 12) && (req->wct != 14)) {
4526 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4527 END_PROFILE(SMBwriteX);
4528 return;
4531 numtowrite = SVAL(req->vwv+10, 0);
4532 smb_doff = SVAL(req->vwv+11, 0);
4533 smblen = smb_len(req->inbuf);
4535 if (req->unread_bytes > 0xFFFF ||
4536 (smblen > smb_doff &&
4537 smblen - smb_doff > 0xFFFF)) {
4538 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
4541 if (req->unread_bytes) {
4542 /* Can't do a recvfile write on IPC$ */
4543 if (IS_IPC(conn)) {
4544 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4545 END_PROFILE(SMBwriteX);
4546 return;
4548 if (numtowrite != req->unread_bytes) {
4549 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4550 END_PROFILE(SMBwriteX);
4551 return;
4553 } else {
4554 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4555 smb_doff + numtowrite > smblen) {
4556 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4557 END_PROFILE(SMBwriteX);
4558 return;
4562 /* If it's an IPC, pass off the pipe handler. */
4563 if (IS_IPC(conn)) {
4564 if (req->unread_bytes) {
4565 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4566 END_PROFILE(SMBwriteX);
4567 return;
4569 reply_pipe_write_and_X(req);
4570 END_PROFILE(SMBwriteX);
4571 return;
4574 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4575 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4576 write_through = BITSETW(req->vwv+7,0);
4578 if (!check_fsp(conn, req, fsp)) {
4579 END_PROFILE(SMBwriteX);
4580 return;
4583 if (!CHECK_WRITE(fsp)) {
4584 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4585 END_PROFILE(SMBwriteX);
4586 return;
4589 data = smb_base(req->inbuf) + smb_doff;
4591 if(req->wct == 14) {
4592 #ifdef LARGE_SMB_OFF_T
4594 * This is a large offset (64 bit) write.
4596 startpos |= (((SMB_OFF_T)IVAL(req->vwv+12, 0)) << 32);
4598 #else /* !LARGE_SMB_OFF_T */
4601 * Ensure we haven't been sent a >32 bit offset.
4604 if(IVAL(req->vwv+12, 0) != 0) {
4605 DEBUG(0,("reply_write_and_X - large offset (%x << 32) "
4606 "used and we don't support 64 bit offsets.\n",
4607 (unsigned int)IVAL(req->vwv+12, 0) ));
4608 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4609 END_PROFILE(SMBwriteX);
4610 return;
4613 #endif /* LARGE_SMB_OFF_T */
4616 /* X/Open SMB protocol says that, unlike SMBwrite
4617 if the length is zero then NO truncation is
4618 done, just a write of zero. To truncate a file,
4619 use SMBwrite. */
4621 if(numtowrite == 0) {
4622 nwritten = 0;
4623 } else {
4624 if (req->unread_bytes == 0) {
4625 status = schedule_aio_write_and_X(conn,
4626 req,
4627 fsp,
4628 data,
4629 startpos,
4630 numtowrite);
4632 if (NT_STATUS_IS_OK(status)) {
4633 /* write scheduled - we're done. */
4634 goto out;
4636 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4637 /* Real error - report to client. */
4638 reply_nterror(req, status);
4639 goto out;
4641 /* NT_STATUS_RETRY - fall through to sync write. */
4644 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4645 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4646 &lock);
4648 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4649 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4650 goto out;
4653 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4654 saved_errno = errno;
4656 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4659 if(nwritten < 0) {
4660 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4661 goto out;
4664 if((nwritten == 0) && (numtowrite != 0)) {
4665 reply_nterror(req, NT_STATUS_DISK_FULL);
4666 goto out;
4669 reply_outbuf(req, 6, 0);
4670 SSVAL(req->outbuf,smb_vwv2,nwritten);
4671 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4673 if (nwritten < (ssize_t)numtowrite) {
4674 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4675 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4678 DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
4679 fsp->fnum, (int)numtowrite, (int)nwritten));
4681 status = sync_file(conn, fsp, write_through);
4682 if (!NT_STATUS_IS_OK(status)) {
4683 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4684 fsp_str_dbg(fsp), nt_errstr(status)));
4685 reply_nterror(req, status);
4686 goto out;
4689 END_PROFILE(SMBwriteX);
4690 chain_reply(req);
4691 return;
4693 out:
4694 END_PROFILE(SMBwriteX);
4695 return;
4698 /****************************************************************************
4699 Reply to a lseek.
4700 ****************************************************************************/
4702 void reply_lseek(struct smb_request *req)
4704 connection_struct *conn = req->conn;
4705 SMB_OFF_T startpos;
4706 SMB_OFF_T res= -1;
4707 int mode,umode;
4708 files_struct *fsp;
4710 START_PROFILE(SMBlseek);
4712 if (req->wct < 4) {
4713 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4714 END_PROFILE(SMBlseek);
4715 return;
4718 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4720 if (!check_fsp(conn, req, fsp)) {
4721 return;
4724 flush_write_cache(fsp, SEEK_FLUSH);
4726 mode = SVAL(req->vwv+1, 0) & 3;
4727 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4728 startpos = (SMB_OFF_T)IVALS(req->vwv+2, 0);
4730 switch (mode) {
4731 case 0:
4732 umode = SEEK_SET;
4733 res = startpos;
4734 break;
4735 case 1:
4736 umode = SEEK_CUR;
4737 res = fsp->fh->pos + startpos;
4738 break;
4739 case 2:
4740 umode = SEEK_END;
4741 break;
4742 default:
4743 umode = SEEK_SET;
4744 res = startpos;
4745 break;
4748 if (umode == SEEK_END) {
4749 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
4750 if(errno == EINVAL) {
4751 SMB_OFF_T current_pos = startpos;
4753 if(fsp_stat(fsp) == -1) {
4754 reply_nterror(req,
4755 map_nt_error_from_unix(errno));
4756 END_PROFILE(SMBlseek);
4757 return;
4760 current_pos += fsp->fsp_name->st.st_ex_size;
4761 if(current_pos < 0)
4762 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
4766 if(res == -1) {
4767 reply_nterror(req, map_nt_error_from_unix(errno));
4768 END_PROFILE(SMBlseek);
4769 return;
4773 fsp->fh->pos = res;
4775 reply_outbuf(req, 2, 0);
4776 SIVAL(req->outbuf,smb_vwv0,res);
4778 DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
4779 fsp->fnum, (double)startpos, (double)res, mode));
4781 END_PROFILE(SMBlseek);
4782 return;
4785 /****************************************************************************
4786 Reply to a flush.
4787 ****************************************************************************/
4789 void reply_flush(struct smb_request *req)
4791 connection_struct *conn = req->conn;
4792 uint16 fnum;
4793 files_struct *fsp;
4795 START_PROFILE(SMBflush);
4797 if (req->wct < 1) {
4798 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4799 return;
4802 fnum = SVAL(req->vwv+0, 0);
4803 fsp = file_fsp(req, fnum);
4805 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
4806 return;
4809 if (!fsp) {
4810 file_sync_all(conn);
4811 } else {
4812 NTSTATUS status = sync_file(conn, fsp, True);
4813 if (!NT_STATUS_IS_OK(status)) {
4814 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
4815 fsp_str_dbg(fsp), nt_errstr(status)));
4816 reply_nterror(req, status);
4817 END_PROFILE(SMBflush);
4818 return;
4822 reply_outbuf(req, 0, 0);
4824 DEBUG(3,("flush\n"));
4825 END_PROFILE(SMBflush);
4826 return;
4829 /****************************************************************************
4830 Reply to a exit.
4831 conn POINTER CAN BE NULL HERE !
4832 ****************************************************************************/
4834 void reply_exit(struct smb_request *req)
4836 START_PROFILE(SMBexit);
4838 file_close_pid(req->sconn, req->smbpid, req->vuid);
4840 reply_outbuf(req, 0, 0);
4842 DEBUG(3,("exit\n"));
4844 END_PROFILE(SMBexit);
4845 return;
4848 /****************************************************************************
4849 Reply to a close - has to deal with closing a directory opened by NT SMB's.
4850 ****************************************************************************/
4852 void reply_close(struct smb_request *req)
4854 connection_struct *conn = req->conn;
4855 NTSTATUS status = NT_STATUS_OK;
4856 files_struct *fsp = NULL;
4857 START_PROFILE(SMBclose);
4859 if (req->wct < 3) {
4860 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4861 END_PROFILE(SMBclose);
4862 return;
4865 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4868 * We can only use check_fsp if we know it's not a directory.
4871 if (!check_fsp_open(conn, req, fsp)) {
4872 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
4873 END_PROFILE(SMBclose);
4874 return;
4877 if(fsp->is_directory) {
4879 * Special case - close NT SMB directory handle.
4881 DEBUG(3,("close directory fnum=%d\n", fsp->fnum));
4882 status = close_file(req, fsp, NORMAL_CLOSE);
4883 } else {
4884 time_t t;
4886 * Close ordinary file.
4889 DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
4890 fsp->fh->fd, fsp->fnum,
4891 conn->num_files_open));
4894 * Take care of any time sent in the close.
4897 t = srv_make_unix_date3(req->vwv+1);
4898 set_close_write_time(fsp, convert_time_t_to_timespec(t));
4901 * close_file() returns the unix errno if an error
4902 * was detected on close - normally this is due to
4903 * a disk full error. If not then it was probably an I/O error.
4906 status = close_file(req, fsp, NORMAL_CLOSE);
4909 if (!NT_STATUS_IS_OK(status)) {
4910 reply_nterror(req, status);
4911 END_PROFILE(SMBclose);
4912 return;
4915 reply_outbuf(req, 0, 0);
4916 END_PROFILE(SMBclose);
4917 return;
4920 /****************************************************************************
4921 Reply to a writeclose (Core+ protocol).
4922 ****************************************************************************/
4924 void reply_writeclose(struct smb_request *req)
4926 connection_struct *conn = req->conn;
4927 size_t numtowrite;
4928 ssize_t nwritten = -1;
4929 NTSTATUS close_status = NT_STATUS_OK;
4930 SMB_OFF_T startpos;
4931 const char *data;
4932 struct timespec mtime;
4933 files_struct *fsp;
4934 struct lock_struct lock;
4936 START_PROFILE(SMBwriteclose);
4938 if (req->wct < 6) {
4939 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4940 END_PROFILE(SMBwriteclose);
4941 return;
4944 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4946 if (!check_fsp(conn, req, fsp)) {
4947 END_PROFILE(SMBwriteclose);
4948 return;
4950 if (!CHECK_WRITE(fsp)) {
4951 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4952 END_PROFILE(SMBwriteclose);
4953 return;
4956 numtowrite = SVAL(req->vwv+1, 0);
4957 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4958 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
4959 data = (const char *)req->buf + 1;
4961 if (!fsp->print_file) {
4962 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4963 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4964 &lock);
4966 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4967 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4968 END_PROFILE(SMBwriteclose);
4969 return;
4973 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4975 set_close_write_time(fsp, mtime);
4978 * More insanity. W2K only closes the file if writelen > 0.
4979 * JRA.
4982 if (numtowrite) {
4983 DEBUG(3,("reply_writeclose: zero length write doesn't close "
4984 "file %s\n", fsp_str_dbg(fsp)));
4985 close_status = close_file(req, fsp, NORMAL_CLOSE);
4988 DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
4989 fsp->fnum, (int)numtowrite, (int)nwritten,
4990 conn->num_files_open));
4992 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
4993 reply_nterror(req, NT_STATUS_DISK_FULL);
4994 goto strict_unlock;
4997 if(!NT_STATUS_IS_OK(close_status)) {
4998 reply_nterror(req, close_status);
4999 goto strict_unlock;
5002 reply_outbuf(req, 1, 0);
5004 SSVAL(req->outbuf,smb_vwv0,nwritten);
5006 strict_unlock:
5007 if (numtowrite && !fsp->print_file) {
5008 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
5011 END_PROFILE(SMBwriteclose);
5012 return;
5015 #undef DBGC_CLASS
5016 #define DBGC_CLASS DBGC_LOCKING
5018 /****************************************************************************
5019 Reply to a lock.
5020 ****************************************************************************/
5022 void reply_lock(struct smb_request *req)
5024 connection_struct *conn = req->conn;
5025 uint64_t count,offset;
5026 NTSTATUS status;
5027 files_struct *fsp;
5028 struct byte_range_lock *br_lck = NULL;
5030 START_PROFILE(SMBlock);
5032 if (req->wct < 5) {
5033 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5034 END_PROFILE(SMBlock);
5035 return;
5038 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5040 if (!check_fsp(conn, req, fsp)) {
5041 END_PROFILE(SMBlock);
5042 return;
5045 count = (uint64_t)IVAL(req->vwv+1, 0);
5046 offset = (uint64_t)IVAL(req->vwv+3, 0);
5048 DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
5049 fsp->fh->fd, fsp->fnum, (double)offset, (double)count));
5051 br_lck = do_lock(req->sconn->msg_ctx,
5052 fsp,
5053 (uint64_t)req->smbpid,
5054 count,
5055 offset,
5056 WRITE_LOCK,
5057 WINDOWS_LOCK,
5058 False, /* Non-blocking lock. */
5059 &status,
5060 NULL,
5061 NULL);
5063 TALLOC_FREE(br_lck);
5065 if (NT_STATUS_V(status)) {
5066 reply_nterror(req, status);
5067 END_PROFILE(SMBlock);
5068 return;
5071 reply_outbuf(req, 0, 0);
5073 END_PROFILE(SMBlock);
5074 return;
5077 /****************************************************************************
5078 Reply to a unlock.
5079 ****************************************************************************/
5081 void reply_unlock(struct smb_request *req)
5083 connection_struct *conn = req->conn;
5084 uint64_t count,offset;
5085 NTSTATUS status;
5086 files_struct *fsp;
5088 START_PROFILE(SMBunlock);
5090 if (req->wct < 5) {
5091 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5092 END_PROFILE(SMBunlock);
5093 return;
5096 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5098 if (!check_fsp(conn, req, fsp)) {
5099 END_PROFILE(SMBunlock);
5100 return;
5103 count = (uint64_t)IVAL(req->vwv+1, 0);
5104 offset = (uint64_t)IVAL(req->vwv+3, 0);
5106 status = do_unlock(req->sconn->msg_ctx,
5107 fsp,
5108 (uint64_t)req->smbpid,
5109 count,
5110 offset,
5111 WINDOWS_LOCK);
5113 if (NT_STATUS_V(status)) {
5114 reply_nterror(req, status);
5115 END_PROFILE(SMBunlock);
5116 return;
5119 DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
5120 fsp->fh->fd, fsp->fnum, (double)offset, (double)count ) );
5122 reply_outbuf(req, 0, 0);
5124 END_PROFILE(SMBunlock);
5125 return;
5128 #undef DBGC_CLASS
5129 #define DBGC_CLASS DBGC_ALL
5131 /****************************************************************************
5132 Reply to a tdis.
5133 conn POINTER CAN BE NULL HERE !
5134 ****************************************************************************/
5136 void reply_tdis(struct smb_request *req)
5138 connection_struct *conn = req->conn;
5139 START_PROFILE(SMBtdis);
5141 if (!conn) {
5142 DEBUG(4,("Invalid connection in tdis\n"));
5143 reply_nterror(req, NT_STATUS_NETWORK_NAME_DELETED);
5144 END_PROFILE(SMBtdis);
5145 return;
5148 conn->used = False;
5150 close_cnum(conn,req->vuid);
5151 req->conn = NULL;
5153 reply_outbuf(req, 0, 0);
5154 END_PROFILE(SMBtdis);
5155 return;
5158 /****************************************************************************
5159 Reply to a echo.
5160 conn POINTER CAN BE NULL HERE !
5161 ****************************************************************************/
5163 void reply_echo(struct smb_request *req)
5165 connection_struct *conn = req->conn;
5166 struct smb_perfcount_data local_pcd;
5167 struct smb_perfcount_data *cur_pcd;
5168 int smb_reverb;
5169 int seq_num;
5171 START_PROFILE(SMBecho);
5173 smb_init_perfcount_data(&local_pcd);
5175 if (req->wct < 1) {
5176 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5177 END_PROFILE(SMBecho);
5178 return;
5181 smb_reverb = SVAL(req->vwv+0, 0);
5183 reply_outbuf(req, 1, req->buflen);
5185 /* copy any incoming data back out */
5186 if (req->buflen > 0) {
5187 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5190 if (smb_reverb > 100) {
5191 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5192 smb_reverb = 100;
5195 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5197 /* this makes sure we catch the request pcd */
5198 if (seq_num == smb_reverb) {
5199 cur_pcd = &req->pcd;
5200 } else {
5201 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5202 cur_pcd = &local_pcd;
5205 SSVAL(req->outbuf,smb_vwv0,seq_num);
5207 show_msg((char *)req->outbuf);
5208 if (!srv_send_smb(req->sconn,
5209 (char *)req->outbuf,
5210 true, req->seqnum+1,
5211 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5212 cur_pcd))
5213 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5216 DEBUG(3,("echo %d times\n", smb_reverb));
5218 TALLOC_FREE(req->outbuf);
5220 END_PROFILE(SMBecho);
5221 return;
5224 /****************************************************************************
5225 Reply to a printopen.
5226 ****************************************************************************/
5228 void reply_printopen(struct smb_request *req)
5230 connection_struct *conn = req->conn;
5231 files_struct *fsp;
5232 NTSTATUS status;
5234 START_PROFILE(SMBsplopen);
5236 if (req->wct < 2) {
5237 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5238 END_PROFILE(SMBsplopen);
5239 return;
5242 if (!CAN_PRINT(conn)) {
5243 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5244 END_PROFILE(SMBsplopen);
5245 return;
5248 status = file_new(req, conn, &fsp);
5249 if(!NT_STATUS_IS_OK(status)) {
5250 reply_nterror(req, status);
5251 END_PROFILE(SMBsplopen);
5252 return;
5255 /* Open for exclusive use, write only. */
5256 status = print_spool_open(fsp, NULL, req->vuid);
5258 if (!NT_STATUS_IS_OK(status)) {
5259 file_free(req, fsp);
5260 reply_nterror(req, status);
5261 END_PROFILE(SMBsplopen);
5262 return;
5265 reply_outbuf(req, 1, 0);
5266 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5268 DEBUG(3,("openprint fd=%d fnum=%d\n",
5269 fsp->fh->fd, fsp->fnum));
5271 END_PROFILE(SMBsplopen);
5272 return;
5275 /****************************************************************************
5276 Reply to a printclose.
5277 ****************************************************************************/
5279 void reply_printclose(struct smb_request *req)
5281 connection_struct *conn = req->conn;
5282 files_struct *fsp;
5283 NTSTATUS status;
5285 START_PROFILE(SMBsplclose);
5287 if (req->wct < 1) {
5288 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5289 END_PROFILE(SMBsplclose);
5290 return;
5293 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5295 if (!check_fsp(conn, req, fsp)) {
5296 END_PROFILE(SMBsplclose);
5297 return;
5300 if (!CAN_PRINT(conn)) {
5301 reply_force_doserror(req, ERRSRV, ERRerror);
5302 END_PROFILE(SMBsplclose);
5303 return;
5306 DEBUG(3,("printclose fd=%d fnum=%d\n",
5307 fsp->fh->fd,fsp->fnum));
5309 status = close_file(req, fsp, NORMAL_CLOSE);
5311 if(!NT_STATUS_IS_OK(status)) {
5312 reply_nterror(req, status);
5313 END_PROFILE(SMBsplclose);
5314 return;
5317 reply_outbuf(req, 0, 0);
5319 END_PROFILE(SMBsplclose);
5320 return;
5323 /****************************************************************************
5324 Reply to a printqueue.
5325 ****************************************************************************/
5327 void reply_printqueue(struct smb_request *req)
5329 connection_struct *conn = req->conn;
5330 int max_count;
5331 int start_index;
5333 START_PROFILE(SMBsplretq);
5335 if (req->wct < 2) {
5336 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5337 END_PROFILE(SMBsplretq);
5338 return;
5341 max_count = SVAL(req->vwv+0, 0);
5342 start_index = SVAL(req->vwv+1, 0);
5344 /* we used to allow the client to get the cnum wrong, but that
5345 is really quite gross and only worked when there was only
5346 one printer - I think we should now only accept it if they
5347 get it right (tridge) */
5348 if (!CAN_PRINT(conn)) {
5349 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5350 END_PROFILE(SMBsplretq);
5351 return;
5354 reply_outbuf(req, 2, 3);
5355 SSVAL(req->outbuf,smb_vwv0,0);
5356 SSVAL(req->outbuf,smb_vwv1,0);
5357 SCVAL(smb_buf(req->outbuf),0,1);
5358 SSVAL(smb_buf(req->outbuf),1,0);
5360 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5361 start_index, max_count));
5364 TALLOC_CTX *mem_ctx = talloc_tos();
5365 NTSTATUS status;
5366 WERROR werr;
5367 const char *sharename = lp_servicename(SNUM(conn));
5368 struct rpc_pipe_client *cli = NULL;
5369 struct dcerpc_binding_handle *b = NULL;
5370 struct policy_handle handle;
5371 struct spoolss_DevmodeContainer devmode_ctr;
5372 union spoolss_JobInfo *info;
5373 uint32_t count;
5374 uint32_t num_to_get;
5375 uint32_t first;
5376 uint32_t i;
5378 ZERO_STRUCT(handle);
5380 status = rpc_pipe_open_interface(conn,
5381 &ndr_table_spoolss.syntax_id,
5382 conn->session_info,
5383 conn->sconn->remote_address,
5384 conn->sconn->msg_ctx,
5385 &cli);
5386 if (!NT_STATUS_IS_OK(status)) {
5387 DEBUG(0, ("reply_printqueue: "
5388 "could not connect to spoolss: %s\n",
5389 nt_errstr(status)));
5390 reply_nterror(req, status);
5391 goto out;
5393 b = cli->binding_handle;
5395 ZERO_STRUCT(devmode_ctr);
5397 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5398 sharename,
5399 NULL, devmode_ctr,
5400 SEC_FLAG_MAXIMUM_ALLOWED,
5401 &handle,
5402 &werr);
5403 if (!NT_STATUS_IS_OK(status)) {
5404 reply_nterror(req, status);
5405 goto out;
5407 if (!W_ERROR_IS_OK(werr)) {
5408 reply_nterror(req, werror_to_ntstatus(werr));
5409 goto out;
5412 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5413 &handle,
5414 0, /* firstjob */
5415 0xff, /* numjobs */
5416 2, /* level */
5417 0, /* offered */
5418 &count,
5419 &info);
5420 if (!W_ERROR_IS_OK(werr)) {
5421 reply_nterror(req, werror_to_ntstatus(werr));
5422 goto out;
5425 if (max_count > 0) {
5426 first = start_index;
5427 } else {
5428 first = start_index + max_count + 1;
5431 if (first >= count) {
5432 num_to_get = first;
5433 } else {
5434 num_to_get = first + MIN(ABS(max_count), count - first);
5437 for (i = first; i < num_to_get; i++) {
5438 char blob[28];
5439 char *p = blob;
5440 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
5441 int qstatus;
5442 uint16_t qrapjobid = pjobid_to_rap(sharename,
5443 info[i].info2.job_id);
5445 if (info[i].info2.status == JOB_STATUS_PRINTING) {
5446 qstatus = 2;
5447 } else {
5448 qstatus = 3;
5451 srv_put_dos_date2(p, 0, qtime);
5452 SCVAL(p, 4, qstatus);
5453 SSVAL(p, 5, qrapjobid);
5454 SIVAL(p, 7, info[i].info2.size);
5455 SCVAL(p, 11, 0);
5456 srvstr_push(blob, req->flags2, p+12,
5457 info[i].info2.notify_name, 16, STR_ASCII);
5459 if (message_push_blob(
5460 &req->outbuf,
5461 data_blob_const(
5462 blob, sizeof(blob))) == -1) {
5463 reply_nterror(req, NT_STATUS_NO_MEMORY);
5464 goto out;
5468 if (count > 0) {
5469 SSVAL(req->outbuf,smb_vwv0,count);
5470 SSVAL(req->outbuf,smb_vwv1,
5471 (max_count>0?first+count:first-1));
5472 SCVAL(smb_buf(req->outbuf),0,1);
5473 SSVAL(smb_buf(req->outbuf),1,28*count);
5477 DEBUG(3, ("%u entries returned in queue\n",
5478 (unsigned)count));
5480 out:
5481 if (b && is_valid_policy_hnd(&handle)) {
5482 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5487 END_PROFILE(SMBsplretq);
5488 return;
5491 /****************************************************************************
5492 Reply to a printwrite.
5493 ****************************************************************************/
5495 void reply_printwrite(struct smb_request *req)
5497 connection_struct *conn = req->conn;
5498 int numtowrite;
5499 const char *data;
5500 files_struct *fsp;
5502 START_PROFILE(SMBsplwr);
5504 if (req->wct < 1) {
5505 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5506 END_PROFILE(SMBsplwr);
5507 return;
5510 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5512 if (!check_fsp(conn, req, fsp)) {
5513 END_PROFILE(SMBsplwr);
5514 return;
5517 if (!fsp->print_file) {
5518 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5519 END_PROFILE(SMBsplwr);
5520 return;
5523 if (!CHECK_WRITE(fsp)) {
5524 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5525 END_PROFILE(SMBsplwr);
5526 return;
5529 numtowrite = SVAL(req->buf, 1);
5531 if (req->buflen < numtowrite + 3) {
5532 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5533 END_PROFILE(SMBsplwr);
5534 return;
5537 data = (const char *)req->buf + 3;
5539 if (write_file(req,fsp,data,(SMB_OFF_T)-1,numtowrite) != numtowrite) {
5540 reply_nterror(req, map_nt_error_from_unix(errno));
5541 END_PROFILE(SMBsplwr);
5542 return;
5545 DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
5547 END_PROFILE(SMBsplwr);
5548 return;
5551 /****************************************************************************
5552 Reply to a mkdir.
5553 ****************************************************************************/
5555 void reply_mkdir(struct smb_request *req)
5557 connection_struct *conn = req->conn;
5558 struct smb_filename *smb_dname = NULL;
5559 char *directory = NULL;
5560 NTSTATUS status;
5561 TALLOC_CTX *ctx = talloc_tos();
5563 START_PROFILE(SMBmkdir);
5565 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5566 STR_TERMINATE, &status);
5567 if (!NT_STATUS_IS_OK(status)) {
5568 reply_nterror(req, status);
5569 goto out;
5572 status = filename_convert(ctx, conn,
5573 req->flags2 & FLAGS2_DFS_PATHNAMES,
5574 directory,
5576 NULL,
5577 &smb_dname);
5578 if (!NT_STATUS_IS_OK(status)) {
5579 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5580 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5581 ERRSRV, ERRbadpath);
5582 goto out;
5584 reply_nterror(req, status);
5585 goto out;
5588 status = create_directory(conn, req, smb_dname);
5590 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
5592 if (!NT_STATUS_IS_OK(status)) {
5594 if (!use_nt_status()
5595 && NT_STATUS_EQUAL(status,
5596 NT_STATUS_OBJECT_NAME_COLLISION)) {
5598 * Yes, in the DOS error code case we get a
5599 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
5600 * samba4 torture test.
5602 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
5605 reply_nterror(req, status);
5606 goto out;
5609 reply_outbuf(req, 0, 0);
5611 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
5612 out:
5613 TALLOC_FREE(smb_dname);
5614 END_PROFILE(SMBmkdir);
5615 return;
5618 /****************************************************************************
5619 Reply to a rmdir.
5620 ****************************************************************************/
5622 void reply_rmdir(struct smb_request *req)
5624 connection_struct *conn = req->conn;
5625 struct smb_filename *smb_dname = NULL;
5626 char *directory = NULL;
5627 NTSTATUS status;
5628 TALLOC_CTX *ctx = talloc_tos();
5629 files_struct *fsp = NULL;
5630 int info = 0;
5631 struct smbd_server_connection *sconn = req->sconn;
5633 START_PROFILE(SMBrmdir);
5635 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5636 STR_TERMINATE, &status);
5637 if (!NT_STATUS_IS_OK(status)) {
5638 reply_nterror(req, status);
5639 goto out;
5642 status = filename_convert(ctx, conn,
5643 req->flags2 & FLAGS2_DFS_PATHNAMES,
5644 directory,
5646 NULL,
5647 &smb_dname);
5648 if (!NT_STATUS_IS_OK(status)) {
5649 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5650 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5651 ERRSRV, ERRbadpath);
5652 goto out;
5654 reply_nterror(req, status);
5655 goto out;
5658 if (is_ntfs_stream_smb_fname(smb_dname)) {
5659 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
5660 goto out;
5663 status = SMB_VFS_CREATE_FILE(
5664 conn, /* conn */
5665 req, /* req */
5666 0, /* root_dir_fid */
5667 smb_dname, /* fname */
5668 DELETE_ACCESS, /* access_mask */
5669 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5670 FILE_SHARE_DELETE),
5671 FILE_OPEN, /* create_disposition*/
5672 FILE_DIRECTORY_FILE, /* create_options */
5673 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
5674 0, /* oplock_request */
5675 0, /* allocation_size */
5676 0, /* private_flags */
5677 NULL, /* sd */
5678 NULL, /* ea_list */
5679 &fsp, /* result */
5680 &info); /* pinfo */
5682 if (!NT_STATUS_IS_OK(status)) {
5683 if (open_was_deferred(req->sconn, req->mid)) {
5684 /* We have re-scheduled this call. */
5685 goto out;
5687 reply_nterror(req, status);
5688 goto out;
5691 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
5692 if (!NT_STATUS_IS_OK(status)) {
5693 close_file(req, fsp, ERROR_CLOSE);
5694 reply_nterror(req, status);
5695 goto out;
5698 if (!set_delete_on_close(fsp, true, conn->session_info->unix_token)) {
5699 close_file(req, fsp, ERROR_CLOSE);
5700 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5701 goto out;
5704 status = close_file(req, fsp, NORMAL_CLOSE);
5705 if (!NT_STATUS_IS_OK(status)) {
5706 reply_nterror(req, status);
5707 } else {
5708 reply_outbuf(req, 0, 0);
5711 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
5713 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
5714 out:
5715 TALLOC_FREE(smb_dname);
5716 END_PROFILE(SMBrmdir);
5717 return;
5720 /*******************************************************************
5721 Resolve wildcards in a filename rename.
5722 ********************************************************************/
5724 static bool resolve_wildcards(TALLOC_CTX *ctx,
5725 const char *name1,
5726 const char *name2,
5727 char **pp_newname)
5729 char *name2_copy = NULL;
5730 char *root1 = NULL;
5731 char *root2 = NULL;
5732 char *ext1 = NULL;
5733 char *ext2 = NULL;
5734 char *p,*p2, *pname1, *pname2;
5736 name2_copy = talloc_strdup(ctx, name2);
5737 if (!name2_copy) {
5738 return False;
5741 pname1 = strrchr_m(name1,'/');
5742 pname2 = strrchr_m(name2_copy,'/');
5744 if (!pname1 || !pname2) {
5745 return False;
5748 /* Truncate the copy of name2 at the last '/' */
5749 *pname2 = '\0';
5751 /* Now go past the '/' */
5752 pname1++;
5753 pname2++;
5755 root1 = talloc_strdup(ctx, pname1);
5756 root2 = talloc_strdup(ctx, pname2);
5758 if (!root1 || !root2) {
5759 return False;
5762 p = strrchr_m(root1,'.');
5763 if (p) {
5764 *p = 0;
5765 ext1 = talloc_strdup(ctx, p+1);
5766 } else {
5767 ext1 = talloc_strdup(ctx, "");
5769 p = strrchr_m(root2,'.');
5770 if (p) {
5771 *p = 0;
5772 ext2 = talloc_strdup(ctx, p+1);
5773 } else {
5774 ext2 = talloc_strdup(ctx, "");
5777 if (!ext1 || !ext2) {
5778 return False;
5781 p = root1;
5782 p2 = root2;
5783 while (*p2) {
5784 if (*p2 == '?') {
5785 /* Hmmm. Should this be mb-aware ? */
5786 *p2 = *p;
5787 p2++;
5788 } else if (*p2 == '*') {
5789 *p2 = '\0';
5790 root2 = talloc_asprintf(ctx, "%s%s",
5791 root2,
5793 if (!root2) {
5794 return False;
5796 break;
5797 } else {
5798 p2++;
5800 if (*p) {
5801 p++;
5805 p = ext1;
5806 p2 = ext2;
5807 while (*p2) {
5808 if (*p2 == '?') {
5809 /* Hmmm. Should this be mb-aware ? */
5810 *p2 = *p;
5811 p2++;
5812 } else if (*p2 == '*') {
5813 *p2 = '\0';
5814 ext2 = talloc_asprintf(ctx, "%s%s",
5815 ext2,
5817 if (!ext2) {
5818 return False;
5820 break;
5821 } else {
5822 p2++;
5824 if (*p) {
5825 p++;
5829 if (*ext2) {
5830 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
5831 name2_copy,
5832 root2,
5833 ext2);
5834 } else {
5835 *pp_newname = talloc_asprintf(ctx, "%s/%s",
5836 name2_copy,
5837 root2);
5840 if (!*pp_newname) {
5841 return False;
5844 return True;
5847 /****************************************************************************
5848 Ensure open files have their names updated. Updated to notify other smbd's
5849 asynchronously.
5850 ****************************************************************************/
5852 static void rename_open_files(connection_struct *conn,
5853 struct share_mode_lock *lck,
5854 uint32_t orig_name_hash,
5855 const struct smb_filename *smb_fname_dst)
5857 files_struct *fsp;
5858 bool did_rename = False;
5859 NTSTATUS status;
5860 uint32_t new_name_hash = 0;
5862 for(fsp = file_find_di_first(conn->sconn, lck->id); fsp;
5863 fsp = file_find_di_next(fsp)) {
5864 /* fsp_name is a relative path under the fsp. To change this for other
5865 sharepaths we need to manipulate relative paths. */
5866 /* TODO - create the absolute path and manipulate the newname
5867 relative to the sharepath. */
5868 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
5869 continue;
5871 if (fsp->name_hash != orig_name_hash) {
5872 continue;
5874 DEBUG(10, ("rename_open_files: renaming file fnum %d "
5875 "(file_id %s) from %s -> %s\n", fsp->fnum,
5876 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
5877 smb_fname_str_dbg(smb_fname_dst)));
5879 status = fsp_set_smb_fname(fsp, smb_fname_dst);
5880 if (NT_STATUS_IS_OK(status)) {
5881 did_rename = True;
5882 new_name_hash = fsp->name_hash;
5886 if (!did_rename) {
5887 DEBUG(10, ("rename_open_files: no open files on file_id %s "
5888 "for %s\n", file_id_string_tos(&lck->id),
5889 smb_fname_str_dbg(smb_fname_dst)));
5892 /* Send messages to all smbd's (not ourself) that the name has changed. */
5893 rename_share_filename(conn->sconn->msg_ctx, lck, conn->connectpath,
5894 orig_name_hash, new_name_hash,
5895 smb_fname_dst);
5899 /****************************************************************************
5900 We need to check if the source path is a parent directory of the destination
5901 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
5902 refuse the rename with a sharing violation. Under UNIX the above call can
5903 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
5904 probably need to check that the client is a Windows one before disallowing
5905 this as a UNIX client (one with UNIX extensions) can know the source is a
5906 symlink and make this decision intelligently. Found by an excellent bug
5907 report from <AndyLiebman@aol.com>.
5908 ****************************************************************************/
5910 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
5911 const struct smb_filename *smb_fname_dst)
5913 const char *psrc = smb_fname_src->base_name;
5914 const char *pdst = smb_fname_dst->base_name;
5915 size_t slen;
5917 if (psrc[0] == '.' && psrc[1] == '/') {
5918 psrc += 2;
5920 if (pdst[0] == '.' && pdst[1] == '/') {
5921 pdst += 2;
5923 if ((slen = strlen(psrc)) > strlen(pdst)) {
5924 return False;
5926 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
5930 * Do the notify calls from a rename
5933 static void notify_rename(connection_struct *conn, bool is_dir,
5934 const struct smb_filename *smb_fname_src,
5935 const struct smb_filename *smb_fname_dst)
5937 char *parent_dir_src = NULL;
5938 char *parent_dir_dst = NULL;
5939 uint32 mask;
5941 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
5942 : FILE_NOTIFY_CHANGE_FILE_NAME;
5944 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
5945 &parent_dir_src, NULL) ||
5946 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
5947 &parent_dir_dst, NULL)) {
5948 goto out;
5951 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
5952 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
5953 smb_fname_src->base_name);
5954 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
5955 smb_fname_dst->base_name);
5957 else {
5958 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
5959 smb_fname_src->base_name);
5960 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
5961 smb_fname_dst->base_name);
5964 /* this is a strange one. w2k3 gives an additional event for
5965 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
5966 files, but not directories */
5967 if (!is_dir) {
5968 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
5969 FILE_NOTIFY_CHANGE_ATTRIBUTES
5970 |FILE_NOTIFY_CHANGE_CREATION,
5971 smb_fname_dst->base_name);
5973 out:
5974 TALLOC_FREE(parent_dir_src);
5975 TALLOC_FREE(parent_dir_dst);
5978 /****************************************************************************
5979 Returns an error if the parent directory for a filename is open in an
5980 incompatible way.
5981 ****************************************************************************/
5983 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
5984 const struct smb_filename *smb_fname_dst_in)
5986 char *parent_dir = NULL;
5987 struct smb_filename smb_fname_parent;
5988 struct file_id id;
5989 files_struct *fsp = NULL;
5990 int ret;
5992 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
5993 &parent_dir, NULL)) {
5994 return NT_STATUS_NO_MEMORY;
5996 ZERO_STRUCT(smb_fname_parent);
5997 smb_fname_parent.base_name = parent_dir;
5999 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
6000 if (ret == -1) {
6001 return map_nt_error_from_unix(errno);
6005 * We're only checking on this smbd here, mostly good
6006 * enough.. and will pass tests.
6009 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
6010 for (fsp = file_find_di_first(conn->sconn, id); fsp;
6011 fsp = file_find_di_next(fsp)) {
6012 if (fsp->access_mask & DELETE_ACCESS) {
6013 return NT_STATUS_SHARING_VIOLATION;
6016 return NT_STATUS_OK;
6019 /****************************************************************************
6020 Rename an open file - given an fsp.
6021 ****************************************************************************/
6023 NTSTATUS rename_internals_fsp(connection_struct *conn,
6024 files_struct *fsp,
6025 const struct smb_filename *smb_fname_dst_in,
6026 uint32 attrs,
6027 bool replace_if_exists)
6029 TALLOC_CTX *ctx = talloc_tos();
6030 struct smb_filename *smb_fname_dst = NULL;
6031 NTSTATUS status = NT_STATUS_OK;
6032 struct share_mode_lock *lck = NULL;
6033 bool dst_exists, old_is_stream, new_is_stream;
6035 status = check_name(conn, smb_fname_dst_in->base_name);
6036 if (!NT_STATUS_IS_OK(status)) {
6037 return status;
6040 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
6041 if (!NT_STATUS_IS_OK(status)) {
6042 return status;
6045 /* Make a copy of the dst smb_fname structs */
6047 status = copy_smb_filename(ctx, smb_fname_dst_in, &smb_fname_dst);
6048 if (!NT_STATUS_IS_OK(status)) {
6049 goto out;
6053 * Check for special case with case preserving and not
6054 * case sensitive. If the old last component differs from the original
6055 * last component only by case, then we should allow
6056 * the rename (user is trying to change the case of the
6057 * filename).
6059 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
6060 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6061 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
6062 char *last_slash;
6063 char *fname_dst_lcomp_base_mod = NULL;
6064 struct smb_filename *smb_fname_orig_lcomp = NULL;
6067 * Get the last component of the destination name.
6069 last_slash = strrchr_m(smb_fname_dst->base_name, '/');
6070 if (last_slash) {
6071 fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1);
6072 } else {
6073 fname_dst_lcomp_base_mod = talloc_strdup(ctx, smb_fname_dst->base_name);
6075 if (!fname_dst_lcomp_base_mod) {
6076 status = NT_STATUS_NO_MEMORY;
6077 goto out;
6081 * Create an smb_filename struct using the original last
6082 * component of the destination.
6084 status = create_synthetic_smb_fname_split(ctx,
6085 smb_fname_dst->original_lcomp, NULL,
6086 &smb_fname_orig_lcomp);
6087 if (!NT_STATUS_IS_OK(status)) {
6088 TALLOC_FREE(fname_dst_lcomp_base_mod);
6089 goto out;
6092 /* If the base names only differ by case, use original. */
6093 if(!strcsequal(fname_dst_lcomp_base_mod,
6094 smb_fname_orig_lcomp->base_name)) {
6095 char *tmp;
6097 * Replace the modified last component with the
6098 * original.
6100 if (last_slash) {
6101 *last_slash = '\0'; /* Truncate at the '/' */
6102 tmp = talloc_asprintf(smb_fname_dst,
6103 "%s/%s",
6104 smb_fname_dst->base_name,
6105 smb_fname_orig_lcomp->base_name);
6106 } else {
6107 tmp = talloc_asprintf(smb_fname_dst,
6108 "%s",
6109 smb_fname_orig_lcomp->base_name);
6111 if (tmp == NULL) {
6112 status = NT_STATUS_NO_MEMORY;
6113 TALLOC_FREE(fname_dst_lcomp_base_mod);
6114 TALLOC_FREE(smb_fname_orig_lcomp);
6115 goto out;
6117 TALLOC_FREE(smb_fname_dst->base_name);
6118 smb_fname_dst->base_name = tmp;
6121 /* If the stream_names only differ by case, use original. */
6122 if(!strcsequal(smb_fname_dst->stream_name,
6123 smb_fname_orig_lcomp->stream_name)) {
6124 char *tmp = NULL;
6125 /* Use the original stream. */
6126 tmp = talloc_strdup(smb_fname_dst,
6127 smb_fname_orig_lcomp->stream_name);
6128 if (tmp == NULL) {
6129 status = NT_STATUS_NO_MEMORY;
6130 TALLOC_FREE(fname_dst_lcomp_base_mod);
6131 TALLOC_FREE(smb_fname_orig_lcomp);
6132 goto out;
6134 TALLOC_FREE(smb_fname_dst->stream_name);
6135 smb_fname_dst->stream_name = tmp;
6137 TALLOC_FREE(fname_dst_lcomp_base_mod);
6138 TALLOC_FREE(smb_fname_orig_lcomp);
6142 * If the src and dest names are identical - including case,
6143 * don't do the rename, just return success.
6146 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6147 strcsequal(fsp->fsp_name->stream_name,
6148 smb_fname_dst->stream_name)) {
6149 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6150 "- returning success\n",
6151 smb_fname_str_dbg(smb_fname_dst)));
6152 status = NT_STATUS_OK;
6153 goto out;
6156 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6157 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6159 /* Return the correct error code if both names aren't streams. */
6160 if (!old_is_stream && new_is_stream) {
6161 status = NT_STATUS_OBJECT_NAME_INVALID;
6162 goto out;
6165 if (old_is_stream && !new_is_stream) {
6166 status = NT_STATUS_INVALID_PARAMETER;
6167 goto out;
6170 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6172 if(!replace_if_exists && dst_exists) {
6173 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6174 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6175 smb_fname_str_dbg(smb_fname_dst)));
6176 status = NT_STATUS_OBJECT_NAME_COLLISION;
6177 goto out;
6180 if (dst_exists) {
6181 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6182 &smb_fname_dst->st);
6183 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6184 fileid);
6185 /* The file can be open when renaming a stream */
6186 if (dst_fsp && !new_is_stream) {
6187 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6188 status = NT_STATUS_ACCESS_DENIED;
6189 goto out;
6193 /* Ensure we have a valid stat struct for the source. */
6194 status = vfs_stat_fsp(fsp);
6195 if (!NT_STATUS_IS_OK(status)) {
6196 goto out;
6199 status = can_rename(conn, fsp, attrs);
6201 if (!NT_STATUS_IS_OK(status)) {
6202 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6203 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6204 smb_fname_str_dbg(smb_fname_dst)));
6205 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6206 status = NT_STATUS_ACCESS_DENIED;
6207 goto out;
6210 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6211 status = NT_STATUS_ACCESS_DENIED;
6214 lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
6215 NULL);
6218 * We have the file open ourselves, so not being able to get the
6219 * corresponding share mode lock is a fatal error.
6222 SMB_ASSERT(lck != NULL);
6224 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6225 uint32 create_options = fsp->fh->private_options;
6227 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6228 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6229 smb_fname_str_dbg(smb_fname_dst)));
6231 if (!lp_posix_pathnames() &&
6232 (lp_map_archive(SNUM(conn)) ||
6233 lp_store_dos_attributes(SNUM(conn)))) {
6234 /* We must set the archive bit on the newly
6235 renamed file. */
6236 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6237 uint32_t old_dosmode = dos_mode(conn,
6238 smb_fname_dst);
6239 file_set_dosmode(conn,
6240 smb_fname_dst,
6241 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6242 NULL,
6243 true);
6247 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6248 smb_fname_dst);
6250 rename_open_files(conn, lck, fsp->name_hash, smb_fname_dst);
6253 * A rename acts as a new file create w.r.t. allowing an initial delete
6254 * on close, probably because in Windows there is a new handle to the
6255 * new file. If initial delete on close was requested but not
6256 * originally set, we need to set it here. This is probably not 100% correct,
6257 * but will work for the CIFSFS client which in non-posix mode
6258 * depends on these semantics. JRA.
6261 if (create_options & FILE_DELETE_ON_CLOSE) {
6262 status = can_set_delete_on_close(fsp, 0);
6264 if (NT_STATUS_IS_OK(status)) {
6265 /* Note that here we set the *inital* delete on close flag,
6266 * not the regular one. The magic gets handled in close. */
6267 fsp->initial_delete_on_close = True;
6270 TALLOC_FREE(lck);
6271 status = NT_STATUS_OK;
6272 goto out;
6275 TALLOC_FREE(lck);
6277 if (errno == ENOTDIR || errno == EISDIR) {
6278 status = NT_STATUS_OBJECT_NAME_COLLISION;
6279 } else {
6280 status = map_nt_error_from_unix(errno);
6283 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6284 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6285 smb_fname_str_dbg(smb_fname_dst)));
6287 out:
6288 TALLOC_FREE(smb_fname_dst);
6290 return status;
6293 /****************************************************************************
6294 The guts of the rename command, split out so it may be called by the NT SMB
6295 code.
6296 ****************************************************************************/
6298 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6299 connection_struct *conn,
6300 struct smb_request *req,
6301 struct smb_filename *smb_fname_src,
6302 struct smb_filename *smb_fname_dst,
6303 uint32 attrs,
6304 bool replace_if_exists,
6305 bool src_has_wild,
6306 bool dest_has_wild,
6307 uint32_t access_mask)
6309 char *fname_src_dir = NULL;
6310 char *fname_src_mask = NULL;
6311 int count=0;
6312 NTSTATUS status = NT_STATUS_OK;
6313 struct smb_Dir *dir_hnd = NULL;
6314 const char *dname = NULL;
6315 char *talloced = NULL;
6316 long offset = 0;
6317 int create_options = 0;
6318 bool posix_pathnames = lp_posix_pathnames();
6321 * Split the old name into directory and last component
6322 * strings. Note that unix_convert may have stripped off a
6323 * leading ./ from both name and newname if the rename is
6324 * at the root of the share. We need to make sure either both
6325 * name and newname contain a / character or neither of them do
6326 * as this is checked in resolve_wildcards().
6329 /* Split up the directory from the filename/mask. */
6330 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6331 &fname_src_dir, &fname_src_mask);
6332 if (!NT_STATUS_IS_OK(status)) {
6333 status = NT_STATUS_NO_MEMORY;
6334 goto out;
6338 * We should only check the mangled cache
6339 * here if unix_convert failed. This means
6340 * that the path in 'mask' doesn't exist
6341 * on the file system and so we need to look
6342 * for a possible mangle. This patch from
6343 * Tine Smukavec <valentin.smukavec@hermes.si>.
6346 if (!VALID_STAT(smb_fname_src->st) &&
6347 mangle_is_mangled(fname_src_mask, conn->params)) {
6348 char *new_mask = NULL;
6349 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6350 conn->params);
6351 if (new_mask) {
6352 TALLOC_FREE(fname_src_mask);
6353 fname_src_mask = new_mask;
6357 if (!src_has_wild) {
6358 files_struct *fsp;
6361 * Only one file needs to be renamed. Append the mask back
6362 * onto the directory.
6364 TALLOC_FREE(smb_fname_src->base_name);
6365 if (ISDOT(fname_src_dir)) {
6366 /* Ensure we use canonical names on open. */
6367 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6368 "%s",
6369 fname_src_mask);
6370 } else {
6371 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6372 "%s/%s",
6373 fname_src_dir,
6374 fname_src_mask);
6376 if (!smb_fname_src->base_name) {
6377 status = NT_STATUS_NO_MEMORY;
6378 goto out;
6381 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6382 "case_preserve = %d, short case preserve = %d, "
6383 "directory = %s, newname = %s, "
6384 "last_component_dest = %s\n",
6385 conn->case_sensitive, conn->case_preserve,
6386 conn->short_case_preserve,
6387 smb_fname_str_dbg(smb_fname_src),
6388 smb_fname_str_dbg(smb_fname_dst),
6389 smb_fname_dst->original_lcomp));
6391 /* The dest name still may have wildcards. */
6392 if (dest_has_wild) {
6393 char *fname_dst_mod = NULL;
6394 if (!resolve_wildcards(smb_fname_dst,
6395 smb_fname_src->base_name,
6396 smb_fname_dst->base_name,
6397 &fname_dst_mod)) {
6398 DEBUG(6, ("rename_internals: resolve_wildcards "
6399 "%s %s failed\n",
6400 smb_fname_src->base_name,
6401 smb_fname_dst->base_name));
6402 status = NT_STATUS_NO_MEMORY;
6403 goto out;
6405 TALLOC_FREE(smb_fname_dst->base_name);
6406 smb_fname_dst->base_name = fname_dst_mod;
6409 ZERO_STRUCT(smb_fname_src->st);
6410 if (posix_pathnames) {
6411 SMB_VFS_LSTAT(conn, smb_fname_src);
6412 } else {
6413 SMB_VFS_STAT(conn, smb_fname_src);
6416 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6417 create_options |= FILE_DIRECTORY_FILE;
6420 status = SMB_VFS_CREATE_FILE(
6421 conn, /* conn */
6422 req, /* req */
6423 0, /* root_dir_fid */
6424 smb_fname_src, /* fname */
6425 access_mask, /* access_mask */
6426 (FILE_SHARE_READ | /* share_access */
6427 FILE_SHARE_WRITE),
6428 FILE_OPEN, /* create_disposition*/
6429 create_options, /* create_options */
6430 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6431 0, /* oplock_request */
6432 0, /* allocation_size */
6433 0, /* private_flags */
6434 NULL, /* sd */
6435 NULL, /* ea_list */
6436 &fsp, /* result */
6437 NULL); /* pinfo */
6439 if (!NT_STATUS_IS_OK(status)) {
6440 DEBUG(3, ("Could not open rename source %s: %s\n",
6441 smb_fname_str_dbg(smb_fname_src),
6442 nt_errstr(status)));
6443 goto out;
6446 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6447 attrs, replace_if_exists);
6449 close_file(req, fsp, NORMAL_CLOSE);
6451 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
6452 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
6453 smb_fname_str_dbg(smb_fname_dst)));
6455 goto out;
6459 * Wildcards - process each file that matches.
6461 if (strequal(fname_src_mask, "????????.???")) {
6462 TALLOC_FREE(fname_src_mask);
6463 fname_src_mask = talloc_strdup(ctx, "*");
6464 if (!fname_src_mask) {
6465 status = NT_STATUS_NO_MEMORY;
6466 goto out;
6470 status = check_name(conn, fname_src_dir);
6471 if (!NT_STATUS_IS_OK(status)) {
6472 goto out;
6475 dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask,
6476 attrs);
6477 if (dir_hnd == NULL) {
6478 status = map_nt_error_from_unix(errno);
6479 goto out;
6482 status = NT_STATUS_NO_SUCH_FILE;
6484 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
6485 * - gentest fix. JRA
6488 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
6489 &talloced))) {
6490 files_struct *fsp = NULL;
6491 char *destname = NULL;
6492 bool sysdir_entry = False;
6494 /* Quick check for "." and ".." */
6495 if (ISDOT(dname) || ISDOTDOT(dname)) {
6496 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
6497 sysdir_entry = True;
6498 } else {
6499 TALLOC_FREE(talloced);
6500 continue;
6504 if (!is_visible_file(conn, fname_src_dir, dname,
6505 &smb_fname_src->st, false)) {
6506 TALLOC_FREE(talloced);
6507 continue;
6510 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
6511 TALLOC_FREE(talloced);
6512 continue;
6515 if (sysdir_entry) {
6516 status = NT_STATUS_OBJECT_NAME_INVALID;
6517 break;
6520 TALLOC_FREE(smb_fname_src->base_name);
6521 if (ISDOT(fname_src_dir)) {
6522 /* Ensure we use canonical names on open. */
6523 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6524 "%s",
6525 dname);
6526 } else {
6527 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6528 "%s/%s",
6529 fname_src_dir,
6530 dname);
6532 if (!smb_fname_src->base_name) {
6533 status = NT_STATUS_NO_MEMORY;
6534 goto out;
6537 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6538 smb_fname_dst->base_name,
6539 &destname)) {
6540 DEBUG(6, ("resolve_wildcards %s %s failed\n",
6541 smb_fname_src->base_name, destname));
6542 TALLOC_FREE(talloced);
6543 continue;
6545 if (!destname) {
6546 status = NT_STATUS_NO_MEMORY;
6547 goto out;
6550 TALLOC_FREE(smb_fname_dst->base_name);
6551 smb_fname_dst->base_name = destname;
6553 ZERO_STRUCT(smb_fname_src->st);
6554 if (posix_pathnames) {
6555 SMB_VFS_LSTAT(conn, smb_fname_src);
6556 } else {
6557 SMB_VFS_STAT(conn, smb_fname_src);
6560 create_options = 0;
6562 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6563 create_options |= FILE_DIRECTORY_FILE;
6566 status = SMB_VFS_CREATE_FILE(
6567 conn, /* conn */
6568 req, /* req */
6569 0, /* root_dir_fid */
6570 smb_fname_src, /* fname */
6571 access_mask, /* access_mask */
6572 (FILE_SHARE_READ | /* share_access */
6573 FILE_SHARE_WRITE),
6574 FILE_OPEN, /* create_disposition*/
6575 create_options, /* create_options */
6576 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6577 0, /* oplock_request */
6578 0, /* allocation_size */
6579 0, /* private_flags */
6580 NULL, /* sd */
6581 NULL, /* ea_list */
6582 &fsp, /* result */
6583 NULL); /* pinfo */
6585 if (!NT_STATUS_IS_OK(status)) {
6586 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
6587 "returned %s rename %s -> %s\n",
6588 nt_errstr(status),
6589 smb_fname_str_dbg(smb_fname_src),
6590 smb_fname_str_dbg(smb_fname_dst)));
6591 break;
6594 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6595 dname);
6596 if (!smb_fname_dst->original_lcomp) {
6597 status = NT_STATUS_NO_MEMORY;
6598 goto out;
6601 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6602 attrs, replace_if_exists);
6604 close_file(req, fsp, NORMAL_CLOSE);
6606 if (!NT_STATUS_IS_OK(status)) {
6607 DEBUG(3, ("rename_internals_fsp returned %s for "
6608 "rename %s -> %s\n", nt_errstr(status),
6609 smb_fname_str_dbg(smb_fname_src),
6610 smb_fname_str_dbg(smb_fname_dst)));
6611 break;
6614 count++;
6616 DEBUG(3,("rename_internals: doing rename on %s -> "
6617 "%s\n", smb_fname_str_dbg(smb_fname_src),
6618 smb_fname_str_dbg(smb_fname_src)));
6619 TALLOC_FREE(talloced);
6621 TALLOC_FREE(dir_hnd);
6623 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
6624 status = map_nt_error_from_unix(errno);
6627 out:
6628 TALLOC_FREE(talloced);
6629 TALLOC_FREE(fname_src_dir);
6630 TALLOC_FREE(fname_src_mask);
6631 return status;
6634 /****************************************************************************
6635 Reply to a mv.
6636 ****************************************************************************/
6638 void reply_mv(struct smb_request *req)
6640 connection_struct *conn = req->conn;
6641 char *name = NULL;
6642 char *newname = NULL;
6643 const char *p;
6644 uint32 attrs;
6645 NTSTATUS status;
6646 bool src_has_wcard = False;
6647 bool dest_has_wcard = False;
6648 TALLOC_CTX *ctx = talloc_tos();
6649 struct smb_filename *smb_fname_src = NULL;
6650 struct smb_filename *smb_fname_dst = NULL;
6651 bool stream_rename = false;
6653 START_PROFILE(SMBmv);
6655 if (req->wct < 1) {
6656 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6657 goto out;
6660 attrs = SVAL(req->vwv+0, 0);
6662 p = (const char *)req->buf + 1;
6663 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
6664 &status, &src_has_wcard);
6665 if (!NT_STATUS_IS_OK(status)) {
6666 reply_nterror(req, status);
6667 goto out;
6669 p++;
6670 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
6671 &status, &dest_has_wcard);
6672 if (!NT_STATUS_IS_OK(status)) {
6673 reply_nterror(req, status);
6674 goto out;
6677 if (!lp_posix_pathnames()) {
6678 /* The newname must begin with a ':' if the
6679 name contains a ':'. */
6680 if (strchr_m(name, ':')) {
6681 if (newname[0] != ':') {
6682 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6683 goto out;
6685 stream_rename = true;
6689 status = filename_convert(ctx,
6690 conn,
6691 req->flags2 & FLAGS2_DFS_PATHNAMES,
6692 name,
6693 UCF_COND_ALLOW_WCARD_LCOMP,
6694 &src_has_wcard,
6695 &smb_fname_src);
6697 if (!NT_STATUS_IS_OK(status)) {
6698 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6699 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6700 ERRSRV, ERRbadpath);
6701 goto out;
6703 reply_nterror(req, status);
6704 goto out;
6707 status = filename_convert(ctx,
6708 conn,
6709 req->flags2 & FLAGS2_DFS_PATHNAMES,
6710 newname,
6711 UCF_COND_ALLOW_WCARD_LCOMP | UCF_SAVE_LCOMP,
6712 &dest_has_wcard,
6713 &smb_fname_dst);
6715 if (!NT_STATUS_IS_OK(status)) {
6716 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6717 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6718 ERRSRV, ERRbadpath);
6719 goto out;
6721 reply_nterror(req, status);
6722 goto out;
6725 if (stream_rename) {
6726 /* smb_fname_dst->base_name must be the same as
6727 smb_fname_src->base_name. */
6728 TALLOC_FREE(smb_fname_dst->base_name);
6729 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
6730 smb_fname_src->base_name);
6731 if (!smb_fname_dst->base_name) {
6732 reply_nterror(req, NT_STATUS_NO_MEMORY);
6733 goto out;
6737 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
6738 smb_fname_str_dbg(smb_fname_dst)));
6740 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
6741 attrs, False, src_has_wcard, dest_has_wcard,
6742 DELETE_ACCESS);
6743 if (!NT_STATUS_IS_OK(status)) {
6744 if (open_was_deferred(req->sconn, req->mid)) {
6745 /* We have re-scheduled this call. */
6746 goto out;
6748 reply_nterror(req, status);
6749 goto out;
6752 reply_outbuf(req, 0, 0);
6753 out:
6754 TALLOC_FREE(smb_fname_src);
6755 TALLOC_FREE(smb_fname_dst);
6756 END_PROFILE(SMBmv);
6757 return;
6760 /*******************************************************************
6761 Copy a file as part of a reply_copy.
6762 ******************************************************************/
6765 * TODO: check error codes on all callers
6768 NTSTATUS copy_file(TALLOC_CTX *ctx,
6769 connection_struct *conn,
6770 struct smb_filename *smb_fname_src,
6771 struct smb_filename *smb_fname_dst,
6772 int ofun,
6773 int count,
6774 bool target_is_directory)
6776 struct smb_filename *smb_fname_dst_tmp = NULL;
6777 SMB_OFF_T ret=-1;
6778 files_struct *fsp1,*fsp2;
6779 uint32 dosattrs;
6780 uint32 new_create_disposition;
6781 NTSTATUS status;
6784 status = copy_smb_filename(ctx, smb_fname_dst, &smb_fname_dst_tmp);
6785 if (!NT_STATUS_IS_OK(status)) {
6786 return status;
6790 * If the target is a directory, extract the last component from the
6791 * src filename and append it to the dst filename
6793 if (target_is_directory) {
6794 const char *p;
6796 /* dest/target can't be a stream if it's a directory. */
6797 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
6799 p = strrchr_m(smb_fname_src->base_name,'/');
6800 if (p) {
6801 p++;
6802 } else {
6803 p = smb_fname_src->base_name;
6805 smb_fname_dst_tmp->base_name =
6806 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
6808 if (!smb_fname_dst_tmp->base_name) {
6809 status = NT_STATUS_NO_MEMORY;
6810 goto out;
6814 status = vfs_file_exist(conn, smb_fname_src);
6815 if (!NT_STATUS_IS_OK(status)) {
6816 goto out;
6819 if (!target_is_directory && count) {
6820 new_create_disposition = FILE_OPEN;
6821 } else {
6822 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
6823 0, ofun,
6824 NULL, NULL,
6825 &new_create_disposition,
6826 NULL,
6827 NULL)) {
6828 status = NT_STATUS_INVALID_PARAMETER;
6829 goto out;
6833 /* Open the src file for reading. */
6834 status = SMB_VFS_CREATE_FILE(
6835 conn, /* conn */
6836 NULL, /* req */
6837 0, /* root_dir_fid */
6838 smb_fname_src, /* fname */
6839 FILE_GENERIC_READ, /* access_mask */
6840 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6841 FILE_OPEN, /* create_disposition*/
6842 0, /* create_options */
6843 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
6844 INTERNAL_OPEN_ONLY, /* oplock_request */
6845 0, /* allocation_size */
6846 0, /* private_flags */
6847 NULL, /* sd */
6848 NULL, /* ea_list */
6849 &fsp1, /* result */
6850 NULL); /* psbuf */
6852 if (!NT_STATUS_IS_OK(status)) {
6853 goto out;
6856 dosattrs = dos_mode(conn, smb_fname_src);
6858 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
6859 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
6862 /* Open the dst file for writing. */
6863 status = SMB_VFS_CREATE_FILE(
6864 conn, /* conn */
6865 NULL, /* req */
6866 0, /* root_dir_fid */
6867 smb_fname_dst, /* fname */
6868 FILE_GENERIC_WRITE, /* access_mask */
6869 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6870 new_create_disposition, /* create_disposition*/
6871 0, /* create_options */
6872 dosattrs, /* file_attributes */
6873 INTERNAL_OPEN_ONLY, /* oplock_request */
6874 0, /* allocation_size */
6875 0, /* private_flags */
6876 NULL, /* sd */
6877 NULL, /* ea_list */
6878 &fsp2, /* result */
6879 NULL); /* psbuf */
6881 if (!NT_STATUS_IS_OK(status)) {
6882 close_file(NULL, fsp1, ERROR_CLOSE);
6883 goto out;
6886 if (ofun & OPENX_FILE_EXISTS_OPEN) {
6887 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
6888 if (ret == -1) {
6889 DEBUG(0, ("error - vfs lseek returned error %s\n",
6890 strerror(errno)));
6891 status = map_nt_error_from_unix(errno);
6892 close_file(NULL, fsp1, ERROR_CLOSE);
6893 close_file(NULL, fsp2, ERROR_CLOSE);
6894 goto out;
6898 /* Do the actual copy. */
6899 if (smb_fname_src->st.st_ex_size) {
6900 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
6901 } else {
6902 ret = 0;
6905 close_file(NULL, fsp1, NORMAL_CLOSE);
6907 /* Ensure the modtime is set correctly on the destination file. */
6908 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
6911 * As we are opening fsp1 read-only we only expect
6912 * an error on close on fsp2 if we are out of space.
6913 * Thus we don't look at the error return from the
6914 * close of fsp1.
6916 status = close_file(NULL, fsp2, NORMAL_CLOSE);
6918 if (!NT_STATUS_IS_OK(status)) {
6919 goto out;
6922 if (ret != (SMB_OFF_T)smb_fname_src->st.st_ex_size) {
6923 status = NT_STATUS_DISK_FULL;
6924 goto out;
6927 status = NT_STATUS_OK;
6929 out:
6930 TALLOC_FREE(smb_fname_dst_tmp);
6931 return status;
6934 /****************************************************************************
6935 Reply to a file copy.
6936 ****************************************************************************/
6938 void reply_copy(struct smb_request *req)
6940 connection_struct *conn = req->conn;
6941 struct smb_filename *smb_fname_src = NULL;
6942 struct smb_filename *smb_fname_dst = NULL;
6943 char *fname_src = NULL;
6944 char *fname_dst = NULL;
6945 char *fname_src_mask = NULL;
6946 char *fname_src_dir = NULL;
6947 const char *p;
6948 int count=0;
6949 int error = ERRnoaccess;
6950 int tid2;
6951 int ofun;
6952 int flags;
6953 bool target_is_directory=False;
6954 bool source_has_wild = False;
6955 bool dest_has_wild = False;
6956 NTSTATUS status;
6957 TALLOC_CTX *ctx = talloc_tos();
6959 START_PROFILE(SMBcopy);
6961 if (req->wct < 3) {
6962 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6963 goto out;
6966 tid2 = SVAL(req->vwv+0, 0);
6967 ofun = SVAL(req->vwv+1, 0);
6968 flags = SVAL(req->vwv+2, 0);
6970 p = (const char *)req->buf;
6971 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
6972 &status, &source_has_wild);
6973 if (!NT_STATUS_IS_OK(status)) {
6974 reply_nterror(req, status);
6975 goto out;
6977 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
6978 &status, &dest_has_wild);
6979 if (!NT_STATUS_IS_OK(status)) {
6980 reply_nterror(req, status);
6981 goto out;
6984 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
6986 if (tid2 != conn->cnum) {
6987 /* can't currently handle inter share copies XXXX */
6988 DEBUG(3,("Rejecting inter-share copy\n"));
6989 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
6990 goto out;
6993 status = filename_convert(ctx, conn,
6994 req->flags2 & FLAGS2_DFS_PATHNAMES,
6995 fname_src,
6996 UCF_COND_ALLOW_WCARD_LCOMP,
6997 &source_has_wild,
6998 &smb_fname_src);
6999 if (!NT_STATUS_IS_OK(status)) {
7000 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7001 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7002 ERRSRV, ERRbadpath);
7003 goto out;
7005 reply_nterror(req, status);
7006 goto out;
7009 status = filename_convert(ctx, conn,
7010 req->flags2 & FLAGS2_DFS_PATHNAMES,
7011 fname_dst,
7012 UCF_COND_ALLOW_WCARD_LCOMP,
7013 &dest_has_wild,
7014 &smb_fname_dst);
7015 if (!NT_STATUS_IS_OK(status)) {
7016 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7017 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7018 ERRSRV, ERRbadpath);
7019 goto out;
7021 reply_nterror(req, status);
7022 goto out;
7025 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
7027 if ((flags&1) && target_is_directory) {
7028 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
7029 goto out;
7032 if ((flags&2) && !target_is_directory) {
7033 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
7034 goto out;
7037 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
7038 /* wants a tree copy! XXXX */
7039 DEBUG(3,("Rejecting tree copy\n"));
7040 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7041 goto out;
7044 /* Split up the directory from the filename/mask. */
7045 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7046 &fname_src_dir, &fname_src_mask);
7047 if (!NT_STATUS_IS_OK(status)) {
7048 reply_nterror(req, NT_STATUS_NO_MEMORY);
7049 goto out;
7053 * We should only check the mangled cache
7054 * here if unix_convert failed. This means
7055 * that the path in 'mask' doesn't exist
7056 * on the file system and so we need to look
7057 * for a possible mangle. This patch from
7058 * Tine Smukavec <valentin.smukavec@hermes.si>.
7060 if (!VALID_STAT(smb_fname_src->st) &&
7061 mangle_is_mangled(fname_src_mask, conn->params)) {
7062 char *new_mask = NULL;
7063 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
7064 &new_mask, conn->params);
7066 /* Use demangled name if one was successfully found. */
7067 if (new_mask) {
7068 TALLOC_FREE(fname_src_mask);
7069 fname_src_mask = new_mask;
7073 if (!source_has_wild) {
7076 * Only one file needs to be copied. Append the mask back onto
7077 * the directory.
7079 TALLOC_FREE(smb_fname_src->base_name);
7080 if (ISDOT(fname_src_dir)) {
7081 /* Ensure we use canonical names on open. */
7082 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7083 "%s",
7084 fname_src_mask);
7085 } else {
7086 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7087 "%s/%s",
7088 fname_src_dir,
7089 fname_src_mask);
7091 if (!smb_fname_src->base_name) {
7092 reply_nterror(req, NT_STATUS_NO_MEMORY);
7093 goto out;
7096 if (dest_has_wild) {
7097 char *fname_dst_mod = NULL;
7098 if (!resolve_wildcards(smb_fname_dst,
7099 smb_fname_src->base_name,
7100 smb_fname_dst->base_name,
7101 &fname_dst_mod)) {
7102 reply_nterror(req, NT_STATUS_NO_MEMORY);
7103 goto out;
7105 TALLOC_FREE(smb_fname_dst->base_name);
7106 smb_fname_dst->base_name = fname_dst_mod;
7109 status = check_name(conn, smb_fname_src->base_name);
7110 if (!NT_STATUS_IS_OK(status)) {
7111 reply_nterror(req, status);
7112 goto out;
7115 status = check_name(conn, smb_fname_dst->base_name);
7116 if (!NT_STATUS_IS_OK(status)) {
7117 reply_nterror(req, status);
7118 goto out;
7121 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7122 ofun, count, target_is_directory);
7124 if(!NT_STATUS_IS_OK(status)) {
7125 reply_nterror(req, status);
7126 goto out;
7127 } else {
7128 count++;
7130 } else {
7131 struct smb_Dir *dir_hnd = NULL;
7132 const char *dname = NULL;
7133 char *talloced = NULL;
7134 long offset = 0;
7137 * There is a wildcard that requires us to actually read the
7138 * src dir and copy each file matching the mask to the dst.
7139 * Right now streams won't be copied, but this could
7140 * presumably be added with a nested loop for reach dir entry.
7142 SMB_ASSERT(!smb_fname_src->stream_name);
7143 SMB_ASSERT(!smb_fname_dst->stream_name);
7145 smb_fname_src->stream_name = NULL;
7146 smb_fname_dst->stream_name = NULL;
7148 if (strequal(fname_src_mask,"????????.???")) {
7149 TALLOC_FREE(fname_src_mask);
7150 fname_src_mask = talloc_strdup(ctx, "*");
7151 if (!fname_src_mask) {
7152 reply_nterror(req, NT_STATUS_NO_MEMORY);
7153 goto out;
7157 status = check_name(conn, fname_src_dir);
7158 if (!NT_STATUS_IS_OK(status)) {
7159 reply_nterror(req, status);
7160 goto out;
7163 dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0);
7164 if (dir_hnd == NULL) {
7165 status = map_nt_error_from_unix(errno);
7166 reply_nterror(req, status);
7167 goto out;
7170 error = ERRbadfile;
7172 /* Iterate over the src dir copying each entry to the dst. */
7173 while ((dname = ReadDirName(dir_hnd, &offset,
7174 &smb_fname_src->st, &talloced))) {
7175 char *destname = NULL;
7177 if (ISDOT(dname) || ISDOTDOT(dname)) {
7178 TALLOC_FREE(talloced);
7179 continue;
7182 if (!is_visible_file(conn, fname_src_dir, dname,
7183 &smb_fname_src->st, false)) {
7184 TALLOC_FREE(talloced);
7185 continue;
7188 if(!mask_match(dname, fname_src_mask,
7189 conn->case_sensitive)) {
7190 TALLOC_FREE(talloced);
7191 continue;
7194 error = ERRnoaccess;
7196 /* Get the src smb_fname struct setup. */
7197 TALLOC_FREE(smb_fname_src->base_name);
7198 if (ISDOT(fname_src_dir)) {
7199 /* Ensure we use canonical names on open. */
7200 smb_fname_src->base_name =
7201 talloc_asprintf(smb_fname_src, "%s",
7202 dname);
7203 } else {
7204 smb_fname_src->base_name =
7205 talloc_asprintf(smb_fname_src, "%s/%s",
7206 fname_src_dir, dname);
7209 if (!smb_fname_src->base_name) {
7210 TALLOC_FREE(dir_hnd);
7211 TALLOC_FREE(talloced);
7212 reply_nterror(req, NT_STATUS_NO_MEMORY);
7213 goto out;
7216 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7217 smb_fname_dst->base_name,
7218 &destname)) {
7219 TALLOC_FREE(talloced);
7220 continue;
7222 if (!destname) {
7223 TALLOC_FREE(dir_hnd);
7224 TALLOC_FREE(talloced);
7225 reply_nterror(req, NT_STATUS_NO_MEMORY);
7226 goto out;
7229 TALLOC_FREE(smb_fname_dst->base_name);
7230 smb_fname_dst->base_name = destname;
7232 status = check_name(conn, smb_fname_src->base_name);
7233 if (!NT_STATUS_IS_OK(status)) {
7234 TALLOC_FREE(dir_hnd);
7235 TALLOC_FREE(talloced);
7236 reply_nterror(req, status);
7237 goto out;
7240 status = check_name(conn, smb_fname_dst->base_name);
7241 if (!NT_STATUS_IS_OK(status)) {
7242 TALLOC_FREE(dir_hnd);
7243 TALLOC_FREE(talloced);
7244 reply_nterror(req, status);
7245 goto out;
7248 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7249 smb_fname_src->base_name,
7250 smb_fname_dst->base_name));
7252 status = copy_file(ctx, conn, smb_fname_src,
7253 smb_fname_dst, ofun, count,
7254 target_is_directory);
7255 if (NT_STATUS_IS_OK(status)) {
7256 count++;
7259 TALLOC_FREE(talloced);
7261 TALLOC_FREE(dir_hnd);
7264 if (count == 0) {
7265 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7266 goto out;
7269 reply_outbuf(req, 1, 0);
7270 SSVAL(req->outbuf,smb_vwv0,count);
7271 out:
7272 TALLOC_FREE(smb_fname_src);
7273 TALLOC_FREE(smb_fname_dst);
7274 TALLOC_FREE(fname_src);
7275 TALLOC_FREE(fname_dst);
7276 TALLOC_FREE(fname_src_mask);
7277 TALLOC_FREE(fname_src_dir);
7279 END_PROFILE(SMBcopy);
7280 return;
7283 #undef DBGC_CLASS
7284 #define DBGC_CLASS DBGC_LOCKING
7286 /****************************************************************************
7287 Get a lock pid, dealing with large count requests.
7288 ****************************************************************************/
7290 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7291 bool large_file_format)
7293 if(!large_file_format)
7294 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7295 else
7296 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7299 /****************************************************************************
7300 Get a lock count, dealing with large count requests.
7301 ****************************************************************************/
7303 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7304 bool large_file_format)
7306 uint64_t count = 0;
7308 if(!large_file_format) {
7309 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7310 } else {
7312 #if defined(HAVE_LONGLONG)
7313 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7314 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7315 #else /* HAVE_LONGLONG */
7318 * NT4.x seems to be broken in that it sends large file (64 bit)
7319 * lockingX calls even if the CAP_LARGE_FILES was *not*
7320 * negotiated. For boxes without large unsigned ints truncate the
7321 * lock count by dropping the top 32 bits.
7324 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
7325 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
7326 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
7327 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
7328 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
7331 count = (uint64_t)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
7332 #endif /* HAVE_LONGLONG */
7335 return count;
7338 #if !defined(HAVE_LONGLONG)
7339 /****************************************************************************
7340 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
7341 ****************************************************************************/
7343 static uint32 map_lock_offset(uint32 high, uint32 low)
7345 unsigned int i;
7346 uint32 mask = 0;
7347 uint32 highcopy = high;
7350 * Try and find out how many significant bits there are in high.
7353 for(i = 0; highcopy; i++)
7354 highcopy >>= 1;
7357 * We use 31 bits not 32 here as POSIX
7358 * lock offsets may not be negative.
7361 mask = (~0) << (31 - i);
7363 if(low & mask)
7364 return 0; /* Fail. */
7366 high <<= (31 - i);
7368 return (high|low);
7370 #endif /* !defined(HAVE_LONGLONG) */
7372 /****************************************************************************
7373 Get a lock offset, dealing with large offset requests.
7374 ****************************************************************************/
7376 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7377 bool large_file_format, bool *err)
7379 uint64_t offset = 0;
7381 *err = False;
7383 if(!large_file_format) {
7384 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7385 } else {
7387 #if defined(HAVE_LONGLONG)
7388 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7389 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7390 #else /* HAVE_LONGLONG */
7393 * NT4.x seems to be broken in that it sends large file (64 bit)
7394 * lockingX calls even if the CAP_LARGE_FILES was *not*
7395 * negotiated. For boxes without large unsigned ints mangle the
7396 * lock offset by mapping the top 32 bits onto the lower 32.
7399 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
7400 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7401 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
7402 uint32 new_low = 0;
7404 if((new_low = map_lock_offset(high, low)) == 0) {
7405 *err = True;
7406 return (uint64_t)-1;
7409 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
7410 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
7411 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
7412 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
7415 offset = (uint64_t)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7416 #endif /* HAVE_LONGLONG */
7419 return offset;
7422 NTSTATUS smbd_do_locking(struct smb_request *req,
7423 files_struct *fsp,
7424 uint8_t type,
7425 int32_t timeout,
7426 uint16_t num_ulocks,
7427 struct smbd_lock_element *ulocks,
7428 uint16_t num_locks,
7429 struct smbd_lock_element *locks,
7430 bool *async)
7432 connection_struct *conn = req->conn;
7433 int i;
7434 NTSTATUS status = NT_STATUS_OK;
7436 *async = false;
7438 /* Data now points at the beginning of the list
7439 of smb_unlkrng structs */
7440 for(i = 0; i < (int)num_ulocks; i++) {
7441 struct smbd_lock_element *e = &ulocks[i];
7443 DEBUG(10,("smbd_do_locking: unlock start=%.0f, len=%.0f for "
7444 "pid %u, file %s\n",
7445 (double)e->offset,
7446 (double)e->count,
7447 (unsigned int)e->smblctx,
7448 fsp_str_dbg(fsp)));
7450 if (e->brltype != UNLOCK_LOCK) {
7451 /* this can only happen with SMB2 */
7452 return NT_STATUS_INVALID_PARAMETER;
7455 status = do_unlock(req->sconn->msg_ctx,
7456 fsp,
7457 e->smblctx,
7458 e->count,
7459 e->offset,
7460 WINDOWS_LOCK);
7462 DEBUG(10, ("smbd_do_locking: unlock returned %s\n",
7463 nt_errstr(status)));
7465 if (!NT_STATUS_IS_OK(status)) {
7466 return status;
7470 /* Setup the timeout in seconds. */
7472 if (!lp_blocking_locks(SNUM(conn))) {
7473 timeout = 0;
7476 /* Data now points at the beginning of the list
7477 of smb_lkrng structs */
7479 for(i = 0; i < (int)num_locks; i++) {
7480 struct smbd_lock_element *e = &locks[i];
7482 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
7483 "%llu, file %s timeout = %d\n",
7484 (double)e->offset,
7485 (double)e->count,
7486 (unsigned long long)e->smblctx,
7487 fsp_str_dbg(fsp),
7488 (int)timeout));
7490 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7491 struct blocking_lock_record *blr = NULL;
7493 if (num_locks > 1) {
7495 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
7496 * if the lock vector contains one entry. When given mutliple cancel
7497 * requests in a single PDU we expect the server to return an
7498 * error. Windows servers seem to accept the request but only
7499 * cancel the first lock.
7500 * JRA - Do what Windows does (tm) :-).
7503 #if 0
7504 /* MS-CIFS (2.2.4.32.1) behavior. */
7505 return NT_STATUS_DOS(ERRDOS,
7506 ERRcancelviolation);
7507 #else
7508 /* Windows behavior. */
7509 if (i != 0) {
7510 DEBUG(10,("smbd_do_locking: ignoring subsequent "
7511 "cancel request\n"));
7512 continue;
7514 #endif
7517 if (lp_blocking_locks(SNUM(conn))) {
7519 /* Schedule a message to ourselves to
7520 remove the blocking lock record and
7521 return the right error. */
7523 blr = blocking_lock_cancel_smb1(fsp,
7524 e->smblctx,
7525 e->offset,
7526 e->count,
7527 WINDOWS_LOCK,
7528 type,
7529 NT_STATUS_FILE_LOCK_CONFLICT);
7530 if (blr == NULL) {
7531 return NT_STATUS_DOS(
7532 ERRDOS,
7533 ERRcancelviolation);
7536 /* Remove a matching pending lock. */
7537 status = do_lock_cancel(fsp,
7538 e->smblctx,
7539 e->count,
7540 e->offset,
7541 WINDOWS_LOCK,
7542 blr);
7543 } else {
7544 bool blocking_lock = timeout ? true : false;
7545 bool defer_lock = false;
7546 struct byte_range_lock *br_lck;
7547 uint64_t block_smblctx;
7549 br_lck = do_lock(req->sconn->msg_ctx,
7550 fsp,
7551 e->smblctx,
7552 e->count,
7553 e->offset,
7554 e->brltype,
7555 WINDOWS_LOCK,
7556 blocking_lock,
7557 &status,
7558 &block_smblctx,
7559 NULL);
7561 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
7562 /* Windows internal resolution for blocking locks seems
7563 to be about 200ms... Don't wait for less than that. JRA. */
7564 if (timeout != -1 && timeout < lp_lock_spin_time()) {
7565 timeout = lp_lock_spin_time();
7567 defer_lock = true;
7570 /* If a lock sent with timeout of zero would fail, and
7571 * this lock has been requested multiple times,
7572 * according to brl_lock_failed() we convert this
7573 * request to a blocking lock with a timeout of between
7574 * 150 - 300 milliseconds.
7576 * If lp_lock_spin_time() has been set to 0, we skip
7577 * this blocking retry and fail immediately.
7579 * Replacement for do_lock_spin(). JRA. */
7581 if (!req->sconn->using_smb2 &&
7582 br_lck && lp_blocking_locks(SNUM(conn)) &&
7583 lp_lock_spin_time() && !blocking_lock &&
7584 NT_STATUS_EQUAL((status),
7585 NT_STATUS_FILE_LOCK_CONFLICT))
7587 defer_lock = true;
7588 timeout = lp_lock_spin_time();
7591 if (br_lck && defer_lock) {
7593 * A blocking lock was requested. Package up
7594 * this smb into a queued request and push it
7595 * onto the blocking lock queue.
7597 if(push_blocking_lock_request(br_lck,
7598 req,
7599 fsp,
7600 timeout,
7602 e->smblctx,
7603 e->brltype,
7604 WINDOWS_LOCK,
7605 e->offset,
7606 e->count,
7607 block_smblctx)) {
7608 TALLOC_FREE(br_lck);
7609 *async = true;
7610 return NT_STATUS_OK;
7614 TALLOC_FREE(br_lck);
7617 if (!NT_STATUS_IS_OK(status)) {
7618 break;
7622 /* If any of the above locks failed, then we must unlock
7623 all of the previous locks (X/Open spec). */
7625 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
7627 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7628 i = -1; /* we want to skip the for loop */
7632 * Ensure we don't do a remove on the lock that just failed,
7633 * as under POSIX rules, if we have a lock already there, we
7634 * will delete it (and we shouldn't) .....
7636 for(i--; i >= 0; i--) {
7637 struct smbd_lock_element *e = &locks[i];
7639 do_unlock(req->sconn->msg_ctx,
7640 fsp,
7641 e->smblctx,
7642 e->count,
7643 e->offset,
7644 WINDOWS_LOCK);
7646 return status;
7649 DEBUG(3, ("smbd_do_locking: fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
7650 fsp->fnum, (unsigned int)type, num_locks, num_ulocks));
7652 return NT_STATUS_OK;
7655 /****************************************************************************
7656 Reply to a lockingX request.
7657 ****************************************************************************/
7659 void reply_lockingX(struct smb_request *req)
7661 connection_struct *conn = req->conn;
7662 files_struct *fsp;
7663 unsigned char locktype;
7664 unsigned char oplocklevel;
7665 uint16 num_ulocks;
7666 uint16 num_locks;
7667 int32 lock_timeout;
7668 int i;
7669 const uint8_t *data;
7670 bool large_file_format;
7671 bool err;
7672 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
7673 struct smbd_lock_element *ulocks;
7674 struct smbd_lock_element *locks;
7675 bool async = false;
7677 START_PROFILE(SMBlockingX);
7679 if (req->wct < 8) {
7680 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7681 END_PROFILE(SMBlockingX);
7682 return;
7685 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
7686 locktype = CVAL(req->vwv+3, 0);
7687 oplocklevel = CVAL(req->vwv+3, 1);
7688 num_ulocks = SVAL(req->vwv+6, 0);
7689 num_locks = SVAL(req->vwv+7, 0);
7690 lock_timeout = IVAL(req->vwv+4, 0);
7691 large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
7693 if (!check_fsp(conn, req, fsp)) {
7694 END_PROFILE(SMBlockingX);
7695 return;
7698 data = req->buf;
7700 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
7701 /* we don't support these - and CANCEL_LOCK makes w2k
7702 and XP reboot so I don't really want to be
7703 compatible! (tridge) */
7704 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
7705 END_PROFILE(SMBlockingX);
7706 return;
7709 /* Check if this is an oplock break on a file
7710 we have granted an oplock on.
7712 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
7713 /* Client can insist on breaking to none. */
7714 bool break_to_none = (oplocklevel == 0);
7715 bool result;
7717 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
7718 "for fnum = %d\n", (unsigned int)oplocklevel,
7719 fsp->fnum ));
7722 * Make sure we have granted an exclusive or batch oplock on
7723 * this file.
7726 if (fsp->oplock_type == 0) {
7728 /* The Samba4 nbench simulator doesn't understand
7729 the difference between break to level2 and break
7730 to none from level2 - it sends oplock break
7731 replies in both cases. Don't keep logging an error
7732 message here - just ignore it. JRA. */
7734 DEBUG(5,("reply_lockingX: Error : oplock break from "
7735 "client for fnum = %d (oplock=%d) and no "
7736 "oplock granted on this file (%s).\n",
7737 fsp->fnum, fsp->oplock_type,
7738 fsp_str_dbg(fsp)));
7740 /* if this is a pure oplock break request then don't
7741 * send a reply */
7742 if (num_locks == 0 && num_ulocks == 0) {
7743 END_PROFILE(SMBlockingX);
7744 return;
7745 } else {
7746 END_PROFILE(SMBlockingX);
7747 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
7748 return;
7752 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
7753 (break_to_none)) {
7754 result = remove_oplock(fsp);
7755 } else {
7756 result = downgrade_oplock(fsp);
7759 if (!result) {
7760 DEBUG(0, ("reply_lockingX: error in removing "
7761 "oplock on file %s\n", fsp_str_dbg(fsp)));
7762 /* Hmmm. Is this panic justified? */
7763 smb_panic("internal tdb error");
7766 reply_to_oplock_break_requests(fsp);
7768 /* if this is a pure oplock break request then don't send a
7769 * reply */
7770 if (num_locks == 0 && num_ulocks == 0) {
7771 /* Sanity check - ensure a pure oplock break is not a
7772 chained request. */
7773 if(CVAL(req->vwv+0, 0) != 0xff)
7774 DEBUG(0,("reply_lockingX: Error : pure oplock "
7775 "break is a chained %d request !\n",
7776 (unsigned int)CVAL(req->vwv+0, 0)));
7777 END_PROFILE(SMBlockingX);
7778 return;
7782 if (req->buflen <
7783 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
7784 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7785 END_PROFILE(SMBlockingX);
7786 return;
7789 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
7790 if (ulocks == NULL) {
7791 reply_nterror(req, NT_STATUS_NO_MEMORY);
7792 END_PROFILE(SMBlockingX);
7793 return;
7796 locks = talloc_array(req, struct smbd_lock_element, num_locks);
7797 if (locks == NULL) {
7798 reply_nterror(req, NT_STATUS_NO_MEMORY);
7799 END_PROFILE(SMBlockingX);
7800 return;
7803 /* Data now points at the beginning of the list
7804 of smb_unlkrng structs */
7805 for(i = 0; i < (int)num_ulocks; i++) {
7806 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
7807 ulocks[i].count = get_lock_count(data, i, large_file_format);
7808 ulocks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7809 ulocks[i].brltype = UNLOCK_LOCK;
7812 * There is no error code marked "stupid client bug".... :-).
7814 if(err) {
7815 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7816 END_PROFILE(SMBlockingX);
7817 return;
7821 /* Now do any requested locks */
7822 data += ((large_file_format ? 20 : 10)*num_ulocks);
7824 /* Data now points at the beginning of the list
7825 of smb_lkrng structs */
7827 for(i = 0; i < (int)num_locks; i++) {
7828 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
7829 locks[i].count = get_lock_count(data, i, large_file_format);
7830 locks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7832 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
7833 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7834 locks[i].brltype = PENDING_READ_LOCK;
7835 } else {
7836 locks[i].brltype = READ_LOCK;
7838 } else {
7839 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7840 locks[i].brltype = PENDING_WRITE_LOCK;
7841 } else {
7842 locks[i].brltype = WRITE_LOCK;
7847 * There is no error code marked "stupid client bug".... :-).
7849 if(err) {
7850 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7851 END_PROFILE(SMBlockingX);
7852 return;
7856 status = smbd_do_locking(req, fsp,
7857 locktype, lock_timeout,
7858 num_ulocks, ulocks,
7859 num_locks, locks,
7860 &async);
7861 if (!NT_STATUS_IS_OK(status)) {
7862 END_PROFILE(SMBlockingX);
7863 reply_nterror(req, status);
7864 return;
7866 if (async) {
7867 END_PROFILE(SMBlockingX);
7868 return;
7871 reply_outbuf(req, 2, 0);
7873 DEBUG(3, ("lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
7874 fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks));
7876 END_PROFILE(SMBlockingX);
7877 chain_reply(req);
7880 #undef DBGC_CLASS
7881 #define DBGC_CLASS DBGC_ALL
7883 /****************************************************************************
7884 Reply to a SMBreadbmpx (read block multiplex) request.
7885 Always reply with an error, if someone has a platform really needs this,
7886 please contact vl@samba.org
7887 ****************************************************************************/
7889 void reply_readbmpx(struct smb_request *req)
7891 START_PROFILE(SMBreadBmpx);
7892 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7893 END_PROFILE(SMBreadBmpx);
7894 return;
7897 /****************************************************************************
7898 Reply to a SMBreadbs (read block multiplex secondary) request.
7899 Always reply with an error, if someone has a platform really needs this,
7900 please contact vl@samba.org
7901 ****************************************************************************/
7903 void reply_readbs(struct smb_request *req)
7905 START_PROFILE(SMBreadBs);
7906 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7907 END_PROFILE(SMBreadBs);
7908 return;
7911 /****************************************************************************
7912 Reply to a SMBsetattrE.
7913 ****************************************************************************/
7915 void reply_setattrE(struct smb_request *req)
7917 connection_struct *conn = req->conn;
7918 struct smb_file_time ft;
7919 files_struct *fsp;
7920 NTSTATUS status;
7922 START_PROFILE(SMBsetattrE);
7923 ZERO_STRUCT(ft);
7925 if (req->wct < 7) {
7926 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7927 goto out;
7930 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
7932 if(!fsp || (fsp->conn != conn)) {
7933 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
7934 goto out;
7938 * Convert the DOS times into unix times.
7941 ft.atime = convert_time_t_to_timespec(
7942 srv_make_unix_date2(req->vwv+3));
7943 ft.mtime = convert_time_t_to_timespec(
7944 srv_make_unix_date2(req->vwv+5));
7945 ft.create_time = convert_time_t_to_timespec(
7946 srv_make_unix_date2(req->vwv+1));
7948 reply_outbuf(req, 0, 0);
7951 * Patch from Ray Frush <frush@engr.colostate.edu>
7952 * Sometimes times are sent as zero - ignore them.
7955 /* Ensure we have a valid stat struct for the source. */
7956 status = vfs_stat_fsp(fsp);
7957 if (!NT_STATUS_IS_OK(status)) {
7958 reply_nterror(req, status);
7959 goto out;
7962 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
7963 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7964 goto out;
7967 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
7968 if (!NT_STATUS_IS_OK(status)) {
7969 reply_nterror(req, status);
7970 goto out;
7973 DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u "
7974 " createtime=%u\n",
7975 fsp->fnum,
7976 (unsigned int)ft.atime.tv_sec,
7977 (unsigned int)ft.mtime.tv_sec,
7978 (unsigned int)ft.create_time.tv_sec
7980 out:
7981 END_PROFILE(SMBsetattrE);
7982 return;
7986 /* Back from the dead for OS/2..... JRA. */
7988 /****************************************************************************
7989 Reply to a SMBwritebmpx (write block multiplex primary) request.
7990 Always reply with an error, if someone has a platform really needs this,
7991 please contact vl@samba.org
7992 ****************************************************************************/
7994 void reply_writebmpx(struct smb_request *req)
7996 START_PROFILE(SMBwriteBmpx);
7997 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7998 END_PROFILE(SMBwriteBmpx);
7999 return;
8002 /****************************************************************************
8003 Reply to a SMBwritebs (write block multiplex secondary) request.
8004 Always reply with an error, if someone has a platform really needs this,
8005 please contact vl@samba.org
8006 ****************************************************************************/
8008 void reply_writebs(struct smb_request *req)
8010 START_PROFILE(SMBwriteBs);
8011 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8012 END_PROFILE(SMBwriteBs);
8013 return;
8016 /****************************************************************************
8017 Reply to a SMBgetattrE.
8018 ****************************************************************************/
8020 void reply_getattrE(struct smb_request *req)
8022 connection_struct *conn = req->conn;
8023 int mode;
8024 files_struct *fsp;
8025 struct timespec create_ts;
8027 START_PROFILE(SMBgetattrE);
8029 if (req->wct < 1) {
8030 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8031 END_PROFILE(SMBgetattrE);
8032 return;
8035 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8037 if(!fsp || (fsp->conn != conn)) {
8038 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8039 END_PROFILE(SMBgetattrE);
8040 return;
8043 /* Do an fstat on this file */
8044 if(fsp_stat(fsp)) {
8045 reply_nterror(req, map_nt_error_from_unix(errno));
8046 END_PROFILE(SMBgetattrE);
8047 return;
8050 mode = dos_mode(conn, fsp->fsp_name);
8053 * Convert the times into dos times. Set create
8054 * date to be last modify date as UNIX doesn't save
8055 * this.
8058 reply_outbuf(req, 11, 0);
8060 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
8061 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
8062 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
8063 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
8064 /* Should we check pending modtime here ? JRA */
8065 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
8066 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
8068 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
8069 SIVAL(req->outbuf, smb_vwv6, 0);
8070 SIVAL(req->outbuf, smb_vwv8, 0);
8071 } else {
8072 uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8073 SIVAL(req->outbuf, smb_vwv6, (uint32)fsp->fsp_name->st.st_ex_size);
8074 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8076 SSVAL(req->outbuf,smb_vwv10, mode);
8078 DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
8080 END_PROFILE(SMBgetattrE);
8081 return;