Fix bug 9811 - Old DOS SMB CTEMP request uses a non-VFS function to access the filesy...
[Samba.git] / source3 / smbd / reply.c
blobca3a08f87236749e69d0d8632383d85f8e1e5a16
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"
43 /****************************************************************************
44 Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
45 path or anything including wildcards.
46 We're assuming here that '/' is not the second byte in any multibyte char
47 set (a safe assumption). '\\' *may* be the second byte in a multibyte char
48 set.
49 ****************************************************************************/
51 /* Custom version for processing POSIX paths. */
52 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
54 static NTSTATUS check_path_syntax_internal(char *path,
55 bool posix_path,
56 bool *p_last_component_contains_wcard)
58 char *d = path;
59 const char *s = path;
60 NTSTATUS ret = NT_STATUS_OK;
61 bool start_of_name_component = True;
62 bool stream_started = false;
64 *p_last_component_contains_wcard = False;
66 while (*s) {
67 if (stream_started) {
68 switch (*s) {
69 case '/':
70 case '\\':
71 return NT_STATUS_OBJECT_NAME_INVALID;
72 case ':':
73 if (s[1] == '\0') {
74 return NT_STATUS_OBJECT_NAME_INVALID;
76 if (strchr_m(&s[1], ':')) {
77 return NT_STATUS_OBJECT_NAME_INVALID;
79 break;
83 if ((*s == ':') && !posix_path && !stream_started) {
84 if (*p_last_component_contains_wcard) {
85 return NT_STATUS_OBJECT_NAME_INVALID;
87 /* Stream names allow more characters than file names.
88 We're overloading posix_path here to allow a wider
89 range of characters. If stream_started is true this
90 is still a Windows path even if posix_path is true.
91 JRA.
93 stream_started = true;
94 start_of_name_component = false;
95 posix_path = true;
97 if (s[1] == '\0') {
98 return NT_STATUS_OBJECT_NAME_INVALID;
102 if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
104 * Safe to assume is not the second part of a mb char
105 * as this is handled below.
107 /* Eat multiple '/' or '\\' */
108 while (IS_PATH_SEP(*s,posix_path)) {
109 s++;
111 if ((d != path) && (*s != '\0')) {
112 /* We only care about non-leading or trailing '/' or '\\' */
113 *d++ = '/';
116 start_of_name_component = True;
117 /* New component. */
118 *p_last_component_contains_wcard = False;
119 continue;
122 if (start_of_name_component) {
123 if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
124 /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
127 * No mb char starts with '.' so we're safe checking the directory separator here.
130 /* If we just added a '/' - delete it */
131 if ((d > path) && (*(d-1) == '/')) {
132 *(d-1) = '\0';
133 d--;
136 /* Are we at the start ? Can't go back further if so. */
137 if (d <= path) {
138 ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
139 break;
141 /* Go back one level... */
142 /* We know this is safe as '/' cannot be part of a mb sequence. */
143 /* NOTE - if this assumption is invalid we are not in good shape... */
144 /* Decrement d first as d points to the *next* char to write into. */
145 for (d--; d > path; d--) {
146 if (*d == '/')
147 break;
149 s += 2; /* Else go past the .. */
150 /* We're still at the start of a name component, just the previous one. */
151 continue;
153 } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
154 if (posix_path) {
155 /* Eat the '.' */
156 s++;
157 continue;
163 if (!(*s & 0x80)) {
164 if (!posix_path) {
165 if (*s <= 0x1f || *s == '|') {
166 return NT_STATUS_OBJECT_NAME_INVALID;
168 switch (*s) {
169 case '*':
170 case '?':
171 case '<':
172 case '>':
173 case '"':
174 *p_last_component_contains_wcard = True;
175 break;
176 default:
177 break;
180 *d++ = *s++;
181 } else {
182 size_t siz;
183 /* Get the size of the next MB character. */
184 next_codepoint(s,&siz);
185 switch(siz) {
186 case 5:
187 *d++ = *s++;
188 /*fall through*/
189 case 4:
190 *d++ = *s++;
191 /*fall through*/
192 case 3:
193 *d++ = *s++;
194 /*fall through*/
195 case 2:
196 *d++ = *s++;
197 /*fall through*/
198 case 1:
199 *d++ = *s++;
200 break;
201 default:
202 DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
203 *d = '\0';
204 return NT_STATUS_INVALID_PARAMETER;
207 start_of_name_component = False;
210 *d = '\0';
212 return ret;
215 /****************************************************************************
216 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
217 No wildcards allowed.
218 ****************************************************************************/
220 NTSTATUS check_path_syntax(char *path)
222 bool ignore;
223 return check_path_syntax_internal(path, False, &ignore);
226 /****************************************************************************
227 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
228 Wildcards allowed - p_contains_wcard returns true if the last component contained
229 a wildcard.
230 ****************************************************************************/
232 NTSTATUS check_path_syntax_wcard(char *path, bool *p_contains_wcard)
234 return check_path_syntax_internal(path, False, p_contains_wcard);
237 /****************************************************************************
238 Check the path for a POSIX client.
239 We're assuming here that '/' is not the second byte in any multibyte char
240 set (a safe assumption).
241 ****************************************************************************/
243 NTSTATUS check_path_syntax_posix(char *path)
245 bool ignore;
246 return check_path_syntax_internal(path, True, &ignore);
249 /****************************************************************************
250 Pull a string and check the path allowing a wilcard - provide for error return.
251 ****************************************************************************/
253 size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
254 const char *base_ptr,
255 uint16 smb_flags2,
256 char **pp_dest,
257 const char *src,
258 size_t src_len,
259 int flags,
260 NTSTATUS *err,
261 bool *contains_wcard)
263 size_t ret;
265 *pp_dest = NULL;
267 ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
268 src_len, flags);
270 if (!*pp_dest) {
271 *err = NT_STATUS_INVALID_PARAMETER;
272 return ret;
275 *contains_wcard = False;
277 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
279 * For a DFS path the function parse_dfs_path()
280 * will do the path processing, just make a copy.
282 *err = NT_STATUS_OK;
283 return ret;
286 if (lp_posix_pathnames()) {
287 *err = check_path_syntax_posix(*pp_dest);
288 } else {
289 *err = check_path_syntax_wcard(*pp_dest, contains_wcard);
292 return ret;
295 /****************************************************************************
296 Pull a string and check the path - provide for error return.
297 ****************************************************************************/
299 size_t srvstr_get_path(TALLOC_CTX *ctx,
300 const char *base_ptr,
301 uint16 smb_flags2,
302 char **pp_dest,
303 const char *src,
304 size_t src_len,
305 int flags,
306 NTSTATUS *err)
308 bool ignore;
309 return srvstr_get_path_wcard(ctx, base_ptr, smb_flags2, pp_dest, src,
310 src_len, flags, err, &ignore);
313 size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req,
314 char **pp_dest, const char *src, int flags,
315 NTSTATUS *err, bool *contains_wcard)
317 return srvstr_get_path_wcard(mem_ctx, (char *)req->inbuf, req->flags2,
318 pp_dest, src, smbreq_bufrem(req, src),
319 flags, err, contains_wcard);
322 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
323 char **pp_dest, const char *src, int flags,
324 NTSTATUS *err)
326 bool ignore;
327 return srvstr_get_path_req_wcard(mem_ctx, req, pp_dest, src,
328 flags, err, &ignore);
331 /****************************************************************************
332 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
333 ****************************************************************************/
335 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
336 files_struct *fsp)
338 if ((fsp == NULL) || (conn == NULL)) {
339 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
340 return False;
342 if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
343 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
344 return False;
346 return True;
349 /****************************************************************************
350 Check if we have a correct fsp pointing to a file.
351 ****************************************************************************/
353 bool check_fsp(connection_struct *conn, struct smb_request *req,
354 files_struct *fsp)
356 if (!check_fsp_open(conn, req, fsp)) {
357 return False;
359 if (fsp->is_directory) {
360 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
361 return False;
363 if (fsp->fh->fd == -1) {
364 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
365 return False;
367 fsp->num_smb_operations++;
368 return True;
371 /****************************************************************************
372 Check if we have a correct fsp pointing to a quota fake file. Replacement for
373 the CHECK_NTQUOTA_HANDLE_OK macro.
374 ****************************************************************************/
376 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
377 files_struct *fsp)
379 if (!check_fsp_open(conn, req, fsp)) {
380 return false;
383 if (fsp->is_directory) {
384 return false;
387 if (fsp->fake_file_handle == NULL) {
388 return false;
391 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
392 return false;
395 if (fsp->fake_file_handle->private_data == NULL) {
396 return false;
399 return true;
402 static bool netbios_session_retarget(struct smbd_server_connection *sconn,
403 const char *name, int name_type)
405 char *trim_name;
406 char *trim_name_type;
407 const char *retarget_parm;
408 char *retarget;
409 char *p;
410 int retarget_type = 0x20;
411 int retarget_port = 139;
412 struct sockaddr_storage retarget_addr;
413 struct sockaddr_in *in_addr;
414 bool ret = false;
415 uint8_t outbuf[10];
417 if (get_socket_port(sconn->sock) != 139) {
418 return false;
421 trim_name = talloc_strdup(talloc_tos(), name);
422 if (trim_name == NULL) {
423 goto fail;
425 trim_char(trim_name, ' ', ' ');
427 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
428 name_type);
429 if (trim_name_type == NULL) {
430 goto fail;
433 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
434 trim_name_type, NULL);
435 if (retarget_parm == NULL) {
436 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
437 trim_name, NULL);
439 if (retarget_parm == NULL) {
440 goto fail;
443 retarget = talloc_strdup(trim_name, retarget_parm);
444 if (retarget == NULL) {
445 goto fail;
448 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
450 p = strchr(retarget, ':');
451 if (p != NULL) {
452 *p++ = '\0';
453 retarget_port = atoi(p);
456 p = strchr_m(retarget, '#');
457 if (p != NULL) {
458 *p++ = '\0';
459 if (sscanf(p, "%x", &retarget_type) != 1) {
460 goto fail;
464 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
465 if (!ret) {
466 DEBUG(10, ("could not resolve %s\n", retarget));
467 goto fail;
470 if (retarget_addr.ss_family != AF_INET) {
471 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
472 goto fail;
475 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
477 _smb_setlen(outbuf, 6);
478 SCVAL(outbuf, 0, 0x84);
479 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
480 *(uint16_t *)(outbuf+8) = htons(retarget_port);
482 if (!srv_send_smb(sconn, (char *)outbuf, false, 0, false,
483 NULL)) {
484 exit_server_cleanly("netbios_session_regarget: srv_send_smb "
485 "failed.");
488 ret = true;
489 fail:
490 TALLOC_FREE(trim_name);
491 return ret;
494 /****************************************************************************
495 Reply to a (netbios-level) special message.
496 ****************************************************************************/
498 void reply_special(struct smbd_server_connection *sconn, char *inbuf, size_t inbuf_size)
500 int msg_type = CVAL(inbuf,0);
501 int msg_flags = CVAL(inbuf,1);
503 * We only really use 4 bytes of the outbuf, but for the smb_setlen
504 * calculation & friends (srv_send_smb uses that) we need the full smb
505 * header.
507 char outbuf[smb_size];
509 memset(outbuf, '\0', sizeof(outbuf));
511 smb_setlen(outbuf,0);
513 switch (msg_type) {
514 case 0x81: /* session request */
516 /* inbuf_size is guarenteed to be at least 4. */
517 fstring name1,name2;
518 int name_type1, name_type2;
519 int name_len1, name_len2;
521 *name1 = *name2 = 0;
523 if (sconn->nbt.got_session) {
524 exit_server_cleanly("multiple session request not permitted");
527 SCVAL(outbuf,0,0x82);
528 SCVAL(outbuf,3,0);
530 /* inbuf_size is guaranteed to be at least 4. */
531 name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
532 if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
533 DEBUG(0,("Invalid name length in session request\n"));
534 break;
536 name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
537 if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
538 DEBUG(0,("Invalid name length in session request\n"));
539 break;
542 name_type1 = name_extract((unsigned char *)inbuf,
543 inbuf_size,(unsigned int)4,name1);
544 name_type2 = name_extract((unsigned char *)inbuf,
545 inbuf_size,(unsigned int)(4 + name_len1),name2);
547 if (name_type1 == -1 || name_type2 == -1) {
548 DEBUG(0,("Invalid name type in session request\n"));
549 break;
552 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
553 name1, name_type1, name2, name_type2));
555 if (netbios_session_retarget(sconn, name1, name_type1)) {
556 exit_server_cleanly("retargeted client");
560 * Windows NT/2k uses "*SMBSERVER" and XP uses
561 * "*SMBSERV" arrggg!!!
563 if (strequal(name1, "*SMBSERVER ")
564 || strequal(name1, "*SMBSERV ")) {
565 fstrcpy(name1, sconn->client_id.addr);
568 set_local_machine_name(name1, True);
569 set_remote_machine_name(name2, True);
571 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
572 get_local_machine_name(), get_remote_machine_name(),
573 name_type2));
575 if (name_type2 == 'R') {
576 /* We are being asked for a pathworks session ---
577 no thanks! */
578 SCVAL(outbuf, 0,0x83);
579 break;
582 /* only add the client's machine name to the list
583 of possibly valid usernames if we are operating
584 in share mode security */
585 if (lp_security() == SEC_SHARE) {
586 add_session_user(sconn, get_remote_machine_name());
589 reload_services(sconn->msg_ctx, sconn->sock, True);
590 reopen_logs();
592 sconn->nbt.got_session = true;
593 break;
596 case 0x89: /* session keepalive request
597 (some old clients produce this?) */
598 SCVAL(outbuf,0,SMBkeepalive);
599 SCVAL(outbuf,3,0);
600 break;
602 case 0x82: /* positive session response */
603 case 0x83: /* negative session response */
604 case 0x84: /* retarget session response */
605 DEBUG(0,("Unexpected session response\n"));
606 break;
608 case SMBkeepalive: /* session keepalive */
609 default:
610 return;
613 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
614 msg_type, msg_flags));
616 srv_send_smb(sconn, outbuf, false, 0, false, NULL);
617 return;
620 /****************************************************************************
621 Reply to a tcon.
622 conn POINTER CAN BE NULL HERE !
623 ****************************************************************************/
625 void reply_tcon(struct smb_request *req)
627 connection_struct *conn = req->conn;
628 const char *service;
629 char *service_buf = NULL;
630 char *password = NULL;
631 char *dev = NULL;
632 int pwlen=0;
633 NTSTATUS nt_status;
634 const char *p;
635 DATA_BLOB password_blob;
636 TALLOC_CTX *ctx = talloc_tos();
637 struct smbd_server_connection *sconn = req->sconn;
639 START_PROFILE(SMBtcon);
641 if (req->buflen < 4) {
642 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
643 END_PROFILE(SMBtcon);
644 return;
647 p = (const char *)req->buf + 1;
648 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
649 p += 1;
650 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
651 p += pwlen+1;
652 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
653 p += 1;
655 if (service_buf == NULL || password == NULL || dev == NULL) {
656 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
657 END_PROFILE(SMBtcon);
658 return;
660 p = strrchr_m(service_buf,'\\');
661 if (p) {
662 service = p+1;
663 } else {
664 service = service_buf;
667 password_blob = data_blob(password, pwlen+1);
669 conn = make_connection(sconn,service,password_blob,dev,
670 req->vuid,&nt_status);
671 req->conn = conn;
673 data_blob_clear_free(&password_blob);
675 if (!conn) {
676 reply_nterror(req, nt_status);
677 END_PROFILE(SMBtcon);
678 return;
681 reply_outbuf(req, 2, 0);
682 SSVAL(req->outbuf,smb_vwv0,sconn->smb1.negprot.max_recv);
683 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
684 SSVAL(req->outbuf,smb_tid,conn->cnum);
686 DEBUG(3,("tcon service=%s cnum=%d\n",
687 service, conn->cnum));
689 END_PROFILE(SMBtcon);
690 return;
693 /****************************************************************************
694 Reply to a tcon and X.
695 conn POINTER CAN BE NULL HERE !
696 ****************************************************************************/
698 void reply_tcon_and_X(struct smb_request *req)
700 connection_struct *conn = req->conn;
701 const char *service = NULL;
702 DATA_BLOB password;
703 TALLOC_CTX *ctx = talloc_tos();
704 /* what the cleint thinks the device is */
705 char *client_devicetype = NULL;
706 /* what the server tells the client the share represents */
707 const char *server_devicetype;
708 NTSTATUS nt_status;
709 int passlen;
710 char *path = NULL;
711 const char *p, *q;
712 uint16 tcon_flags;
713 struct smbd_server_connection *sconn = req->sconn;
715 START_PROFILE(SMBtconX);
717 if (req->wct < 4) {
718 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
719 END_PROFILE(SMBtconX);
720 return;
723 passlen = SVAL(req->vwv+3, 0);
724 tcon_flags = SVAL(req->vwv+2, 0);
726 /* we might have to close an old one */
727 if ((tcon_flags & 0x1) && conn) {
728 close_cnum(conn,req->vuid);
729 req->conn = NULL;
730 conn = NULL;
733 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
734 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
735 END_PROFILE(SMBtconX);
736 return;
739 if (sconn->smb1.negprot.encrypted_passwords) {
740 password = data_blob_talloc(talloc_tos(), req->buf, passlen);
741 if (lp_security() == SEC_SHARE) {
743 * Security = share always has a pad byte
744 * after the password.
746 p = (const char *)req->buf + passlen + 1;
747 } else {
748 p = (const char *)req->buf + passlen;
750 } else {
751 password = data_blob_talloc(talloc_tos(), req->buf, passlen+1);
752 /* Ensure correct termination */
753 password.data[passlen]=0;
754 p = (const char *)req->buf + passlen + 1;
757 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
759 if (path == NULL) {
760 data_blob_clear_free(&password);
761 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
762 END_PROFILE(SMBtconX);
763 return;
767 * the service name can be either: \\server\share
768 * or share directly like on the DELL PowerVault 705
770 if (*path=='\\') {
771 q = strchr_m(path+2,'\\');
772 if (!q) {
773 data_blob_clear_free(&password);
774 reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
775 END_PROFILE(SMBtconX);
776 return;
778 service = q+1;
779 } else {
780 service = path;
783 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
784 &client_devicetype, p,
785 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
787 if (client_devicetype == NULL) {
788 data_blob_clear_free(&password);
789 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
790 END_PROFILE(SMBtconX);
791 return;
794 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
796 conn = make_connection(sconn, service, password, client_devicetype,
797 req->vuid, &nt_status);
798 req->conn =conn;
800 data_blob_clear_free(&password);
802 if (!conn) {
803 reply_nterror(req, nt_status);
804 END_PROFILE(SMBtconX);
805 return;
808 if ( IS_IPC(conn) )
809 server_devicetype = "IPC";
810 else if ( IS_PRINT(conn) )
811 server_devicetype = "LPT1:";
812 else
813 server_devicetype = "A:";
815 if (get_Protocol() < PROTOCOL_NT1) {
816 reply_outbuf(req, 2, 0);
817 if (message_push_string(&req->outbuf, server_devicetype,
818 STR_TERMINATE|STR_ASCII) == -1) {
819 reply_nterror(req, NT_STATUS_NO_MEMORY);
820 END_PROFILE(SMBtconX);
821 return;
823 } else {
824 /* NT sets the fstype of IPC$ to the null string */
825 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
827 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
828 /* Return permissions. */
829 uint32 perm1 = 0;
830 uint32 perm2 = 0;
832 reply_outbuf(req, 7, 0);
834 if (IS_IPC(conn)) {
835 perm1 = FILE_ALL_ACCESS;
836 perm2 = FILE_ALL_ACCESS;
837 } else {
838 perm1 = conn->share_access;
841 SIVAL(req->outbuf, smb_vwv3, perm1);
842 SIVAL(req->outbuf, smb_vwv5, perm2);
843 } else {
844 reply_outbuf(req, 3, 0);
847 if ((message_push_string(&req->outbuf, server_devicetype,
848 STR_TERMINATE|STR_ASCII) == -1)
849 || (message_push_string(&req->outbuf, fstype,
850 STR_TERMINATE) == -1)) {
851 reply_nterror(req, NT_STATUS_NO_MEMORY);
852 END_PROFILE(SMBtconX);
853 return;
856 /* what does setting this bit do? It is set by NT4 and
857 may affect the ability to autorun mounted cdroms */
858 SSVAL(req->outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS|
859 (lp_csc_policy(SNUM(conn)) << 2));
861 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
862 DEBUG(2,("Serving %s as a Dfs root\n",
863 lp_servicename(SNUM(conn)) ));
864 SSVAL(req->outbuf, smb_vwv2,
865 SMB_SHARE_IN_DFS | SVAL(req->outbuf, smb_vwv2));
870 DEBUG(3,("tconX service=%s \n",
871 service));
873 /* set the incoming and outgoing tid to the just created one */
874 SSVAL(req->inbuf,smb_tid,conn->cnum);
875 SSVAL(req->outbuf,smb_tid,conn->cnum);
877 END_PROFILE(SMBtconX);
879 req->tid = conn->cnum;
880 chain_reply(req);
881 return;
884 /****************************************************************************
885 Reply to an unknown type.
886 ****************************************************************************/
888 void reply_unknown_new(struct smb_request *req, uint8 type)
890 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
891 smb_fn_name(type), type, type));
892 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
893 return;
896 /****************************************************************************
897 Reply to an ioctl.
898 conn POINTER CAN BE NULL HERE !
899 ****************************************************************************/
901 void reply_ioctl(struct smb_request *req)
903 connection_struct *conn = req->conn;
904 uint16 device;
905 uint16 function;
906 uint32 ioctl_code;
907 int replysize;
908 char *p;
910 START_PROFILE(SMBioctl);
912 if (req->wct < 3) {
913 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
914 END_PROFILE(SMBioctl);
915 return;
918 device = SVAL(req->vwv+1, 0);
919 function = SVAL(req->vwv+2, 0);
920 ioctl_code = (device << 16) + function;
922 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
924 switch (ioctl_code) {
925 case IOCTL_QUERY_JOB_INFO:
926 replysize = 32;
927 break;
928 default:
929 reply_force_doserror(req, ERRSRV, ERRnosupport);
930 END_PROFILE(SMBioctl);
931 return;
934 reply_outbuf(req, 8, replysize+1);
935 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
936 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
937 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
938 p = smb_buf(req->outbuf);
939 memset(p, '\0', replysize+1); /* valgrind-safe. */
940 p += 1; /* Allow for alignment */
942 switch (ioctl_code) {
943 case IOCTL_QUERY_JOB_INFO:
945 files_struct *fsp = file_fsp(
946 req, SVAL(req->vwv+0, 0));
947 if (!fsp) {
948 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
949 END_PROFILE(SMBioctl);
950 return;
952 /* Job number */
953 if (fsp->print_file) {
954 SSVAL(p, 0, fsp->print_file->rap_jobid);
955 } else {
956 SSVAL(p, 0, 0);
958 srvstr_push((char *)req->outbuf, req->flags2, p+2,
959 global_myname(), 15,
960 STR_TERMINATE|STR_ASCII);
961 if (conn) {
962 srvstr_push((char *)req->outbuf, req->flags2,
963 p+18, lp_servicename(SNUM(conn)),
964 13, STR_TERMINATE|STR_ASCII);
965 } else {
966 memset(p+18, 0, 13);
968 break;
972 END_PROFILE(SMBioctl);
973 return;
976 /****************************************************************************
977 Strange checkpath NTSTATUS mapping.
978 ****************************************************************************/
980 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
982 /* Strange DOS error code semantics only for checkpath... */
983 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
984 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
985 /* We need to map to ERRbadpath */
986 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
989 return status;
992 /****************************************************************************
993 Reply to a checkpath.
994 ****************************************************************************/
996 void reply_checkpath(struct smb_request *req)
998 connection_struct *conn = req->conn;
999 struct smb_filename *smb_fname = NULL;
1000 char *name = NULL;
1001 NTSTATUS status;
1002 TALLOC_CTX *ctx = talloc_tos();
1004 START_PROFILE(SMBcheckpath);
1006 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
1007 STR_TERMINATE, &status);
1009 if (!NT_STATUS_IS_OK(status)) {
1010 status = map_checkpath_error(req->flags2, status);
1011 reply_nterror(req, status);
1012 END_PROFILE(SMBcheckpath);
1013 return;
1016 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1018 status = filename_convert(ctx,
1019 conn,
1020 req->flags2 & FLAGS2_DFS_PATHNAMES,
1021 name,
1023 NULL,
1024 &smb_fname);
1026 if (!NT_STATUS_IS_OK(status)) {
1027 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1028 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1029 ERRSRV, ERRbadpath);
1030 END_PROFILE(SMBcheckpath);
1031 return;
1033 goto path_err;
1036 if (!VALID_STAT(smb_fname->st) &&
1037 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1038 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1039 smb_fname_str_dbg(smb_fname), strerror(errno)));
1040 status = map_nt_error_from_unix(errno);
1041 goto path_err;
1044 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1045 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1046 ERRDOS, ERRbadpath);
1047 goto out;
1050 reply_outbuf(req, 0, 0);
1052 path_err:
1053 /* We special case this - as when a Windows machine
1054 is parsing a path is steps through the components
1055 one at a time - if a component fails it expects
1056 ERRbadpath, not ERRbadfile.
1058 status = map_checkpath_error(req->flags2, status);
1059 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1061 * Windows returns different error codes if
1062 * the parent directory is valid but not the
1063 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1064 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1065 * if the path is invalid.
1067 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1068 ERRDOS, ERRbadpath);
1069 goto out;
1072 reply_nterror(req, status);
1074 out:
1075 TALLOC_FREE(smb_fname);
1076 END_PROFILE(SMBcheckpath);
1077 return;
1080 /****************************************************************************
1081 Reply to a getatr.
1082 ****************************************************************************/
1084 void reply_getatr(struct smb_request *req)
1086 connection_struct *conn = req->conn;
1087 struct smb_filename *smb_fname = NULL;
1088 char *fname = NULL;
1089 int mode=0;
1090 SMB_OFF_T size=0;
1091 time_t mtime=0;
1092 const char *p;
1093 NTSTATUS status;
1094 TALLOC_CTX *ctx = talloc_tos();
1095 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1097 START_PROFILE(SMBgetatr);
1099 p = (const char *)req->buf + 1;
1100 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1101 if (!NT_STATUS_IS_OK(status)) {
1102 reply_nterror(req, status);
1103 goto out;
1106 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1107 under WfWg - weird! */
1108 if (*fname == '\0') {
1109 mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1110 if (!CAN_WRITE(conn)) {
1111 mode |= FILE_ATTRIBUTE_READONLY;
1113 size = 0;
1114 mtime = 0;
1115 } else {
1116 status = filename_convert(ctx,
1117 conn,
1118 req->flags2 & FLAGS2_DFS_PATHNAMES,
1119 fname,
1121 NULL,
1122 &smb_fname);
1123 if (!NT_STATUS_IS_OK(status)) {
1124 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1125 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1126 ERRSRV, ERRbadpath);
1127 goto out;
1129 reply_nterror(req, status);
1130 goto out;
1132 if (!VALID_STAT(smb_fname->st) &&
1133 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1134 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1135 smb_fname_str_dbg(smb_fname),
1136 strerror(errno)));
1137 reply_nterror(req, map_nt_error_from_unix(errno));
1138 goto out;
1141 mode = dos_mode(conn, smb_fname);
1142 size = smb_fname->st.st_ex_size;
1144 if (ask_sharemode) {
1145 struct timespec write_time_ts;
1146 struct file_id fileid;
1148 ZERO_STRUCT(write_time_ts);
1149 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1150 get_file_infos(fileid, 0, NULL, &write_time_ts);
1151 if (!null_timespec(write_time_ts)) {
1152 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1156 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1157 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1158 size = 0;
1162 reply_outbuf(req, 10, 0);
1164 SSVAL(req->outbuf,smb_vwv0,mode);
1165 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1166 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1167 } else {
1168 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1170 SIVAL(req->outbuf,smb_vwv3,(uint32)size);
1172 if (get_Protocol() >= PROTOCOL_NT1) {
1173 SSVAL(req->outbuf, smb_flg2,
1174 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1177 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1178 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1180 out:
1181 TALLOC_FREE(smb_fname);
1182 TALLOC_FREE(fname);
1183 END_PROFILE(SMBgetatr);
1184 return;
1187 /****************************************************************************
1188 Reply to a setatr.
1189 ****************************************************************************/
1191 void reply_setatr(struct smb_request *req)
1193 struct smb_file_time ft;
1194 connection_struct *conn = req->conn;
1195 struct smb_filename *smb_fname = NULL;
1196 char *fname = NULL;
1197 int mode;
1198 time_t mtime;
1199 const char *p;
1200 NTSTATUS status;
1201 TALLOC_CTX *ctx = talloc_tos();
1203 START_PROFILE(SMBsetatr);
1205 ZERO_STRUCT(ft);
1207 if (req->wct < 2) {
1208 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1209 goto out;
1212 p = (const char *)req->buf + 1;
1213 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1214 if (!NT_STATUS_IS_OK(status)) {
1215 reply_nterror(req, status);
1216 goto out;
1219 status = filename_convert(ctx,
1220 conn,
1221 req->flags2 & FLAGS2_DFS_PATHNAMES,
1222 fname,
1224 NULL,
1225 &smb_fname);
1226 if (!NT_STATUS_IS_OK(status)) {
1227 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1228 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1229 ERRSRV, ERRbadpath);
1230 goto out;
1232 reply_nterror(req, status);
1233 goto out;
1236 if (smb_fname->base_name[0] == '.' &&
1237 smb_fname->base_name[1] == '\0') {
1239 * Not sure here is the right place to catch this
1240 * condition. Might be moved to somewhere else later -- vl
1242 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1243 goto out;
1246 mode = SVAL(req->vwv+0, 0);
1247 mtime = srv_make_unix_date3(req->vwv+1);
1249 ft.mtime = convert_time_t_to_timespec(mtime);
1250 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1251 if (!NT_STATUS_IS_OK(status)) {
1252 reply_nterror(req, status);
1253 goto out;
1256 if (mode != FILE_ATTRIBUTE_NORMAL) {
1257 if (VALID_STAT_OF_DIR(smb_fname->st))
1258 mode |= FILE_ATTRIBUTE_DIRECTORY;
1259 else
1260 mode &= ~FILE_ATTRIBUTE_DIRECTORY;
1262 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1263 false) != 0) {
1264 reply_nterror(req, map_nt_error_from_unix(errno));
1265 goto out;
1269 reply_outbuf(req, 0, 0);
1271 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1272 mode));
1273 out:
1274 TALLOC_FREE(smb_fname);
1275 END_PROFILE(SMBsetatr);
1276 return;
1279 /****************************************************************************
1280 Reply to a dskattr.
1281 ****************************************************************************/
1283 void reply_dskattr(struct smb_request *req)
1285 connection_struct *conn = req->conn;
1286 uint64_t dfree,dsize,bsize;
1287 START_PROFILE(SMBdskattr);
1289 if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (uint64_t)-1) {
1290 reply_nterror(req, map_nt_error_from_unix(errno));
1291 END_PROFILE(SMBdskattr);
1292 return;
1295 reply_outbuf(req, 5, 0);
1297 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1298 double total_space, free_space;
1299 /* we need to scale this to a number that DOS6 can handle. We
1300 use floating point so we can handle large drives on systems
1301 that don't have 64 bit integers
1303 we end up displaying a maximum of 2G to DOS systems
1305 total_space = dsize * (double)bsize;
1306 free_space = dfree * (double)bsize;
1308 dsize = (uint64_t)((total_space+63*512) / (64*512));
1309 dfree = (uint64_t)((free_space+63*512) / (64*512));
1311 if (dsize > 0xFFFF) dsize = 0xFFFF;
1312 if (dfree > 0xFFFF) dfree = 0xFFFF;
1314 SSVAL(req->outbuf,smb_vwv0,dsize);
1315 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1316 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1317 SSVAL(req->outbuf,smb_vwv3,dfree);
1318 } else {
1319 SSVAL(req->outbuf,smb_vwv0,dsize);
1320 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1321 SSVAL(req->outbuf,smb_vwv2,512);
1322 SSVAL(req->outbuf,smb_vwv3,dfree);
1325 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1327 END_PROFILE(SMBdskattr);
1328 return;
1332 * Utility function to split the filename from the directory.
1334 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1335 char **fname_dir_out,
1336 char **fname_mask_out)
1338 const char *p = NULL;
1339 char *fname_dir = NULL;
1340 char *fname_mask = NULL;
1342 p = strrchr_m(fname_in, '/');
1343 if (!p) {
1344 fname_dir = talloc_strdup(ctx, ".");
1345 fname_mask = talloc_strdup(ctx, fname_in);
1346 } else {
1347 fname_dir = talloc_strndup(ctx, fname_in,
1348 PTR_DIFF(p, fname_in));
1349 fname_mask = talloc_strdup(ctx, p+1);
1352 if (!fname_dir || !fname_mask) {
1353 TALLOC_FREE(fname_dir);
1354 TALLOC_FREE(fname_mask);
1355 return NT_STATUS_NO_MEMORY;
1358 *fname_dir_out = fname_dir;
1359 *fname_mask_out = fname_mask;
1360 return NT_STATUS_OK;
1363 /****************************************************************************
1364 Reply to a search.
1365 Can be called from SMBsearch, SMBffirst or SMBfunique.
1366 ****************************************************************************/
1368 void reply_search(struct smb_request *req)
1370 connection_struct *conn = req->conn;
1371 char *path = NULL;
1372 const char *mask = NULL;
1373 char *directory = NULL;
1374 struct smb_filename *smb_fname = NULL;
1375 char *fname = NULL;
1376 SMB_OFF_T size;
1377 uint32 mode;
1378 struct timespec date;
1379 uint32 dirtype;
1380 unsigned int numentries = 0;
1381 unsigned int maxentries = 0;
1382 bool finished = False;
1383 const char *p;
1384 int status_len;
1385 char status[21];
1386 int dptr_num= -1;
1387 bool check_descend = False;
1388 bool expect_close = False;
1389 NTSTATUS nt_status;
1390 bool mask_contains_wcard = False;
1391 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1392 TALLOC_CTX *ctx = talloc_tos();
1393 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1394 struct dptr_struct *dirptr = NULL;
1395 struct smbd_server_connection *sconn = req->sconn;
1397 START_PROFILE(SMBsearch);
1399 if (req->wct < 2) {
1400 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1401 goto out;
1404 if (lp_posix_pathnames()) {
1405 reply_unknown_new(req, req->cmd);
1406 goto out;
1409 /* If we were called as SMBffirst then we must expect close. */
1410 if(req->cmd == SMBffirst) {
1411 expect_close = True;
1414 reply_outbuf(req, 1, 3);
1415 maxentries = SVAL(req->vwv+0, 0);
1416 dirtype = SVAL(req->vwv+1, 0);
1417 p = (const char *)req->buf + 1;
1418 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1419 &nt_status, &mask_contains_wcard);
1420 if (!NT_STATUS_IS_OK(nt_status)) {
1421 reply_nterror(req, nt_status);
1422 goto out;
1425 p++;
1426 status_len = SVAL(p, 0);
1427 p += 2;
1429 /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1431 if (status_len == 0) {
1432 nt_status = filename_convert(ctx, conn,
1433 req->flags2 & FLAGS2_DFS_PATHNAMES,
1434 path,
1435 UCF_ALWAYS_ALLOW_WCARD_LCOMP,
1436 &mask_contains_wcard,
1437 &smb_fname);
1438 if (!NT_STATUS_IS_OK(nt_status)) {
1439 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1440 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1441 ERRSRV, ERRbadpath);
1442 goto out;
1444 reply_nterror(req, nt_status);
1445 goto out;
1448 directory = smb_fname->base_name;
1450 p = strrchr_m(directory,'/');
1451 if ((p != NULL) && (*directory != '/')) {
1452 mask = p + 1;
1453 directory = talloc_strndup(ctx, directory,
1454 PTR_DIFF(p, directory));
1455 } else {
1456 mask = directory;
1457 directory = talloc_strdup(ctx,".");
1460 if (!directory) {
1461 reply_nterror(req, NT_STATUS_NO_MEMORY);
1462 goto out;
1465 memset((char *)status,'\0',21);
1466 SCVAL(status,0,(dirtype & 0x1F));
1468 nt_status = dptr_create(conn,
1469 NULL, /* fsp */
1470 directory,
1471 True,
1472 expect_close,
1473 req->smbpid,
1474 mask,
1475 mask_contains_wcard,
1476 dirtype,
1477 &dirptr);
1478 if (!NT_STATUS_IS_OK(nt_status)) {
1479 reply_nterror(req, nt_status);
1480 goto out;
1482 dptr_num = dptr_dnum(dirptr);
1483 } else {
1484 int status_dirtype;
1485 const char *dirpath;
1487 memcpy(status,p,21);
1488 status_dirtype = CVAL(status,0) & 0x1F;
1489 if (status_dirtype != (dirtype & 0x1F)) {
1490 dirtype = status_dirtype;
1493 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1494 if (!dirptr) {
1495 goto SearchEmpty;
1497 dirpath = dptr_path(sconn, dptr_num);
1498 directory = talloc_strdup(ctx, dirpath);
1499 if (!directory) {
1500 reply_nterror(req, NT_STATUS_NO_MEMORY);
1501 goto out;
1504 mask = dptr_wcard(sconn, dptr_num);
1505 if (!mask) {
1506 goto SearchEmpty;
1509 * For a 'continue' search we have no string. So
1510 * check from the initial saved string.
1512 mask_contains_wcard = ms_has_wild(mask);
1513 dirtype = dptr_attr(sconn, dptr_num);
1516 DEBUG(4,("dptr_num is %d\n",dptr_num));
1518 /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
1519 dptr_init_search_op(dirptr);
1521 if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1522 char buf[DIR_STRUCT_SIZE];
1523 memcpy(buf,status,21);
1524 if (!make_dir_struct(ctx,buf,"???????????",volume_label(SNUM(conn)),
1525 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1526 reply_nterror(req, NT_STATUS_NO_MEMORY);
1527 goto out;
1529 dptr_fill(sconn, buf+12,dptr_num);
1530 if (dptr_zero(buf+12) && (status_len==0)) {
1531 numentries = 1;
1532 } else {
1533 numentries = 0;
1535 if (message_push_blob(&req->outbuf,
1536 data_blob_const(buf, sizeof(buf)))
1537 == -1) {
1538 reply_nterror(req, NT_STATUS_NO_MEMORY);
1539 goto out;
1541 } else {
1542 unsigned int i;
1543 maxentries = MIN(
1544 maxentries,
1545 ((BUFFER_SIZE -
1546 ((uint8 *)smb_buf(req->outbuf) + 3 - req->outbuf))
1547 /DIR_STRUCT_SIZE));
1549 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1550 directory,lp_dontdescend(SNUM(conn))));
1551 if (in_list(directory, lp_dontdescend(SNUM(conn)),True)) {
1552 check_descend = True;
1555 for (i=numentries;(i<maxentries) && !finished;i++) {
1556 finished = !get_dir_entry(ctx,
1557 dirptr,
1558 mask,
1559 dirtype,
1560 &fname,
1561 &size,
1562 &mode,
1563 &date,
1564 check_descend,
1565 ask_sharemode);
1566 if (!finished) {
1567 char buf[DIR_STRUCT_SIZE];
1568 memcpy(buf,status,21);
1569 if (!make_dir_struct(ctx,
1570 buf,
1571 mask,
1572 fname,
1573 size,
1574 mode,
1575 convert_timespec_to_time_t(date),
1576 !allow_long_path_components)) {
1577 reply_nterror(req, NT_STATUS_NO_MEMORY);
1578 goto out;
1580 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1581 break;
1583 if (message_push_blob(&req->outbuf,
1584 data_blob_const(buf, sizeof(buf)))
1585 == -1) {
1586 reply_nterror(req, NT_STATUS_NO_MEMORY);
1587 goto out;
1589 numentries++;
1594 SearchEmpty:
1596 /* If we were called as SMBffirst with smb_search_id == NULL
1597 and no entries were found then return error and close dirptr
1598 (X/Open spec) */
1600 if (numentries == 0) {
1601 dptr_close(sconn, &dptr_num);
1602 } else if(expect_close && status_len == 0) {
1603 /* Close the dptr - we know it's gone */
1604 dptr_close(sconn, &dptr_num);
1607 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1608 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1609 dptr_close(sconn, &dptr_num);
1612 if ((numentries == 0) && !mask_contains_wcard) {
1613 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1614 goto out;
1617 SSVAL(req->outbuf,smb_vwv0,numentries);
1618 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1619 SCVAL(smb_buf(req->outbuf),0,5);
1620 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1622 /* The replies here are never long name. */
1623 SSVAL(req->outbuf, smb_flg2,
1624 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1625 if (!allow_long_path_components) {
1626 SSVAL(req->outbuf, smb_flg2,
1627 SVAL(req->outbuf, smb_flg2)
1628 & (~FLAGS2_LONG_PATH_COMPONENTS));
1631 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
1632 SSVAL(req->outbuf, smb_flg2,
1633 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
1635 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
1636 smb_fn_name(req->cmd),
1637 mask,
1638 directory,
1639 dirtype,
1640 numentries,
1641 maxentries ));
1642 out:
1643 TALLOC_FREE(directory);
1644 TALLOC_FREE(smb_fname);
1645 END_PROFILE(SMBsearch);
1646 return;
1649 /****************************************************************************
1650 Reply to a fclose (stop directory search).
1651 ****************************************************************************/
1653 void reply_fclose(struct smb_request *req)
1655 int status_len;
1656 char status[21];
1657 int dptr_num= -2;
1658 const char *p;
1659 char *path = NULL;
1660 NTSTATUS err;
1661 bool path_contains_wcard = False;
1662 TALLOC_CTX *ctx = talloc_tos();
1663 struct smbd_server_connection *sconn = req->sconn;
1665 START_PROFILE(SMBfclose);
1667 if (lp_posix_pathnames()) {
1668 reply_unknown_new(req, req->cmd);
1669 END_PROFILE(SMBfclose);
1670 return;
1673 p = (const char *)req->buf + 1;
1674 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1675 &err, &path_contains_wcard);
1676 if (!NT_STATUS_IS_OK(err)) {
1677 reply_nterror(req, err);
1678 END_PROFILE(SMBfclose);
1679 return;
1681 p++;
1682 status_len = SVAL(p,0);
1683 p += 2;
1685 if (status_len == 0) {
1686 reply_force_doserror(req, ERRSRV, ERRsrverror);
1687 END_PROFILE(SMBfclose);
1688 return;
1691 memcpy(status,p,21);
1693 if(dptr_fetch(sconn, status+12,&dptr_num)) {
1694 /* Close the dptr - we know it's gone */
1695 dptr_close(sconn, &dptr_num);
1698 reply_outbuf(req, 1, 0);
1699 SSVAL(req->outbuf,smb_vwv0,0);
1701 DEBUG(3,("search close\n"));
1703 END_PROFILE(SMBfclose);
1704 return;
1707 /****************************************************************************
1708 Reply to an open.
1709 ****************************************************************************/
1711 void reply_open(struct smb_request *req)
1713 connection_struct *conn = req->conn;
1714 struct smb_filename *smb_fname = NULL;
1715 char *fname = NULL;
1716 uint32 fattr=0;
1717 SMB_OFF_T size = 0;
1718 time_t mtime=0;
1719 int info;
1720 files_struct *fsp;
1721 int oplock_request;
1722 int deny_mode;
1723 uint32 dos_attr;
1724 uint32 access_mask;
1725 uint32 share_mode;
1726 uint32 create_disposition;
1727 uint32 create_options = 0;
1728 uint32_t private_flags = 0;
1729 NTSTATUS status;
1730 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1731 TALLOC_CTX *ctx = talloc_tos();
1733 START_PROFILE(SMBopen);
1735 if (req->wct < 2) {
1736 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1737 goto out;
1740 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1741 deny_mode = SVAL(req->vwv+0, 0);
1742 dos_attr = SVAL(req->vwv+1, 0);
1744 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
1745 STR_TERMINATE, &status);
1746 if (!NT_STATUS_IS_OK(status)) {
1747 reply_nterror(req, status);
1748 goto out;
1751 status = filename_convert(ctx,
1752 conn,
1753 req->flags2 & FLAGS2_DFS_PATHNAMES,
1754 fname,
1756 NULL,
1757 &smb_fname);
1758 if (!NT_STATUS_IS_OK(status)) {
1759 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1760 reply_botherror(req,
1761 NT_STATUS_PATH_NOT_COVERED,
1762 ERRSRV, ERRbadpath);
1763 goto out;
1765 reply_nterror(req, status);
1766 goto out;
1769 if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode,
1770 OPENX_FILE_EXISTS_OPEN, &access_mask,
1771 &share_mode, &create_disposition,
1772 &create_options, &private_flags)) {
1773 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1774 goto out;
1777 status = SMB_VFS_CREATE_FILE(
1778 conn, /* conn */
1779 req, /* req */
1780 0, /* root_dir_fid */
1781 smb_fname, /* fname */
1782 access_mask, /* access_mask */
1783 share_mode, /* share_access */
1784 create_disposition, /* create_disposition*/
1785 create_options, /* create_options */
1786 dos_attr, /* file_attributes */
1787 oplock_request, /* oplock_request */
1788 0, /* allocation_size */
1789 private_flags,
1790 NULL, /* sd */
1791 NULL, /* ea_list */
1792 &fsp, /* result */
1793 &info); /* pinfo */
1795 if (!NT_STATUS_IS_OK(status)) {
1796 if (open_was_deferred(req->mid)) {
1797 /* We have re-scheduled this call. */
1798 goto out;
1800 reply_openerror(req, status);
1801 goto out;
1804 size = smb_fname->st.st_ex_size;
1805 fattr = dos_mode(conn, smb_fname);
1807 /* Deal with other possible opens having a modified
1808 write time. JRA. */
1809 if (ask_sharemode) {
1810 struct timespec write_time_ts;
1812 ZERO_STRUCT(write_time_ts);
1813 get_file_infos(fsp->file_id, 0, NULL, &write_time_ts);
1814 if (!null_timespec(write_time_ts)) {
1815 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1819 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1821 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
1822 DEBUG(3,("attempt to open a directory %s\n",
1823 fsp_str_dbg(fsp)));
1824 close_file(req, fsp, ERROR_CLOSE);
1825 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
1826 ERRDOS, ERRnoaccess);
1827 goto out;
1830 reply_outbuf(req, 7, 0);
1831 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
1832 SSVAL(req->outbuf,smb_vwv1,fattr);
1833 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1834 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
1835 } else {
1836 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
1838 SIVAL(req->outbuf,smb_vwv4,(uint32)size);
1839 SSVAL(req->outbuf,smb_vwv6,deny_mode);
1841 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1842 SCVAL(req->outbuf,smb_flg,
1843 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1846 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1847 SCVAL(req->outbuf,smb_flg,
1848 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1850 out:
1851 TALLOC_FREE(smb_fname);
1852 END_PROFILE(SMBopen);
1853 return;
1856 /****************************************************************************
1857 Reply to an open and X.
1858 ****************************************************************************/
1860 void reply_open_and_X(struct smb_request *req)
1862 connection_struct *conn = req->conn;
1863 struct smb_filename *smb_fname = NULL;
1864 char *fname = NULL;
1865 uint16 open_flags;
1866 int deny_mode;
1867 uint32 smb_attr;
1868 /* Breakout the oplock request bits so we can set the
1869 reply bits separately. */
1870 int ex_oplock_request;
1871 int core_oplock_request;
1872 int oplock_request;
1873 #if 0
1874 int smb_sattr = SVAL(req->vwv+4, 0);
1875 uint32 smb_time = make_unix_date3(req->vwv+6);
1876 #endif
1877 int smb_ofun;
1878 uint32 fattr=0;
1879 int mtime=0;
1880 int smb_action = 0;
1881 files_struct *fsp;
1882 NTSTATUS status;
1883 uint64_t allocation_size;
1884 ssize_t retval = -1;
1885 uint32 access_mask;
1886 uint32 share_mode;
1887 uint32 create_disposition;
1888 uint32 create_options = 0;
1889 uint32_t private_flags = 0;
1890 TALLOC_CTX *ctx = talloc_tos();
1892 START_PROFILE(SMBopenX);
1894 if (req->wct < 15) {
1895 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1896 goto out;
1899 open_flags = SVAL(req->vwv+2, 0);
1900 deny_mode = SVAL(req->vwv+3, 0);
1901 smb_attr = SVAL(req->vwv+5, 0);
1902 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
1903 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1904 oplock_request = ex_oplock_request | core_oplock_request;
1905 smb_ofun = SVAL(req->vwv+8, 0);
1906 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
1908 /* If it's an IPC, pass off the pipe handler. */
1909 if (IS_IPC(conn)) {
1910 if (lp_nt_pipe_support()) {
1911 reply_open_pipe_and_X(conn, req);
1912 } else {
1913 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
1915 goto out;
1918 /* XXXX we need to handle passed times, sattr and flags */
1919 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
1920 STR_TERMINATE, &status);
1921 if (!NT_STATUS_IS_OK(status)) {
1922 reply_nterror(req, status);
1923 goto out;
1926 status = filename_convert(ctx,
1927 conn,
1928 req->flags2 & FLAGS2_DFS_PATHNAMES,
1929 fname,
1931 NULL,
1932 &smb_fname);
1933 if (!NT_STATUS_IS_OK(status)) {
1934 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1935 reply_botherror(req,
1936 NT_STATUS_PATH_NOT_COVERED,
1937 ERRSRV, ERRbadpath);
1938 goto out;
1940 reply_nterror(req, status);
1941 goto out;
1944 if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode,
1945 smb_ofun,
1946 &access_mask, &share_mode,
1947 &create_disposition,
1948 &create_options,
1949 &private_flags)) {
1950 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1951 goto out;
1954 status = SMB_VFS_CREATE_FILE(
1955 conn, /* conn */
1956 req, /* req */
1957 0, /* root_dir_fid */
1958 smb_fname, /* fname */
1959 access_mask, /* access_mask */
1960 share_mode, /* share_access */
1961 create_disposition, /* create_disposition*/
1962 create_options, /* create_options */
1963 smb_attr, /* file_attributes */
1964 oplock_request, /* oplock_request */
1965 0, /* allocation_size */
1966 private_flags,
1967 NULL, /* sd */
1968 NULL, /* ea_list */
1969 &fsp, /* result */
1970 &smb_action); /* pinfo */
1972 if (!NT_STATUS_IS_OK(status)) {
1973 if (open_was_deferred(req->mid)) {
1974 /* We have re-scheduled this call. */
1975 goto out;
1977 reply_openerror(req, status);
1978 goto out;
1981 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
1982 if the file is truncated or created. */
1983 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
1984 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
1985 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
1986 close_file(req, fsp, ERROR_CLOSE);
1987 reply_nterror(req, NT_STATUS_DISK_FULL);
1988 goto out;
1990 retval = vfs_set_filelen(fsp, (SMB_OFF_T)allocation_size);
1991 if (retval < 0) {
1992 close_file(req, fsp, ERROR_CLOSE);
1993 reply_nterror(req, NT_STATUS_DISK_FULL);
1994 goto out;
1996 status = vfs_stat_fsp(fsp);
1997 if (!NT_STATUS_IS_OK(status)) {
1998 close_file(req, fsp, ERROR_CLOSE);
1999 reply_nterror(req, status);
2000 goto out;
2004 fattr = dos_mode(conn, fsp->fsp_name);
2005 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2006 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2007 close_file(req, fsp, ERROR_CLOSE);
2008 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2009 goto out;
2012 /* If the caller set the extended oplock request bit
2013 and we granted one (by whatever means) - set the
2014 correct bit for extended oplock reply.
2017 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2018 smb_action |= EXTENDED_OPLOCK_GRANTED;
2021 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2022 smb_action |= EXTENDED_OPLOCK_GRANTED;
2025 /* If the caller set the core oplock request bit
2026 and we granted one (by whatever means) - set the
2027 correct bit for core oplock reply.
2030 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2031 reply_outbuf(req, 19, 0);
2032 } else {
2033 reply_outbuf(req, 15, 0);
2036 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2037 SCVAL(req->outbuf, smb_flg,
2038 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2041 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2042 SCVAL(req->outbuf, smb_flg,
2043 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2046 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2047 SSVAL(req->outbuf,smb_vwv3,fattr);
2048 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2049 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2050 } else {
2051 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2053 SIVAL(req->outbuf,smb_vwv6,(uint32)fsp->fsp_name->st.st_ex_size);
2054 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2055 SSVAL(req->outbuf,smb_vwv11,smb_action);
2057 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2058 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2061 chain_reply(req);
2062 out:
2063 TALLOC_FREE(smb_fname);
2064 END_PROFILE(SMBopenX);
2065 return;
2068 /****************************************************************************
2069 Reply to a SMBulogoffX.
2070 ****************************************************************************/
2072 void reply_ulogoffX(struct smb_request *req)
2074 struct smbd_server_connection *sconn = req->sconn;
2075 user_struct *vuser;
2077 START_PROFILE(SMBulogoffX);
2079 vuser = get_valid_user_struct(sconn, req->vuid);
2081 if(vuser == NULL) {
2082 DEBUG(3,("ulogoff, vuser id %d does not map to user.\n",
2083 req->vuid));
2086 /* in user level security we are supposed to close any files
2087 open by this user */
2088 if ((vuser != NULL) && (lp_security() != SEC_SHARE)) {
2089 file_close_user(sconn, req->vuid);
2092 invalidate_vuid(sconn, req->vuid);
2094 reply_outbuf(req, 2, 0);
2096 DEBUG( 3, ( "ulogoffX vuid=%d\n", req->vuid ) );
2098 END_PROFILE(SMBulogoffX);
2099 req->vuid = UID_FIELD_INVALID;
2100 chain_reply(req);
2103 /****************************************************************************
2104 Reply to a mknew or a create.
2105 ****************************************************************************/
2107 void reply_mknew(struct smb_request *req)
2109 connection_struct *conn = req->conn;
2110 struct smb_filename *smb_fname = NULL;
2111 char *fname = NULL;
2112 uint32 fattr = 0;
2113 struct smb_file_time ft;
2114 files_struct *fsp;
2115 int oplock_request = 0;
2116 NTSTATUS status;
2117 uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2118 uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2119 uint32 create_disposition;
2120 uint32 create_options = 0;
2121 TALLOC_CTX *ctx = talloc_tos();
2123 START_PROFILE(SMBcreate);
2124 ZERO_STRUCT(ft);
2126 if (req->wct < 3) {
2127 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2128 goto out;
2131 fattr = SVAL(req->vwv+0, 0);
2132 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2134 /* mtime. */
2135 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2137 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2138 STR_TERMINATE, &status);
2139 if (!NT_STATUS_IS_OK(status)) {
2140 reply_nterror(req, status);
2141 goto out;
2144 status = filename_convert(ctx,
2145 conn,
2146 req->flags2 & FLAGS2_DFS_PATHNAMES,
2147 fname,
2149 NULL,
2150 &smb_fname);
2151 if (!NT_STATUS_IS_OK(status)) {
2152 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2153 reply_botherror(req,
2154 NT_STATUS_PATH_NOT_COVERED,
2155 ERRSRV, ERRbadpath);
2156 goto out;
2158 reply_nterror(req, status);
2159 goto out;
2162 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2163 DEBUG(0,("Attempt to create file (%s) with volid set - "
2164 "please report this\n",
2165 smb_fname_str_dbg(smb_fname)));
2168 if(req->cmd == SMBmknew) {
2169 /* We should fail if file exists. */
2170 create_disposition = FILE_CREATE;
2171 } else {
2172 /* Create if file doesn't exist, truncate if it does. */
2173 create_disposition = FILE_OVERWRITE_IF;
2176 status = SMB_VFS_CREATE_FILE(
2177 conn, /* conn */
2178 req, /* req */
2179 0, /* root_dir_fid */
2180 smb_fname, /* fname */
2181 access_mask, /* access_mask */
2182 share_mode, /* share_access */
2183 create_disposition, /* create_disposition*/
2184 create_options, /* create_options */
2185 fattr, /* file_attributes */
2186 oplock_request, /* oplock_request */
2187 0, /* allocation_size */
2188 0, /* private_flags */
2189 NULL, /* sd */
2190 NULL, /* ea_list */
2191 &fsp, /* result */
2192 NULL); /* pinfo */
2194 if (!NT_STATUS_IS_OK(status)) {
2195 if (open_was_deferred(req->mid)) {
2196 /* We have re-scheduled this call. */
2197 goto out;
2199 reply_openerror(req, status);
2200 goto out;
2203 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2204 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2205 if (!NT_STATUS_IS_OK(status)) {
2206 END_PROFILE(SMBcreate);
2207 goto out;
2210 reply_outbuf(req, 1, 0);
2211 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2213 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2214 SCVAL(req->outbuf,smb_flg,
2215 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2218 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2219 SCVAL(req->outbuf,smb_flg,
2220 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2223 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2224 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2225 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2226 (unsigned int)fattr));
2228 out:
2229 TALLOC_FREE(smb_fname);
2230 END_PROFILE(SMBcreate);
2231 return;
2234 /****************************************************************************
2235 Reply to a create temporary file.
2236 ****************************************************************************/
2238 void reply_ctemp(struct smb_request *req)
2240 connection_struct *conn = req->conn;
2241 struct smb_filename *smb_fname = NULL;
2242 char *wire_name = NULL;
2243 char *fname = NULL;
2244 uint32 fattr;
2245 files_struct *fsp;
2246 int oplock_request;
2247 char *s;
2248 NTSTATUS status;
2249 int i;
2250 TALLOC_CTX *ctx = talloc_tos();
2252 START_PROFILE(SMBctemp);
2254 if (req->wct < 3) {
2255 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2256 goto out;
2259 fattr = SVAL(req->vwv+0, 0);
2260 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2262 srvstr_get_path_req(ctx, req, &wire_name, (const char *)req->buf+1,
2263 STR_TERMINATE, &status);
2264 if (!NT_STATUS_IS_OK(status)) {
2265 reply_nterror(req, status);
2266 goto out;
2269 for (i = 0; i < 10; i++) {
2270 if (*wire_name) {
2271 fname = talloc_asprintf(ctx,
2272 "%s/TMP%s",
2273 wire_name,
2274 generate_random_str_list(ctx, 5, "0123456789"));
2275 } else {
2276 fname = talloc_asprintf(ctx,
2277 "TMP%s",
2278 generate_random_str_list(ctx, 5, "0123456789"));
2281 if (!fname) {
2282 reply_nterror(req, NT_STATUS_NO_MEMORY);
2283 goto out;
2286 status = filename_convert(ctx, conn,
2287 req->flags2 & FLAGS2_DFS_PATHNAMES,
2288 fname,
2290 NULL,
2291 &smb_fname);
2292 if (!NT_STATUS_IS_OK(status)) {
2293 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2294 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2295 ERRSRV, ERRbadpath);
2296 goto out;
2298 reply_nterror(req, status);
2299 goto out;
2302 /* Create the file. */
2303 status = SMB_VFS_CREATE_FILE(
2304 conn, /* conn */
2305 req, /* req */
2306 0, /* root_dir_fid */
2307 smb_fname, /* fname */
2308 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2309 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2310 FILE_CREATE, /* create_disposition*/
2311 0, /* create_options */
2312 fattr, /* file_attributes */
2313 oplock_request, /* oplock_request */
2314 0, /* allocation_size */
2315 0, /* private_flags */
2316 NULL, /* sd */
2317 NULL, /* ea_list */
2318 &fsp, /* result */
2319 NULL); /* pinfo */
2321 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2322 TALLOC_FREE(fname);
2323 TALLOC_FREE(smb_fname);
2324 continue;
2327 if (!NT_STATUS_IS_OK(status)) {
2328 if (open_was_deferred(req->mid)) {
2329 /* We have re-scheduled this call. */
2330 goto out;
2332 reply_openerror(req, status);
2333 goto out;
2336 break;
2339 if (i == 10) {
2340 /* Collision after 10 times... */
2341 reply_nterror(req, status);
2342 goto out;
2345 reply_outbuf(req, 1, 0);
2346 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2348 /* the returned filename is relative to the directory */
2349 s = strrchr_m(fsp->fsp_name->base_name, '/');
2350 if (!s) {
2351 s = fsp->fsp_name->base_name;
2352 } else {
2353 s++;
2356 #if 0
2357 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2358 thing in the byte section. JRA */
2359 SSVALS(p, 0, -1); /* what is this? not in spec */
2360 #endif
2361 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2362 == -1) {
2363 reply_nterror(req, NT_STATUS_NO_MEMORY);
2364 goto out;
2367 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2368 SCVAL(req->outbuf, smb_flg,
2369 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2372 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2373 SCVAL(req->outbuf, smb_flg,
2374 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2377 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2378 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2379 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2380 out:
2381 TALLOC_FREE(smb_fname);
2382 TALLOC_FREE(fname);
2383 TALLOC_FREE(wire_name);
2384 END_PROFILE(SMBctemp);
2385 return;
2388 /*******************************************************************
2389 Check if a user is allowed to rename a file.
2390 ********************************************************************/
2392 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2393 uint16 dirtype)
2395 if (!CAN_WRITE(conn)) {
2396 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2399 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
2400 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2401 /* Only bother to read the DOS attribute if we might deny the
2402 rename on the grounds of attribute missmatch. */
2403 uint32_t fmode = dos_mode(conn, fsp->fsp_name);
2404 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2405 return NT_STATUS_NO_SUCH_FILE;
2409 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2410 if (fsp->posix_open) {
2411 return NT_STATUS_OK;
2414 /* If no pathnames are open below this
2415 directory, allow the rename. */
2417 if (file_find_subpath(fsp)) {
2418 return NT_STATUS_ACCESS_DENIED;
2420 return NT_STATUS_OK;
2423 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2424 return NT_STATUS_OK;
2427 return NT_STATUS_ACCESS_DENIED;
2430 /*******************************************************************
2431 * unlink a file with all relevant access checks
2432 *******************************************************************/
2434 static NTSTATUS do_unlink(connection_struct *conn,
2435 struct smb_request *req,
2436 struct smb_filename *smb_fname,
2437 uint32 dirtype)
2439 uint32 fattr;
2440 files_struct *fsp;
2441 uint32 dirtype_orig = dirtype;
2442 NTSTATUS status;
2443 int ret;
2444 bool posix_paths = lp_posix_pathnames();
2446 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2447 smb_fname_str_dbg(smb_fname),
2448 dirtype));
2450 if (!CAN_WRITE(conn)) {
2451 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2454 if (posix_paths) {
2455 ret = SMB_VFS_LSTAT(conn, smb_fname);
2456 } else {
2457 ret = SMB_VFS_STAT(conn, smb_fname);
2459 if (ret != 0) {
2460 return map_nt_error_from_unix(errno);
2463 fattr = dos_mode(conn, smb_fname);
2465 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2466 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
2469 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
2470 if (!dirtype) {
2471 return NT_STATUS_NO_SUCH_FILE;
2474 if (!dir_check_ftype(conn, fattr, dirtype)) {
2475 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2476 return NT_STATUS_FILE_IS_A_DIRECTORY;
2478 return NT_STATUS_NO_SUCH_FILE;
2481 if (dirtype_orig & 0x8000) {
2482 /* These will never be set for POSIX. */
2483 return NT_STATUS_NO_SUCH_FILE;
2486 #if 0
2487 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2488 return NT_STATUS_FILE_IS_A_DIRECTORY;
2491 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2492 return NT_STATUS_NO_SUCH_FILE;
2495 if (dirtype & 0xFF00) {
2496 /* These will never be set for POSIX. */
2497 return NT_STATUS_NO_SUCH_FILE;
2500 dirtype &= 0xFF;
2501 if (!dirtype) {
2502 return NT_STATUS_NO_SUCH_FILE;
2505 /* Can't delete a directory. */
2506 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2507 return NT_STATUS_FILE_IS_A_DIRECTORY;
2509 #endif
2511 #if 0 /* JRATEST */
2512 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
2513 return NT_STATUS_OBJECT_NAME_INVALID;
2514 #endif /* JRATEST */
2516 /* On open checks the open itself will check the share mode, so
2517 don't do it here as we'll get it wrong. */
2519 status = SMB_VFS_CREATE_FILE
2520 (conn, /* conn */
2521 req, /* req */
2522 0, /* root_dir_fid */
2523 smb_fname, /* fname */
2524 DELETE_ACCESS, /* access_mask */
2525 FILE_SHARE_NONE, /* share_access */
2526 FILE_OPEN, /* create_disposition*/
2527 FILE_NON_DIRECTORY_FILE, /* create_options */
2528 /* file_attributes */
2529 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2530 FILE_ATTRIBUTE_NORMAL,
2531 0, /* oplock_request */
2532 0, /* allocation_size */
2533 0, /* private_flags */
2534 NULL, /* sd */
2535 NULL, /* ea_list */
2536 &fsp, /* result */
2537 NULL); /* pinfo */
2539 if (!NT_STATUS_IS_OK(status)) {
2540 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2541 nt_errstr(status)));
2542 return status;
2545 status = can_set_delete_on_close(fsp, fattr);
2546 if (!NT_STATUS_IS_OK(status)) {
2547 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2548 "(%s)\n",
2549 smb_fname_str_dbg(smb_fname),
2550 nt_errstr(status)));
2551 close_file(req, fsp, NORMAL_CLOSE);
2552 return status;
2555 /* The set is across all open files on this dev/inode pair. */
2556 if (!set_delete_on_close(fsp, true,
2557 conn->session_info->security_token,
2558 &conn->session_info->utok)) {
2559 close_file(req, fsp, NORMAL_CLOSE);
2560 return NT_STATUS_ACCESS_DENIED;
2563 return close_file(req, fsp, NORMAL_CLOSE);
2566 /****************************************************************************
2567 The guts of the unlink command, split out so it may be called by the NT SMB
2568 code.
2569 ****************************************************************************/
2571 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2572 uint32 dirtype, struct smb_filename *smb_fname,
2573 bool has_wild)
2575 char *fname_dir = NULL;
2576 char *fname_mask = NULL;
2577 int count=0;
2578 NTSTATUS status = NT_STATUS_OK;
2579 TALLOC_CTX *ctx = talloc_tos();
2581 /* Split up the directory from the filename/mask. */
2582 status = split_fname_dir_mask(ctx, smb_fname->base_name,
2583 &fname_dir, &fname_mask);
2584 if (!NT_STATUS_IS_OK(status)) {
2585 goto out;
2589 * We should only check the mangled cache
2590 * here if unix_convert failed. This means
2591 * that the path in 'mask' doesn't exist
2592 * on the file system and so we need to look
2593 * for a possible mangle. This patch from
2594 * Tine Smukavec <valentin.smukavec@hermes.si>.
2597 if (!VALID_STAT(smb_fname->st) &&
2598 mangle_is_mangled(fname_mask, conn->params)) {
2599 char *new_mask = NULL;
2600 mangle_lookup_name_from_8_3(ctx, fname_mask,
2601 &new_mask, conn->params);
2602 if (new_mask) {
2603 TALLOC_FREE(fname_mask);
2604 fname_mask = new_mask;
2608 if (!has_wild) {
2611 * Only one file needs to be unlinked. Append the mask back
2612 * onto the directory.
2614 TALLOC_FREE(smb_fname->base_name);
2615 if (ISDOT(fname_dir)) {
2616 /* Ensure we use canonical names on open. */
2617 smb_fname->base_name = talloc_asprintf(smb_fname,
2618 "%s",
2619 fname_mask);
2620 } else {
2621 smb_fname->base_name = talloc_asprintf(smb_fname,
2622 "%s/%s",
2623 fname_dir,
2624 fname_mask);
2626 if (!smb_fname->base_name) {
2627 status = NT_STATUS_NO_MEMORY;
2628 goto out;
2630 if (dirtype == 0) {
2631 dirtype = FILE_ATTRIBUTE_NORMAL;
2634 status = check_name(conn, smb_fname->base_name);
2635 if (!NT_STATUS_IS_OK(status)) {
2636 goto out;
2639 status = do_unlink(conn, req, smb_fname, dirtype);
2640 if (!NT_STATUS_IS_OK(status)) {
2641 goto out;
2644 count++;
2645 } else {
2646 struct smb_Dir *dir_hnd = NULL;
2647 long offset = 0;
2648 const char *dname = NULL;
2649 char *talloced = NULL;
2651 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
2652 status = NT_STATUS_OBJECT_NAME_INVALID;
2653 goto out;
2656 if (strequal(fname_mask,"????????.???")) {
2657 TALLOC_FREE(fname_mask);
2658 fname_mask = talloc_strdup(ctx, "*");
2659 if (!fname_mask) {
2660 status = NT_STATUS_NO_MEMORY;
2661 goto out;
2665 status = check_name(conn, fname_dir);
2666 if (!NT_STATUS_IS_OK(status)) {
2667 goto out;
2670 dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask,
2671 dirtype);
2672 if (dir_hnd == NULL) {
2673 status = map_nt_error_from_unix(errno);
2674 goto out;
2677 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2678 the pattern matches against the long name, otherwise the short name
2679 We don't implement this yet XXXX
2682 status = NT_STATUS_NO_SUCH_FILE;
2684 while ((dname = ReadDirName(dir_hnd, &offset,
2685 &smb_fname->st, &talloced))) {
2686 TALLOC_CTX *frame = talloc_stackframe();
2688 if (!is_visible_file(conn, fname_dir, dname,
2689 &smb_fname->st, true)) {
2690 TALLOC_FREE(frame);
2691 TALLOC_FREE(talloced);
2692 continue;
2695 /* Quick check for "." and ".." */
2696 if (ISDOT(dname) || ISDOTDOT(dname)) {
2697 TALLOC_FREE(frame);
2698 TALLOC_FREE(talloced);
2699 continue;
2702 if(!mask_match(dname, fname_mask,
2703 conn->case_sensitive)) {
2704 TALLOC_FREE(frame);
2705 TALLOC_FREE(talloced);
2706 continue;
2709 TALLOC_FREE(smb_fname->base_name);
2710 if (ISDOT(fname_dir)) {
2711 /* Ensure we use canonical names on open. */
2712 smb_fname->base_name =
2713 talloc_asprintf(smb_fname, "%s",
2714 dname);
2715 } else {
2716 smb_fname->base_name =
2717 talloc_asprintf(smb_fname, "%s/%s",
2718 fname_dir, dname);
2721 if (!smb_fname->base_name) {
2722 TALLOC_FREE(dir_hnd);
2723 status = NT_STATUS_NO_MEMORY;
2724 TALLOC_FREE(frame);
2725 TALLOC_FREE(talloced);
2726 goto out;
2729 status = check_name(conn, smb_fname->base_name);
2730 if (!NT_STATUS_IS_OK(status)) {
2731 TALLOC_FREE(dir_hnd);
2732 TALLOC_FREE(frame);
2733 TALLOC_FREE(talloced);
2734 goto out;
2737 status = do_unlink(conn, req, smb_fname, dirtype);
2738 if (!NT_STATUS_IS_OK(status)) {
2739 TALLOC_FREE(frame);
2740 TALLOC_FREE(talloced);
2741 continue;
2744 count++;
2745 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
2746 smb_fname->base_name));
2748 TALLOC_FREE(frame);
2749 TALLOC_FREE(talloced);
2751 TALLOC_FREE(dir_hnd);
2754 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
2755 status = map_nt_error_from_unix(errno);
2758 out:
2759 TALLOC_FREE(fname_dir);
2760 TALLOC_FREE(fname_mask);
2761 return status;
2764 /****************************************************************************
2765 Reply to a unlink
2766 ****************************************************************************/
2768 void reply_unlink(struct smb_request *req)
2770 connection_struct *conn = req->conn;
2771 char *name = NULL;
2772 struct smb_filename *smb_fname = NULL;
2773 uint32 dirtype;
2774 NTSTATUS status;
2775 bool path_contains_wcard = False;
2776 TALLOC_CTX *ctx = talloc_tos();
2778 START_PROFILE(SMBunlink);
2780 if (req->wct < 1) {
2781 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2782 goto out;
2785 dirtype = SVAL(req->vwv+0, 0);
2787 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
2788 STR_TERMINATE, &status,
2789 &path_contains_wcard);
2790 if (!NT_STATUS_IS_OK(status)) {
2791 reply_nterror(req, status);
2792 goto out;
2795 status = filename_convert(ctx, conn,
2796 req->flags2 & FLAGS2_DFS_PATHNAMES,
2797 name,
2798 UCF_COND_ALLOW_WCARD_LCOMP,
2799 &path_contains_wcard,
2800 &smb_fname);
2801 if (!NT_STATUS_IS_OK(status)) {
2802 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2803 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2804 ERRSRV, ERRbadpath);
2805 goto out;
2807 reply_nterror(req, status);
2808 goto out;
2811 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
2813 status = unlink_internals(conn, req, dirtype, smb_fname,
2814 path_contains_wcard);
2815 if (!NT_STATUS_IS_OK(status)) {
2816 if (open_was_deferred(req->mid)) {
2817 /* We have re-scheduled this call. */
2818 goto out;
2820 reply_nterror(req, status);
2821 goto out;
2824 reply_outbuf(req, 0, 0);
2825 out:
2826 TALLOC_FREE(smb_fname);
2827 END_PROFILE(SMBunlink);
2828 return;
2831 /****************************************************************************
2832 Fail for readbraw.
2833 ****************************************************************************/
2835 static void fail_readraw(void)
2837 const char *errstr = talloc_asprintf(talloc_tos(),
2838 "FAIL ! reply_readbraw: socket write fail (%s)",
2839 strerror(errno));
2840 if (!errstr) {
2841 errstr = "";
2843 exit_server_cleanly(errstr);
2846 /****************************************************************************
2847 Fake (read/write) sendfile. Returns -1 on read or write fail.
2848 ****************************************************************************/
2850 ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos, size_t nread)
2852 size_t bufsize;
2853 size_t tosend = nread;
2854 char *buf;
2856 if (nread == 0) {
2857 return 0;
2860 bufsize = MIN(nread, 65536);
2862 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
2863 return -1;
2866 while (tosend > 0) {
2867 ssize_t ret;
2868 size_t cur_read;
2870 if (tosend > bufsize) {
2871 cur_read = bufsize;
2872 } else {
2873 cur_read = tosend;
2875 ret = read_file(fsp,buf,startpos,cur_read);
2876 if (ret == -1) {
2877 SAFE_FREE(buf);
2878 return -1;
2881 /* If we had a short read, fill with zeros. */
2882 if (ret < cur_read) {
2883 memset(buf + ret, '\0', cur_read - ret);
2886 if (write_data(fsp->conn->sconn->sock, buf, cur_read)
2887 != cur_read) {
2888 char addr[INET6_ADDRSTRLEN];
2890 * Try and give an error message saying what
2891 * client failed.
2893 DEBUG(0, ("write_data failed for client %s. "
2894 "Error %s\n",
2895 get_peer_addr(fsp->conn->sconn->sock, addr,
2896 sizeof(addr)),
2897 strerror(errno)));
2898 SAFE_FREE(buf);
2899 return -1;
2901 tosend -= cur_read;
2902 startpos += cur_read;
2905 SAFE_FREE(buf);
2906 return (ssize_t)nread;
2909 /****************************************************************************
2910 Deal with the case of sendfile reading less bytes from the file than
2911 requested. Fill with zeros (all we can do).
2912 ****************************************************************************/
2914 void sendfile_short_send(files_struct *fsp,
2915 ssize_t nread,
2916 size_t headersize,
2917 size_t smb_maxcnt)
2919 #define SHORT_SEND_BUFSIZE 1024
2920 if (nread < headersize) {
2921 DEBUG(0,("sendfile_short_send: sendfile failed to send "
2922 "header for file %s (%s). Terminating\n",
2923 fsp_str_dbg(fsp), strerror(errno)));
2924 exit_server_cleanly("sendfile_short_send failed");
2927 nread -= headersize;
2929 if (nread < smb_maxcnt) {
2930 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
2931 if (!buf) {
2932 exit_server_cleanly("sendfile_short_send: "
2933 "malloc failed");
2936 DEBUG(0,("sendfile_short_send: filling truncated file %s "
2937 "with zeros !\n", fsp_str_dbg(fsp)));
2939 while (nread < smb_maxcnt) {
2941 * We asked for the real file size and told sendfile
2942 * to not go beyond the end of the file. But it can
2943 * happen that in between our fstat call and the
2944 * sendfile call the file was truncated. This is very
2945 * bad because we have already announced the larger
2946 * number of bytes to the client.
2948 * The best we can do now is to send 0-bytes, just as
2949 * a read from a hole in a sparse file would do.
2951 * This should happen rarely enough that I don't care
2952 * about efficiency here :-)
2954 size_t to_write;
2956 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
2957 if (write_data(fsp->conn->sconn->sock, buf, to_write)
2958 != to_write) {
2959 char addr[INET6_ADDRSTRLEN];
2961 * Try and give an error message saying what
2962 * client failed.
2964 DEBUG(0, ("write_data failed for client %s. "
2965 "Error %s\n",
2966 get_peer_addr(
2967 fsp->conn->sconn->sock, addr,
2968 sizeof(addr)),
2969 strerror(errno)));
2970 exit_server_cleanly("sendfile_short_send: "
2971 "write_data failed");
2973 nread += to_write;
2975 SAFE_FREE(buf);
2979 /****************************************************************************
2980 Return a readbraw error (4 bytes of zero).
2981 ****************************************************************************/
2983 static void reply_readbraw_error(struct smbd_server_connection *sconn)
2985 char header[4];
2987 SIVAL(header,0,0);
2989 smbd_lock_socket(sconn);
2990 if (write_data(sconn->sock,header,4) != 4) {
2991 char addr[INET6_ADDRSTRLEN];
2993 * Try and give an error message saying what
2994 * client failed.
2996 DEBUG(0, ("write_data failed for client %s. "
2997 "Error %s\n",
2998 get_peer_addr(sconn->sock, addr, sizeof(addr)),
2999 strerror(errno)));
3001 fail_readraw();
3003 smbd_unlock_socket(sconn);
3006 /****************************************************************************
3007 Use sendfile in readbraw.
3008 ****************************************************************************/
3010 static void send_file_readbraw(connection_struct *conn,
3011 struct smb_request *req,
3012 files_struct *fsp,
3013 SMB_OFF_T startpos,
3014 size_t nread,
3015 ssize_t mincount)
3017 struct smbd_server_connection *sconn = req->sconn;
3018 char *outbuf = NULL;
3019 ssize_t ret=0;
3022 * We can only use sendfile on a non-chained packet
3023 * but we can use on a non-oplocked file. tridge proved this
3024 * on a train in Germany :-). JRA.
3025 * reply_readbraw has already checked the length.
3028 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3029 (fsp->wcp == NULL) &&
3030 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3031 ssize_t sendfile_read = -1;
3032 char header[4];
3033 DATA_BLOB header_blob;
3035 _smb_setlen(header,nread);
3036 header_blob = data_blob_const(header, 4);
3038 sendfile_read = SMB_VFS_SENDFILE(sconn->sock, fsp,
3039 &header_blob, startpos,
3040 nread);
3041 if (sendfile_read == -1) {
3042 /* Returning ENOSYS means no data at all was sent.
3043 * Do this as a normal read. */
3044 if (errno == ENOSYS) {
3045 goto normal_readbraw;
3049 * Special hack for broken Linux with no working sendfile. If we
3050 * return EINTR we sent the header but not the rest of the data.
3051 * Fake this up by doing read/write calls.
3053 if (errno == EINTR) {
3054 /* Ensure we don't do this again. */
3055 set_use_sendfile(SNUM(conn), False);
3056 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3058 if (fake_sendfile(fsp, startpos, nread) == -1) {
3059 DEBUG(0,("send_file_readbraw: "
3060 "fake_sendfile failed for "
3061 "file %s (%s).\n",
3062 fsp_str_dbg(fsp),
3063 strerror(errno)));
3064 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3066 return;
3069 DEBUG(0,("send_file_readbraw: sendfile failed for "
3070 "file %s (%s). Terminating\n",
3071 fsp_str_dbg(fsp), strerror(errno)));
3072 exit_server_cleanly("send_file_readbraw sendfile failed");
3073 } else if (sendfile_read == 0) {
3075 * Some sendfile implementations return 0 to indicate
3076 * that there was a short read, but nothing was
3077 * actually written to the socket. In this case,
3078 * fallback to the normal read path so the header gets
3079 * the correct byte count.
3081 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3082 "bytes falling back to the normal read: "
3083 "%s\n", fsp_str_dbg(fsp)));
3084 goto normal_readbraw;
3087 /* Deal with possible short send. */
3088 if (sendfile_read != 4+nread) {
3089 sendfile_short_send(fsp, sendfile_read, 4, nread);
3091 return;
3094 normal_readbraw:
3096 outbuf = TALLOC_ARRAY(NULL, char, nread+4);
3097 if (!outbuf) {
3098 DEBUG(0,("send_file_readbraw: TALLOC_ARRAY failed for size %u.\n",
3099 (unsigned)(nread+4)));
3100 reply_readbraw_error(sconn);
3101 return;
3104 if (nread > 0) {
3105 ret = read_file(fsp,outbuf+4,startpos,nread);
3106 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3107 if (ret < mincount)
3108 ret = 0;
3109 #else
3110 if (ret < nread)
3111 ret = 0;
3112 #endif
3115 _smb_setlen(outbuf,ret);
3116 if (write_data(sconn->sock, outbuf, 4+ret) != 4+ret) {
3117 char addr[INET6_ADDRSTRLEN];
3119 * Try and give an error message saying what
3120 * client failed.
3122 DEBUG(0, ("write_data failed for client %s. "
3123 "Error %s\n",
3124 get_peer_addr(fsp->conn->sconn->sock, addr,
3125 sizeof(addr)),
3126 strerror(errno)));
3128 fail_readraw();
3131 TALLOC_FREE(outbuf);
3134 /****************************************************************************
3135 Reply to a readbraw (core+ protocol).
3136 ****************************************************************************/
3138 void reply_readbraw(struct smb_request *req)
3140 connection_struct *conn = req->conn;
3141 struct smbd_server_connection *sconn = req->sconn;
3142 ssize_t maxcount,mincount;
3143 size_t nread = 0;
3144 SMB_OFF_T startpos;
3145 files_struct *fsp;
3146 struct lock_struct lock;
3147 SMB_OFF_T size = 0;
3149 START_PROFILE(SMBreadbraw);
3151 if (srv_is_signing_active(sconn) || req->encrypted) {
3152 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3153 "raw reads/writes are disallowed.");
3156 if (req->wct < 8) {
3157 reply_readbraw_error(sconn);
3158 END_PROFILE(SMBreadbraw);
3159 return;
3162 if (sconn->smb1.echo_handler.trusted_fde) {
3163 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3164 "'async smb echo handler = yes'\n"));
3165 reply_readbraw_error(sconn);
3166 END_PROFILE(SMBreadbraw);
3167 return;
3171 * Special check if an oplock break has been issued
3172 * and the readraw request croses on the wire, we must
3173 * return a zero length response here.
3176 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3179 * We have to do a check_fsp by hand here, as
3180 * we must always return 4 zero bytes on error,
3181 * not a NTSTATUS.
3184 if (!fsp || !conn || conn != fsp->conn ||
3185 req->vuid != fsp->vuid ||
3186 fsp->is_directory || fsp->fh->fd == -1) {
3188 * fsp could be NULL here so use the value from the packet. JRA.
3190 DEBUG(3,("reply_readbraw: fnum %d not valid "
3191 "- cache prime?\n",
3192 (int)SVAL(req->vwv+0, 0)));
3193 reply_readbraw_error(sconn);
3194 END_PROFILE(SMBreadbraw);
3195 return;
3198 /* Do a "by hand" version of CHECK_READ. */
3199 if (!(fsp->can_read ||
3200 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3201 (fsp->access_mask & FILE_EXECUTE)))) {
3202 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3203 (int)SVAL(req->vwv+0, 0)));
3204 reply_readbraw_error(sconn);
3205 END_PROFILE(SMBreadbraw);
3206 return;
3209 flush_write_cache(fsp, READRAW_FLUSH);
3211 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3212 if(req->wct == 10) {
3214 * This is a large offset (64 bit) read.
3216 #ifdef LARGE_SMB_OFF_T
3218 startpos |= (((SMB_OFF_T)IVAL(req->vwv+8, 0)) << 32);
3220 #else /* !LARGE_SMB_OFF_T */
3223 * Ensure we haven't been sent a >32 bit offset.
3226 if(IVAL(req->vwv+8, 0) != 0) {
3227 DEBUG(0,("reply_readbraw: large offset "
3228 "(%x << 32) used and we don't support "
3229 "64 bit offsets.\n",
3230 (unsigned int)IVAL(req->vwv+8, 0) ));
3231 reply_readbraw_error(sconn);
3232 END_PROFILE(SMBreadbraw);
3233 return;
3236 #endif /* LARGE_SMB_OFF_T */
3238 if(startpos < 0) {
3239 DEBUG(0,("reply_readbraw: negative 64 bit "
3240 "readraw offset (%.0f) !\n",
3241 (double)startpos ));
3242 reply_readbraw_error(sconn);
3243 END_PROFILE(SMBreadbraw);
3244 return;
3248 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3249 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3251 /* ensure we don't overrun the packet size */
3252 maxcount = MIN(65535,maxcount);
3254 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3255 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3256 &lock);
3258 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3259 reply_readbraw_error(sconn);
3260 END_PROFILE(SMBreadbraw);
3261 return;
3264 if (fsp_stat(fsp) == 0) {
3265 size = fsp->fsp_name->st.st_ex_size;
3268 if (startpos >= size) {
3269 nread = 0;
3270 } else {
3271 nread = MIN(maxcount,(size - startpos));
3274 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3275 if (nread < mincount)
3276 nread = 0;
3277 #endif
3279 DEBUG( 3, ( "reply_readbraw: fnum=%d start=%.0f max=%lu "
3280 "min=%lu nread=%lu\n",
3281 fsp->fnum, (double)startpos,
3282 (unsigned long)maxcount,
3283 (unsigned long)mincount,
3284 (unsigned long)nread ) );
3286 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3288 DEBUG(5,("reply_readbraw finished\n"));
3290 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3292 END_PROFILE(SMBreadbraw);
3293 return;
3296 #undef DBGC_CLASS
3297 #define DBGC_CLASS DBGC_LOCKING
3299 /****************************************************************************
3300 Reply to a lockread (core+ protocol).
3301 ****************************************************************************/
3303 void reply_lockread(struct smb_request *req)
3305 connection_struct *conn = req->conn;
3306 ssize_t nread = -1;
3307 char *data;
3308 SMB_OFF_T startpos;
3309 size_t numtoread;
3310 NTSTATUS status;
3311 files_struct *fsp;
3312 struct byte_range_lock *br_lck = NULL;
3313 char *p = NULL;
3314 struct smbd_server_connection *sconn = req->sconn;
3316 START_PROFILE(SMBlockread);
3318 if (req->wct < 5) {
3319 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3320 END_PROFILE(SMBlockread);
3321 return;
3324 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3326 if (!check_fsp(conn, req, fsp)) {
3327 END_PROFILE(SMBlockread);
3328 return;
3331 if (!CHECK_READ(fsp,req)) {
3332 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3333 END_PROFILE(SMBlockread);
3334 return;
3337 numtoread = SVAL(req->vwv+1, 0);
3338 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3340 numtoread = MIN(BUFFER_SIZE - (smb_size + 3*2 + 3), numtoread);
3342 reply_outbuf(req, 5, numtoread + 3);
3344 data = smb_buf(req->outbuf) + 3;
3347 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3348 * protocol request that predates the read/write lock concept.
3349 * Thus instead of asking for a read lock here we need to ask
3350 * for a write lock. JRA.
3351 * Note that the requested lock size is unaffected by max_recv.
3354 br_lck = do_lock(req->sconn->msg_ctx,
3355 fsp,
3356 (uint64_t)req->smbpid,
3357 (uint64_t)numtoread,
3358 (uint64_t)startpos,
3359 WRITE_LOCK,
3360 WINDOWS_LOCK,
3361 False, /* Non-blocking lock. */
3362 &status,
3363 NULL,
3364 NULL);
3365 TALLOC_FREE(br_lck);
3367 if (NT_STATUS_V(status)) {
3368 reply_nterror(req, status);
3369 END_PROFILE(SMBlockread);
3370 return;
3374 * However the requested READ size IS affected by max_recv. Insanity.... JRA.
3377 if (numtoread > sconn->smb1.negprot.max_recv) {
3378 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \
3379 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3380 (unsigned int)numtoread,
3381 (unsigned int)sconn->smb1.negprot.max_recv));
3382 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3384 nread = read_file(fsp,data,startpos,numtoread);
3386 if (nread < 0) {
3387 reply_nterror(req, map_nt_error_from_unix(errno));
3388 END_PROFILE(SMBlockread);
3389 return;
3392 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3394 SSVAL(req->outbuf,smb_vwv0,nread);
3395 SSVAL(req->outbuf,smb_vwv5,nread+3);
3396 p = smb_buf(req->outbuf);
3397 SCVAL(p,0,0); /* pad byte. */
3398 SSVAL(p,1,nread);
3400 DEBUG(3,("lockread fnum=%d num=%d nread=%d\n",
3401 fsp->fnum, (int)numtoread, (int)nread));
3403 END_PROFILE(SMBlockread);
3404 return;
3407 #undef DBGC_CLASS
3408 #define DBGC_CLASS DBGC_ALL
3410 /****************************************************************************
3411 Reply to a read.
3412 ****************************************************************************/
3414 void reply_read(struct smb_request *req)
3416 connection_struct *conn = req->conn;
3417 size_t numtoread;
3418 ssize_t nread = 0;
3419 char *data;
3420 SMB_OFF_T startpos;
3421 int outsize = 0;
3422 files_struct *fsp;
3423 struct lock_struct lock;
3424 struct smbd_server_connection *sconn = req->sconn;
3426 START_PROFILE(SMBread);
3428 if (req->wct < 3) {
3429 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3430 END_PROFILE(SMBread);
3431 return;
3434 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3436 if (!check_fsp(conn, req, fsp)) {
3437 END_PROFILE(SMBread);
3438 return;
3441 if (!CHECK_READ(fsp,req)) {
3442 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3443 END_PROFILE(SMBread);
3444 return;
3447 numtoread = SVAL(req->vwv+1, 0);
3448 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3450 numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
3453 * The requested read size cannot be greater than max_recv. JRA.
3455 if (numtoread > sconn->smb1.negprot.max_recv) {
3456 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \
3457 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3458 (unsigned int)numtoread,
3459 (unsigned int)sconn->smb1.negprot.max_recv));
3460 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3463 reply_outbuf(req, 5, numtoread+3);
3465 data = smb_buf(req->outbuf) + 3;
3467 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3468 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3469 &lock);
3471 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3472 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3473 END_PROFILE(SMBread);
3474 return;
3477 if (numtoread > 0)
3478 nread = read_file(fsp,data,startpos,numtoread);
3480 if (nread < 0) {
3481 reply_nterror(req, map_nt_error_from_unix(errno));
3482 goto strict_unlock;
3485 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3487 SSVAL(req->outbuf,smb_vwv0,nread);
3488 SSVAL(req->outbuf,smb_vwv5,nread+3);
3489 SCVAL(smb_buf(req->outbuf),0,1);
3490 SSVAL(smb_buf(req->outbuf),1,nread);
3492 DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
3493 fsp->fnum, (int)numtoread, (int)nread ) );
3495 strict_unlock:
3496 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3498 END_PROFILE(SMBread);
3499 return;
3502 /****************************************************************************
3503 Setup readX header.
3504 ****************************************************************************/
3506 static int setup_readX_header(struct smb_request *req, char *outbuf,
3507 size_t smb_maxcnt)
3509 int outsize;
3510 char *data;
3512 outsize = srv_set_message(outbuf,12,smb_maxcnt,False);
3513 data = smb_buf(outbuf);
3515 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3517 SCVAL(outbuf,smb_vwv0,0xFF);
3518 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3519 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3520 SSVAL(outbuf,smb_vwv6,
3521 req_wct_ofs(req)
3522 + 1 /* the wct field */
3523 + 12 * sizeof(uint16_t) /* vwv */
3524 + 2); /* the buflen field */
3525 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3526 SSVAL(outbuf,smb_vwv11,smb_maxcnt);
3527 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3528 _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
3529 return outsize;
3532 /****************************************************************************
3533 Reply to a read and X - possibly using sendfile.
3534 ****************************************************************************/
3536 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3537 files_struct *fsp, SMB_OFF_T startpos,
3538 size_t smb_maxcnt)
3540 ssize_t nread = -1;
3541 struct lock_struct lock;
3542 int saved_errno = 0;
3544 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3545 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3546 &lock);
3548 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3549 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3550 return;
3554 * We can only use sendfile on a non-chained packet
3555 * but we can use on a non-oplocked file. tridge proved this
3556 * on a train in Germany :-). JRA.
3559 if (!req_is_in_chain(req) &&
3560 !req->encrypted && (fsp->base_fsp == NULL) &&
3561 (fsp->wcp == NULL) &&
3562 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3563 uint8 headerbuf[smb_size + 12 * 2];
3564 DATA_BLOB header;
3566 if(fsp_stat(fsp) == -1) {
3567 reply_nterror(req, map_nt_error_from_unix(errno));
3568 goto strict_unlock;
3571 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3572 (startpos > fsp->fsp_name->st.st_ex_size) ||
3573 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3575 * We already know that we would do a short read, so don't
3576 * try the sendfile() path.
3578 goto nosendfile_read;
3582 * Set up the packet header before send. We
3583 * assume here the sendfile will work (get the
3584 * correct amount of data).
3587 header = data_blob_const(headerbuf, sizeof(headerbuf));
3589 construct_reply_common_req(req, (char *)headerbuf);
3590 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3592 nread = SMB_VFS_SENDFILE(req->sconn->sock, fsp, &header,
3593 startpos, smb_maxcnt);
3594 if (nread == -1) {
3595 /* Returning ENOSYS means no data at all was sent.
3596 Do this as a normal read. */
3597 if (errno == ENOSYS) {
3598 goto normal_read;
3602 * Special hack for broken Linux with no working sendfile. If we
3603 * return EINTR we sent the header but not the rest of the data.
3604 * Fake this up by doing read/write calls.
3607 if (errno == EINTR) {
3608 /* Ensure we don't do this again. */
3609 set_use_sendfile(SNUM(conn), False);
3610 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3611 nread = fake_sendfile(fsp, startpos,
3612 smb_maxcnt);
3613 if (nread == -1) {
3614 DEBUG(0,("send_file_readX: "
3615 "fake_sendfile failed for "
3616 "file %s (%s).\n",
3617 fsp_str_dbg(fsp),
3618 strerror(errno)));
3619 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3621 DEBUG( 3, ( "send_file_readX: fake_sendfile fnum=%d max=%d nread=%d\n",
3622 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3623 /* No outbuf here means successful sendfile. */
3624 goto strict_unlock;
3627 DEBUG(0,("send_file_readX: sendfile failed for file "
3628 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3629 strerror(errno)));
3630 exit_server_cleanly("send_file_readX sendfile failed");
3631 } else if (nread == 0) {
3633 * Some sendfile implementations return 0 to indicate
3634 * that there was a short read, but nothing was
3635 * actually written to the socket. In this case,
3636 * fallback to the normal read path so the header gets
3637 * the correct byte count.
3639 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
3640 "falling back to the normal read: %s\n",
3641 fsp_str_dbg(fsp)));
3642 goto normal_read;
3645 DEBUG( 3, ( "send_file_readX: sendfile fnum=%d max=%d nread=%d\n",
3646 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3648 /* Deal with possible short send. */
3649 if (nread != smb_maxcnt + sizeof(headerbuf)) {
3650 sendfile_short_send(fsp, nread, sizeof(headerbuf), smb_maxcnt);
3652 /* No outbuf here means successful sendfile. */
3653 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
3654 SMB_PERFCOUNT_END(&req->pcd);
3655 goto strict_unlock;
3658 normal_read:
3660 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3661 uint8 headerbuf[smb_size + 2*12];
3663 construct_reply_common_req(req, (char *)headerbuf);
3664 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3666 /* Send out the header. */
3667 if (write_data(req->sconn->sock, (char *)headerbuf,
3668 sizeof(headerbuf)) != sizeof(headerbuf)) {
3670 char addr[INET6_ADDRSTRLEN];
3672 * Try and give an error message saying what
3673 * client failed.
3675 DEBUG(0, ("write_data failed for client %s. "
3676 "Error %s\n",
3677 get_peer_addr(req->sconn->sock, addr,
3678 sizeof(addr)),
3679 strerror(errno)));
3681 DEBUG(0,("send_file_readX: write_data failed for file "
3682 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3683 strerror(errno)));
3684 exit_server_cleanly("send_file_readX sendfile failed");
3686 nread = fake_sendfile(fsp, startpos, smb_maxcnt);
3687 if (nread == -1) {
3688 DEBUG(0,("send_file_readX: fake_sendfile failed for "
3689 "file %s (%s).\n", fsp_str_dbg(fsp),
3690 strerror(errno)));
3691 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3693 goto strict_unlock;
3696 nosendfile_read:
3698 reply_outbuf(req, 12, smb_maxcnt);
3700 nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt);
3701 saved_errno = errno;
3703 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3705 if (nread < 0) {
3706 reply_nterror(req, map_nt_error_from_unix(saved_errno));
3707 return;
3710 setup_readX_header(req, (char *)req->outbuf, nread);
3712 DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
3713 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3715 chain_reply(req);
3716 return;
3718 strict_unlock:
3719 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3720 TALLOC_FREE(req->outbuf);
3721 return;
3724 /****************************************************************************
3725 Reply to a read and X.
3726 ****************************************************************************/
3728 void reply_read_and_X(struct smb_request *req)
3730 connection_struct *conn = req->conn;
3731 files_struct *fsp;
3732 SMB_OFF_T startpos;
3733 size_t smb_maxcnt;
3734 bool big_readX = False;
3735 #if 0
3736 size_t smb_mincnt = SVAL(req->vwv+6, 0);
3737 #endif
3739 START_PROFILE(SMBreadX);
3741 if ((req->wct != 10) && (req->wct != 12)) {
3742 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3743 return;
3746 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
3747 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3748 smb_maxcnt = SVAL(req->vwv+5, 0);
3750 /* If it's an IPC, pass off the pipe handler. */
3751 if (IS_IPC(conn)) {
3752 reply_pipe_read_and_X(req);
3753 END_PROFILE(SMBreadX);
3754 return;
3757 if (!check_fsp(conn, req, fsp)) {
3758 END_PROFILE(SMBreadX);
3759 return;
3762 if (!CHECK_READ(fsp,req)) {
3763 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3764 END_PROFILE(SMBreadX);
3765 return;
3768 if (global_client_caps & CAP_LARGE_READX) {
3769 size_t upper_size = SVAL(req->vwv+7, 0);
3770 smb_maxcnt |= (upper_size<<16);
3771 if (upper_size > 1) {
3772 /* Can't do this on a chained packet. */
3773 if ((CVAL(req->vwv+0, 0) != 0xFF)) {
3774 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3775 END_PROFILE(SMBreadX);
3776 return;
3778 /* We currently don't do this on signed or sealed data. */
3779 if (srv_is_signing_active(req->sconn) || req->encrypted) {
3780 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3781 END_PROFILE(SMBreadX);
3782 return;
3784 /* Is there room in the reply for this data ? */
3785 if (smb_maxcnt > (0xFFFFFF - (smb_size -4 + 12*2))) {
3786 reply_nterror(req,
3787 NT_STATUS_INVALID_PARAMETER);
3788 END_PROFILE(SMBreadX);
3789 return;
3791 big_readX = True;
3795 if (req->wct == 12) {
3796 #ifdef LARGE_SMB_OFF_T
3798 * This is a large offset (64 bit) read.
3800 startpos |= (((SMB_OFF_T)IVAL(req->vwv+10, 0)) << 32);
3802 #else /* !LARGE_SMB_OFF_T */
3805 * Ensure we haven't been sent a >32 bit offset.
3808 if(IVAL(req->vwv+10, 0) != 0) {
3809 DEBUG(0,("reply_read_and_X - large offset (%x << 32) "
3810 "used and we don't support 64 bit offsets.\n",
3811 (unsigned int)IVAL(req->vwv+10, 0) ));
3812 END_PROFILE(SMBreadX);
3813 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3814 return;
3817 #endif /* LARGE_SMB_OFF_T */
3821 if (!big_readX) {
3822 NTSTATUS status = schedule_aio_read_and_X(conn,
3823 req,
3824 fsp,
3825 startpos,
3826 smb_maxcnt);
3827 if (NT_STATUS_IS_OK(status)) {
3828 /* Read scheduled - we're done. */
3829 goto out;
3831 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
3832 /* Real error - report to client. */
3833 END_PROFILE(SMBreadX);
3834 reply_nterror(req, status);
3835 return;
3837 /* NT_STATUS_RETRY - fall back to sync read. */
3840 smbd_lock_socket(req->sconn);
3841 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
3842 smbd_unlock_socket(req->sconn);
3844 out:
3845 END_PROFILE(SMBreadX);
3846 return;
3849 /****************************************************************************
3850 Error replies to writebraw must have smb_wct == 1. Fix this up.
3851 ****************************************************************************/
3853 void error_to_writebrawerr(struct smb_request *req)
3855 uint8 *old_outbuf = req->outbuf;
3857 reply_outbuf(req, 1, 0);
3859 memcpy(req->outbuf, old_outbuf, smb_size);
3860 TALLOC_FREE(old_outbuf);
3863 /****************************************************************************
3864 Read 4 bytes of a smb packet and return the smb length of the packet.
3865 Store the result in the buffer. This version of the function will
3866 never return a session keepalive (length of zero).
3867 Timeout is in milliseconds.
3868 ****************************************************************************/
3870 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
3871 size_t *len)
3873 uint8_t msgtype = SMBkeepalive;
3875 while (msgtype == SMBkeepalive) {
3876 NTSTATUS status;
3878 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
3879 len);
3880 if (!NT_STATUS_IS_OK(status)) {
3881 char addr[INET6_ADDRSTRLEN];
3882 /* Try and give an error message
3883 * saying what client failed. */
3884 DEBUG(0, ("read_fd_with_timeout failed for "
3885 "client %s read error = %s.\n",
3886 get_peer_addr(fd,addr,sizeof(addr)),
3887 nt_errstr(status)));
3888 return status;
3891 msgtype = CVAL(inbuf, 0);
3894 DEBUG(10,("read_smb_length: got smb length of %lu\n",
3895 (unsigned long)len));
3897 return NT_STATUS_OK;
3900 /****************************************************************************
3901 Reply to a writebraw (core+ or LANMAN1.0 protocol).
3902 ****************************************************************************/
3904 void reply_writebraw(struct smb_request *req)
3906 connection_struct *conn = req->conn;
3907 char *buf = NULL;
3908 ssize_t nwritten=0;
3909 ssize_t total_written=0;
3910 size_t numtowrite=0;
3911 size_t tcount;
3912 SMB_OFF_T startpos;
3913 char *data=NULL;
3914 bool write_through;
3915 files_struct *fsp;
3916 struct lock_struct lock;
3917 NTSTATUS status;
3919 START_PROFILE(SMBwritebraw);
3922 * If we ever reply with an error, it must have the SMB command
3923 * type of SMBwritec, not SMBwriteBraw, as this tells the client
3924 * we're finished.
3926 SCVAL(req->inbuf,smb_com,SMBwritec);
3928 if (srv_is_signing_active(req->sconn)) {
3929 END_PROFILE(SMBwritebraw);
3930 exit_server_cleanly("reply_writebraw: SMB signing is active - "
3931 "raw reads/writes are disallowed.");
3934 if (req->wct < 12) {
3935 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3936 error_to_writebrawerr(req);
3937 END_PROFILE(SMBwritebraw);
3938 return;
3941 if (req->sconn->smb1.echo_handler.trusted_fde) {
3942 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
3943 "'async smb echo handler = yes'\n"));
3944 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3945 error_to_writebrawerr(req);
3946 END_PROFILE(SMBwritebraw);
3947 return;
3950 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3951 if (!check_fsp(conn, req, fsp)) {
3952 error_to_writebrawerr(req);
3953 END_PROFILE(SMBwritebraw);
3954 return;
3957 if (!CHECK_WRITE(fsp)) {
3958 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3959 error_to_writebrawerr(req);
3960 END_PROFILE(SMBwritebraw);
3961 return;
3964 tcount = IVAL(req->vwv+1, 0);
3965 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3966 write_through = BITSETW(req->vwv+7,0);
3968 /* We have to deal with slightly different formats depending
3969 on whether we are using the core+ or lanman1.0 protocol */
3971 if(get_Protocol() <= PROTOCOL_COREPLUS) {
3972 numtowrite = SVAL(smb_buf(req->inbuf),-2);
3973 data = smb_buf(req->inbuf);
3974 } else {
3975 numtowrite = SVAL(req->vwv+10, 0);
3976 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
3979 /* Ensure we don't write bytes past the end of this packet. */
3980 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
3981 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3982 error_to_writebrawerr(req);
3983 END_PROFILE(SMBwritebraw);
3984 return;
3987 if (!fsp->print_file) {
3988 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3989 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
3990 &lock);
3992 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3993 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3994 error_to_writebrawerr(req);
3995 END_PROFILE(SMBwritebraw);
3996 return;
4000 if (numtowrite>0) {
4001 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4004 DEBUG(3,("reply_writebraw: initial write fnum=%d start=%.0f num=%d "
4005 "wrote=%d sync=%d\n",
4006 fsp->fnum, (double)startpos, (int)numtowrite,
4007 (int)nwritten, (int)write_through));
4009 if (nwritten < (ssize_t)numtowrite) {
4010 reply_nterror(req, NT_STATUS_DISK_FULL);
4011 error_to_writebrawerr(req);
4012 goto strict_unlock;
4015 total_written = nwritten;
4017 /* Allocate a buffer of 64k + length. */
4018 buf = TALLOC_ARRAY(NULL, char, 65540);
4019 if (!buf) {
4020 reply_nterror(req, NT_STATUS_NO_MEMORY);
4021 error_to_writebrawerr(req);
4022 goto strict_unlock;
4025 /* Return a SMBwritebraw message to the redirector to tell
4026 * it to send more bytes */
4028 memcpy(buf, req->inbuf, smb_size);
4029 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4030 SCVAL(buf,smb_com,SMBwritebraw);
4031 SSVALS(buf,smb_vwv0,0xFFFF);
4032 show_msg(buf);
4033 if (!srv_send_smb(req->sconn,
4034 buf,
4035 false, 0, /* no signing */
4036 IS_CONN_ENCRYPTED(conn),
4037 &req->pcd)) {
4038 exit_server_cleanly("reply_writebraw: srv_send_smb "
4039 "failed.");
4042 /* Now read the raw data into the buffer and write it */
4043 status = read_smb_length(req->sconn->sock, buf, SMB_SECONDARY_WAIT,
4044 &numtowrite);
4045 if (!NT_STATUS_IS_OK(status)) {
4046 exit_server_cleanly("secondary writebraw failed");
4049 /* Set up outbuf to return the correct size */
4050 reply_outbuf(req, 1, 0);
4052 if (numtowrite != 0) {
4054 if (numtowrite > 0xFFFF) {
4055 DEBUG(0,("reply_writebraw: Oversize secondary write "
4056 "raw requested (%u). Terminating\n",
4057 (unsigned int)numtowrite ));
4058 exit_server_cleanly("secondary writebraw failed");
4061 if (tcount > nwritten+numtowrite) {
4062 DEBUG(3,("reply_writebraw: Client overestimated the "
4063 "write %d %d %d\n",
4064 (int)tcount,(int)nwritten,(int)numtowrite));
4067 status = read_data(req->sconn->sock, buf+4, numtowrite);
4069 if (!NT_STATUS_IS_OK(status)) {
4070 char addr[INET6_ADDRSTRLEN];
4071 /* Try and give an error message
4072 * saying what client failed. */
4073 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4074 "raw read failed (%s) for client %s. "
4075 "Terminating\n", nt_errstr(status),
4076 get_peer_addr(req->sconn->sock, addr,
4077 sizeof(addr))));
4078 exit_server_cleanly("secondary writebraw failed");
4081 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4082 if (nwritten == -1) {
4083 TALLOC_FREE(buf);
4084 reply_nterror(req, map_nt_error_from_unix(errno));
4085 error_to_writebrawerr(req);
4086 goto strict_unlock;
4089 if (nwritten < (ssize_t)numtowrite) {
4090 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4091 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4094 if (nwritten > 0) {
4095 total_written += nwritten;
4099 TALLOC_FREE(buf);
4100 SSVAL(req->outbuf,smb_vwv0,total_written);
4102 status = sync_file(conn, fsp, write_through);
4103 if (!NT_STATUS_IS_OK(status)) {
4104 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4105 fsp_str_dbg(fsp), nt_errstr(status)));
4106 reply_nterror(req, status);
4107 error_to_writebrawerr(req);
4108 goto strict_unlock;
4111 DEBUG(3,("reply_writebraw: secondart write fnum=%d start=%.0f num=%d "
4112 "wrote=%d\n",
4113 fsp->fnum, (double)startpos, (int)numtowrite,
4114 (int)total_written));
4116 if (!fsp->print_file) {
4117 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4120 /* We won't return a status if write through is not selected - this
4121 * follows what WfWg does */
4122 END_PROFILE(SMBwritebraw);
4124 if (!write_through && total_written==tcount) {
4126 #if RABBIT_PELLET_FIX
4128 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4129 * sending a SMBkeepalive. Thanks to DaveCB at Sun for this.
4130 * JRA.
4132 if (!send_keepalive(req->sconn->sock)) {
4133 exit_server_cleanly("reply_writebraw: send of "
4134 "keepalive failed");
4136 #endif
4137 TALLOC_FREE(req->outbuf);
4139 return;
4141 strict_unlock:
4142 if (!fsp->print_file) {
4143 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4146 END_PROFILE(SMBwritebraw);
4147 return;
4150 #undef DBGC_CLASS
4151 #define DBGC_CLASS DBGC_LOCKING
4153 /****************************************************************************
4154 Reply to a writeunlock (core+).
4155 ****************************************************************************/
4157 void reply_writeunlock(struct smb_request *req)
4159 connection_struct *conn = req->conn;
4160 ssize_t nwritten = -1;
4161 size_t numtowrite;
4162 SMB_OFF_T startpos;
4163 const char *data;
4164 NTSTATUS status = NT_STATUS_OK;
4165 files_struct *fsp;
4166 struct lock_struct lock;
4167 int saved_errno = 0;
4169 START_PROFILE(SMBwriteunlock);
4171 if (req->wct < 5) {
4172 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4173 END_PROFILE(SMBwriteunlock);
4174 return;
4177 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4179 if (!check_fsp(conn, req, fsp)) {
4180 END_PROFILE(SMBwriteunlock);
4181 return;
4184 if (!CHECK_WRITE(fsp)) {
4185 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4186 END_PROFILE(SMBwriteunlock);
4187 return;
4190 numtowrite = SVAL(req->vwv+1, 0);
4191 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4192 data = (const char *)req->buf + 3;
4194 if (!fsp->print_file && numtowrite > 0) {
4195 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4196 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4197 &lock);
4199 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4200 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4201 END_PROFILE(SMBwriteunlock);
4202 return;
4206 /* The special X/Open SMB protocol handling of
4207 zero length writes is *NOT* done for
4208 this call */
4209 if(numtowrite == 0) {
4210 nwritten = 0;
4211 } else {
4212 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4213 saved_errno = errno;
4216 status = sync_file(conn, fsp, False /* write through */);
4217 if (!NT_STATUS_IS_OK(status)) {
4218 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4219 fsp_str_dbg(fsp), nt_errstr(status)));
4220 reply_nterror(req, status);
4221 goto strict_unlock;
4224 if(nwritten < 0) {
4225 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4226 goto strict_unlock;
4229 if((nwritten < numtowrite) && (numtowrite != 0)) {
4230 reply_nterror(req, NT_STATUS_DISK_FULL);
4231 goto strict_unlock;
4234 if (numtowrite && !fsp->print_file) {
4235 status = do_unlock(req->sconn->msg_ctx,
4236 fsp,
4237 (uint64_t)req->smbpid,
4238 (uint64_t)numtowrite,
4239 (uint64_t)startpos,
4240 WINDOWS_LOCK);
4242 if (NT_STATUS_V(status)) {
4243 reply_nterror(req, status);
4244 goto strict_unlock;
4248 reply_outbuf(req, 1, 0);
4250 SSVAL(req->outbuf,smb_vwv0,nwritten);
4252 DEBUG(3,("writeunlock fnum=%d num=%d wrote=%d\n",
4253 fsp->fnum, (int)numtowrite, (int)nwritten));
4255 strict_unlock:
4256 if (numtowrite && !fsp->print_file) {
4257 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4260 END_PROFILE(SMBwriteunlock);
4261 return;
4264 #undef DBGC_CLASS
4265 #define DBGC_CLASS DBGC_ALL
4267 /****************************************************************************
4268 Reply to a write.
4269 ****************************************************************************/
4271 void reply_write(struct smb_request *req)
4273 connection_struct *conn = req->conn;
4274 size_t numtowrite;
4275 ssize_t nwritten = -1;
4276 SMB_OFF_T startpos;
4277 const char *data;
4278 files_struct *fsp;
4279 struct lock_struct lock;
4280 NTSTATUS status;
4281 int saved_errno = 0;
4283 START_PROFILE(SMBwrite);
4285 if (req->wct < 5) {
4286 END_PROFILE(SMBwrite);
4287 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4288 return;
4291 /* If it's an IPC, pass off the pipe handler. */
4292 if (IS_IPC(conn)) {
4293 reply_pipe_write(req);
4294 END_PROFILE(SMBwrite);
4295 return;
4298 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4300 if (!check_fsp(conn, req, fsp)) {
4301 END_PROFILE(SMBwrite);
4302 return;
4305 if (!CHECK_WRITE(fsp)) {
4306 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4307 END_PROFILE(SMBwrite);
4308 return;
4311 numtowrite = SVAL(req->vwv+1, 0);
4312 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4313 data = (const char *)req->buf + 3;
4315 if (!fsp->print_file) {
4316 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4317 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4318 &lock);
4320 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4321 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4322 END_PROFILE(SMBwrite);
4323 return;
4328 * X/Open SMB protocol says that if smb_vwv1 is
4329 * zero then the file size should be extended or
4330 * truncated to the size given in smb_vwv[2-3].
4333 if(numtowrite == 0) {
4335 * This is actually an allocate call, and set EOF. JRA.
4337 nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos);
4338 if (nwritten < 0) {
4339 reply_nterror(req, NT_STATUS_DISK_FULL);
4340 goto strict_unlock;
4342 nwritten = vfs_set_filelen(fsp, (SMB_OFF_T)startpos);
4343 if (nwritten < 0) {
4344 reply_nterror(req, NT_STATUS_DISK_FULL);
4345 goto strict_unlock;
4347 trigger_write_time_update_immediate(fsp);
4348 } else {
4349 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4352 status = sync_file(conn, fsp, False);
4353 if (!NT_STATUS_IS_OK(status)) {
4354 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4355 fsp_str_dbg(fsp), nt_errstr(status)));
4356 reply_nterror(req, status);
4357 goto strict_unlock;
4360 if(nwritten < 0) {
4361 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4362 goto strict_unlock;
4365 if((nwritten == 0) && (numtowrite != 0)) {
4366 reply_nterror(req, NT_STATUS_DISK_FULL);
4367 goto strict_unlock;
4370 reply_outbuf(req, 1, 0);
4372 SSVAL(req->outbuf,smb_vwv0,nwritten);
4374 if (nwritten < (ssize_t)numtowrite) {
4375 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4376 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4379 DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten));
4381 strict_unlock:
4382 if (!fsp->print_file) {
4383 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4386 END_PROFILE(SMBwrite);
4387 return;
4390 /****************************************************************************
4391 Ensure a buffer is a valid writeX for recvfile purposes.
4392 ****************************************************************************/
4394 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4395 (2*14) + /* word count (including bcc) */ \
4396 1 /* pad byte */)
4398 bool is_valid_writeX_buffer(struct smbd_server_connection *sconn,
4399 const uint8_t *inbuf)
4401 size_t numtowrite;
4402 connection_struct *conn = NULL;
4403 unsigned int doff = 0;
4404 size_t len = smb_len_large(inbuf);
4406 if (is_encrypted_packet(inbuf)) {
4407 /* Can't do this on encrypted
4408 * connections. */
4409 return false;
4412 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4413 return false;
4416 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4417 CVAL(inbuf,smb_wct) != 14) {
4418 DEBUG(10,("is_valid_writeX_buffer: chained or "
4419 "invalid word length.\n"));
4420 return false;
4423 conn = conn_find(sconn, SVAL(inbuf, smb_tid));
4424 if (conn == NULL) {
4425 DEBUG(10,("is_valid_writeX_buffer: bad tid\n"));
4426 return false;
4428 if (IS_IPC(conn)) {
4429 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4430 return false;
4432 if (IS_PRINT(conn)) {
4433 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4434 return false;
4436 doff = SVAL(inbuf,smb_vwv11);
4438 numtowrite = SVAL(inbuf,smb_vwv10);
4440 if (len > doff && len - doff > 0xFFFF) {
4441 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4444 if (numtowrite == 0) {
4445 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4446 return false;
4449 /* Ensure the sizes match up. */
4450 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4451 /* no pad byte...old smbclient :-( */
4452 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4453 (unsigned int)doff,
4454 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4455 return false;
4458 if (len - doff != numtowrite) {
4459 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4460 "len = %u, doff = %u, numtowrite = %u\n",
4461 (unsigned int)len,
4462 (unsigned int)doff,
4463 (unsigned int)numtowrite ));
4464 return false;
4467 DEBUG(10,("is_valid_writeX_buffer: true "
4468 "len = %u, doff = %u, numtowrite = %u\n",
4469 (unsigned int)len,
4470 (unsigned int)doff,
4471 (unsigned int)numtowrite ));
4473 return true;
4476 /****************************************************************************
4477 Reply to a write and X.
4478 ****************************************************************************/
4480 void reply_write_and_X(struct smb_request *req)
4482 connection_struct *conn = req->conn;
4483 files_struct *fsp;
4484 struct lock_struct lock;
4485 SMB_OFF_T startpos;
4486 size_t numtowrite;
4487 bool write_through;
4488 ssize_t nwritten;
4489 unsigned int smb_doff;
4490 unsigned int smblen;
4491 char *data;
4492 NTSTATUS status;
4493 int saved_errno = 0;
4495 START_PROFILE(SMBwriteX);
4497 if ((req->wct != 12) && (req->wct != 14)) {
4498 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4499 END_PROFILE(SMBwriteX);
4500 return;
4503 numtowrite = SVAL(req->vwv+10, 0);
4504 smb_doff = SVAL(req->vwv+11, 0);
4505 smblen = smb_len(req->inbuf);
4507 if (req->unread_bytes > 0xFFFF ||
4508 (smblen > smb_doff &&
4509 smblen - smb_doff > 0xFFFF)) {
4510 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
4513 if (req->unread_bytes) {
4514 /* Can't do a recvfile write on IPC$ */
4515 if (IS_IPC(conn)) {
4516 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4517 END_PROFILE(SMBwriteX);
4518 return;
4520 if (numtowrite != req->unread_bytes) {
4521 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4522 END_PROFILE(SMBwriteX);
4523 return;
4525 } else {
4526 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4527 smb_doff + numtowrite > smblen) {
4528 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4529 END_PROFILE(SMBwriteX);
4530 return;
4534 /* If it's an IPC, pass off the pipe handler. */
4535 if (IS_IPC(conn)) {
4536 if (req->unread_bytes) {
4537 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4538 END_PROFILE(SMBwriteX);
4539 return;
4541 reply_pipe_write_and_X(req);
4542 END_PROFILE(SMBwriteX);
4543 return;
4546 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4547 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4548 write_through = BITSETW(req->vwv+7,0);
4550 if (!check_fsp(conn, req, fsp)) {
4551 END_PROFILE(SMBwriteX);
4552 return;
4555 if (!CHECK_WRITE(fsp)) {
4556 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4557 END_PROFILE(SMBwriteX);
4558 return;
4561 data = smb_base(req->inbuf) + smb_doff;
4563 if(req->wct == 14) {
4564 #ifdef LARGE_SMB_OFF_T
4566 * This is a large offset (64 bit) write.
4568 startpos |= (((SMB_OFF_T)IVAL(req->vwv+12, 0)) << 32);
4570 #else /* !LARGE_SMB_OFF_T */
4573 * Ensure we haven't been sent a >32 bit offset.
4576 if(IVAL(req->vwv+12, 0) != 0) {
4577 DEBUG(0,("reply_write_and_X - large offset (%x << 32) "
4578 "used and we don't support 64 bit offsets.\n",
4579 (unsigned int)IVAL(req->vwv+12, 0) ));
4580 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4581 END_PROFILE(SMBwriteX);
4582 return;
4585 #endif /* LARGE_SMB_OFF_T */
4588 /* X/Open SMB protocol says that, unlike SMBwrite
4589 if the length is zero then NO truncation is
4590 done, just a write of zero. To truncate a file,
4591 use SMBwrite. */
4593 if(numtowrite == 0) {
4594 nwritten = 0;
4595 } else {
4596 if (req->unread_bytes == 0) {
4597 status = schedule_aio_write_and_X(conn,
4598 req,
4599 fsp,
4600 data,
4601 startpos,
4602 numtowrite);
4604 if (NT_STATUS_IS_OK(status)) {
4605 /* write scheduled - we're done. */
4606 goto out;
4608 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4609 /* Real error - report to client. */
4610 reply_nterror(req, status);
4611 goto out;
4613 /* NT_STATUS_RETRY - fall through to sync write. */
4616 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4617 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4618 &lock);
4620 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4621 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4622 goto out;
4625 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4626 saved_errno = errno;
4628 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4631 if(nwritten < 0) {
4632 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4633 goto out;
4636 if((nwritten == 0) && (numtowrite != 0)) {
4637 reply_nterror(req, NT_STATUS_DISK_FULL);
4638 goto out;
4641 reply_outbuf(req, 6, 0);
4642 SSVAL(req->outbuf,smb_vwv2,nwritten);
4643 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4645 DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
4646 fsp->fnum, (int)numtowrite, (int)nwritten));
4648 status = sync_file(conn, fsp, write_through);
4649 if (!NT_STATUS_IS_OK(status)) {
4650 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4651 fsp_str_dbg(fsp), nt_errstr(status)));
4652 reply_nterror(req, status);
4653 goto out;
4656 END_PROFILE(SMBwriteX);
4657 chain_reply(req);
4658 return;
4660 out:
4661 END_PROFILE(SMBwriteX);
4662 return;
4665 /****************************************************************************
4666 Reply to a lseek.
4667 ****************************************************************************/
4669 void reply_lseek(struct smb_request *req)
4671 connection_struct *conn = req->conn;
4672 SMB_OFF_T startpos;
4673 SMB_OFF_T res= -1;
4674 int mode,umode;
4675 files_struct *fsp;
4677 START_PROFILE(SMBlseek);
4679 if (req->wct < 4) {
4680 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4681 END_PROFILE(SMBlseek);
4682 return;
4685 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4687 if (!check_fsp(conn, req, fsp)) {
4688 return;
4691 flush_write_cache(fsp, SEEK_FLUSH);
4693 mode = SVAL(req->vwv+1, 0) & 3;
4694 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4695 startpos = (SMB_OFF_T)IVALS(req->vwv+2, 0);
4697 switch (mode) {
4698 case 0:
4699 umode = SEEK_SET;
4700 res = startpos;
4701 break;
4702 case 1:
4703 umode = SEEK_CUR;
4704 res = fsp->fh->pos + startpos;
4705 break;
4706 case 2:
4707 umode = SEEK_END;
4708 break;
4709 default:
4710 umode = SEEK_SET;
4711 res = startpos;
4712 break;
4715 if (umode == SEEK_END) {
4716 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
4717 if(errno == EINVAL) {
4718 SMB_OFF_T current_pos = startpos;
4720 if(fsp_stat(fsp) == -1) {
4721 reply_nterror(req,
4722 map_nt_error_from_unix(errno));
4723 END_PROFILE(SMBlseek);
4724 return;
4727 current_pos += fsp->fsp_name->st.st_ex_size;
4728 if(current_pos < 0)
4729 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
4733 if(res == -1) {
4734 reply_nterror(req, map_nt_error_from_unix(errno));
4735 END_PROFILE(SMBlseek);
4736 return;
4740 fsp->fh->pos = res;
4742 reply_outbuf(req, 2, 0);
4743 SIVAL(req->outbuf,smb_vwv0,res);
4745 DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
4746 fsp->fnum, (double)startpos, (double)res, mode));
4748 END_PROFILE(SMBlseek);
4749 return;
4752 /****************************************************************************
4753 Reply to a flush.
4754 ****************************************************************************/
4756 void reply_flush(struct smb_request *req)
4758 connection_struct *conn = req->conn;
4759 uint16 fnum;
4760 files_struct *fsp;
4762 START_PROFILE(SMBflush);
4764 if (req->wct < 1) {
4765 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4766 return;
4769 fnum = SVAL(req->vwv+0, 0);
4770 fsp = file_fsp(req, fnum);
4772 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
4773 return;
4776 if (!fsp) {
4777 file_sync_all(conn);
4778 } else {
4779 NTSTATUS status = sync_file(conn, fsp, True);
4780 if (!NT_STATUS_IS_OK(status)) {
4781 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
4782 fsp_str_dbg(fsp), nt_errstr(status)));
4783 reply_nterror(req, status);
4784 END_PROFILE(SMBflush);
4785 return;
4789 reply_outbuf(req, 0, 0);
4791 DEBUG(3,("flush\n"));
4792 END_PROFILE(SMBflush);
4793 return;
4796 /****************************************************************************
4797 Reply to a exit.
4798 conn POINTER CAN BE NULL HERE !
4799 ****************************************************************************/
4801 void reply_exit(struct smb_request *req)
4803 START_PROFILE(SMBexit);
4805 file_close_pid(req->sconn, req->smbpid, req->vuid);
4807 reply_outbuf(req, 0, 0);
4809 DEBUG(3,("exit\n"));
4811 END_PROFILE(SMBexit);
4812 return;
4815 /****************************************************************************
4816 Reply to a close - has to deal with closing a directory opened by NT SMB's.
4817 ****************************************************************************/
4819 void reply_close(struct smb_request *req)
4821 connection_struct *conn = req->conn;
4822 NTSTATUS status = NT_STATUS_OK;
4823 files_struct *fsp = NULL;
4824 START_PROFILE(SMBclose);
4826 if (req->wct < 3) {
4827 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4828 END_PROFILE(SMBclose);
4829 return;
4832 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4835 * We can only use check_fsp if we know it's not a directory.
4838 if (!check_fsp_open(conn, req, fsp)) {
4839 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
4840 END_PROFILE(SMBclose);
4841 return;
4844 if(fsp->is_directory) {
4846 * Special case - close NT SMB directory handle.
4848 DEBUG(3,("close directory fnum=%d\n", fsp->fnum));
4849 status = close_file(req, fsp, NORMAL_CLOSE);
4850 } else {
4851 time_t t;
4853 * Close ordinary file.
4856 DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
4857 fsp->fh->fd, fsp->fnum,
4858 conn->num_files_open));
4861 * Take care of any time sent in the close.
4864 t = srv_make_unix_date3(req->vwv+1);
4865 set_close_write_time(fsp, convert_time_t_to_timespec(t));
4868 * close_file() returns the unix errno if an error
4869 * was detected on close - normally this is due to
4870 * a disk full error. If not then it was probably an I/O error.
4873 status = close_file(req, fsp, NORMAL_CLOSE);
4876 if (!NT_STATUS_IS_OK(status)) {
4877 reply_nterror(req, status);
4878 END_PROFILE(SMBclose);
4879 return;
4882 reply_outbuf(req, 0, 0);
4883 END_PROFILE(SMBclose);
4884 return;
4887 /****************************************************************************
4888 Reply to a writeclose (Core+ protocol).
4889 ****************************************************************************/
4891 void reply_writeclose(struct smb_request *req)
4893 connection_struct *conn = req->conn;
4894 size_t numtowrite;
4895 ssize_t nwritten = -1;
4896 NTSTATUS close_status = NT_STATUS_OK;
4897 SMB_OFF_T startpos;
4898 const char *data;
4899 struct timespec mtime;
4900 files_struct *fsp;
4901 struct lock_struct lock;
4903 START_PROFILE(SMBwriteclose);
4905 if (req->wct < 6) {
4906 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4907 END_PROFILE(SMBwriteclose);
4908 return;
4911 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4913 if (!check_fsp(conn, req, fsp)) {
4914 END_PROFILE(SMBwriteclose);
4915 return;
4917 if (!CHECK_WRITE(fsp)) {
4918 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4919 END_PROFILE(SMBwriteclose);
4920 return;
4923 numtowrite = SVAL(req->vwv+1, 0);
4924 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4925 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
4926 data = (const char *)req->buf + 1;
4928 if (!fsp->print_file) {
4929 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4930 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4931 &lock);
4933 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4934 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4935 END_PROFILE(SMBwriteclose);
4936 return;
4940 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4942 set_close_write_time(fsp, mtime);
4945 * More insanity. W2K only closes the file if writelen > 0.
4946 * JRA.
4949 if (numtowrite) {
4950 DEBUG(3,("reply_writeclose: zero length write doesn't close "
4951 "file %s\n", fsp_str_dbg(fsp)));
4952 close_status = close_file(req, fsp, NORMAL_CLOSE);
4955 DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
4956 fsp->fnum, (int)numtowrite, (int)nwritten,
4957 conn->num_files_open));
4959 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
4960 reply_nterror(req, NT_STATUS_DISK_FULL);
4961 goto strict_unlock;
4964 if(!NT_STATUS_IS_OK(close_status)) {
4965 reply_nterror(req, close_status);
4966 goto strict_unlock;
4969 reply_outbuf(req, 1, 0);
4971 SSVAL(req->outbuf,smb_vwv0,nwritten);
4973 strict_unlock:
4974 if (numtowrite && !fsp->print_file) {
4975 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4978 END_PROFILE(SMBwriteclose);
4979 return;
4982 #undef DBGC_CLASS
4983 #define DBGC_CLASS DBGC_LOCKING
4985 /****************************************************************************
4986 Reply to a lock.
4987 ****************************************************************************/
4989 void reply_lock(struct smb_request *req)
4991 connection_struct *conn = req->conn;
4992 uint64_t count,offset;
4993 NTSTATUS status;
4994 files_struct *fsp;
4995 struct byte_range_lock *br_lck = NULL;
4997 START_PROFILE(SMBlock);
4999 if (req->wct < 5) {
5000 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5001 END_PROFILE(SMBlock);
5002 return;
5005 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5007 if (!check_fsp(conn, req, fsp)) {
5008 END_PROFILE(SMBlock);
5009 return;
5012 count = (uint64_t)IVAL(req->vwv+1, 0);
5013 offset = (uint64_t)IVAL(req->vwv+3, 0);
5015 DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
5016 fsp->fh->fd, fsp->fnum, (double)offset, (double)count));
5018 br_lck = do_lock(req->sconn->msg_ctx,
5019 fsp,
5020 (uint64_t)req->smbpid,
5021 count,
5022 offset,
5023 WRITE_LOCK,
5024 WINDOWS_LOCK,
5025 False, /* Non-blocking lock. */
5026 &status,
5027 NULL,
5028 NULL);
5030 TALLOC_FREE(br_lck);
5032 if (NT_STATUS_V(status)) {
5033 reply_nterror(req, status);
5034 END_PROFILE(SMBlock);
5035 return;
5038 reply_outbuf(req, 0, 0);
5040 END_PROFILE(SMBlock);
5041 return;
5044 /****************************************************************************
5045 Reply to a unlock.
5046 ****************************************************************************/
5048 void reply_unlock(struct smb_request *req)
5050 connection_struct *conn = req->conn;
5051 uint64_t count,offset;
5052 NTSTATUS status;
5053 files_struct *fsp;
5055 START_PROFILE(SMBunlock);
5057 if (req->wct < 5) {
5058 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5059 END_PROFILE(SMBunlock);
5060 return;
5063 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5065 if (!check_fsp(conn, req, fsp)) {
5066 END_PROFILE(SMBunlock);
5067 return;
5070 count = (uint64_t)IVAL(req->vwv+1, 0);
5071 offset = (uint64_t)IVAL(req->vwv+3, 0);
5073 status = do_unlock(req->sconn->msg_ctx,
5074 fsp,
5075 (uint64_t)req->smbpid,
5076 count,
5077 offset,
5078 WINDOWS_LOCK);
5080 if (NT_STATUS_V(status)) {
5081 reply_nterror(req, status);
5082 END_PROFILE(SMBunlock);
5083 return;
5086 DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
5087 fsp->fh->fd, fsp->fnum, (double)offset, (double)count ) );
5089 reply_outbuf(req, 0, 0);
5091 END_PROFILE(SMBunlock);
5092 return;
5095 #undef DBGC_CLASS
5096 #define DBGC_CLASS DBGC_ALL
5098 /****************************************************************************
5099 Reply to a tdis.
5100 conn POINTER CAN BE NULL HERE !
5101 ****************************************************************************/
5103 void reply_tdis(struct smb_request *req)
5105 connection_struct *conn = req->conn;
5106 START_PROFILE(SMBtdis);
5108 if (!conn) {
5109 DEBUG(4,("Invalid connection in tdis\n"));
5110 reply_nterror(req, NT_STATUS_NETWORK_NAME_DELETED);
5111 END_PROFILE(SMBtdis);
5112 return;
5115 conn->used = False;
5117 close_cnum(conn,req->vuid);
5118 req->conn = NULL;
5120 reply_outbuf(req, 0, 0);
5121 END_PROFILE(SMBtdis);
5122 return;
5125 /****************************************************************************
5126 Reply to a echo.
5127 conn POINTER CAN BE NULL HERE !
5128 ****************************************************************************/
5130 void reply_echo(struct smb_request *req)
5132 connection_struct *conn = req->conn;
5133 struct smb_perfcount_data local_pcd;
5134 struct smb_perfcount_data *cur_pcd;
5135 int smb_reverb;
5136 int seq_num;
5138 START_PROFILE(SMBecho);
5140 smb_init_perfcount_data(&local_pcd);
5142 if (req->wct < 1) {
5143 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5144 END_PROFILE(SMBecho);
5145 return;
5148 smb_reverb = SVAL(req->vwv+0, 0);
5150 reply_outbuf(req, 1, req->buflen);
5152 /* copy any incoming data back out */
5153 if (req->buflen > 0) {
5154 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5157 if (smb_reverb > 100) {
5158 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5159 smb_reverb = 100;
5162 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5164 /* this makes sure we catch the request pcd */
5165 if (seq_num == smb_reverb) {
5166 cur_pcd = &req->pcd;
5167 } else {
5168 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5169 cur_pcd = &local_pcd;
5172 SSVAL(req->outbuf,smb_vwv0,seq_num);
5174 show_msg((char *)req->outbuf);
5175 if (!srv_send_smb(req->sconn,
5176 (char *)req->outbuf,
5177 true, req->seqnum+1,
5178 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5179 cur_pcd))
5180 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5183 DEBUG(3,("echo %d times\n", smb_reverb));
5185 TALLOC_FREE(req->outbuf);
5187 END_PROFILE(SMBecho);
5188 return;
5191 /****************************************************************************
5192 Reply to a printopen.
5193 ****************************************************************************/
5195 void reply_printopen(struct smb_request *req)
5197 connection_struct *conn = req->conn;
5198 files_struct *fsp;
5199 NTSTATUS status;
5201 START_PROFILE(SMBsplopen);
5203 if (req->wct < 2) {
5204 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5205 END_PROFILE(SMBsplopen);
5206 return;
5209 if (!CAN_PRINT(conn)) {
5210 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5211 END_PROFILE(SMBsplopen);
5212 return;
5215 status = file_new(req, conn, &fsp);
5216 if(!NT_STATUS_IS_OK(status)) {
5217 reply_nterror(req, status);
5218 END_PROFILE(SMBsplopen);
5219 return;
5222 /* Open for exclusive use, write only. */
5223 status = print_spool_open(fsp, NULL, req->vuid);
5225 if (!NT_STATUS_IS_OK(status)) {
5226 file_free(req, fsp);
5227 reply_nterror(req, status);
5228 END_PROFILE(SMBsplopen);
5229 return;
5232 reply_outbuf(req, 1, 0);
5233 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5235 DEBUG(3,("openprint fd=%d fnum=%d\n",
5236 fsp->fh->fd, fsp->fnum));
5238 END_PROFILE(SMBsplopen);
5239 return;
5242 /****************************************************************************
5243 Reply to a printclose.
5244 ****************************************************************************/
5246 void reply_printclose(struct smb_request *req)
5248 connection_struct *conn = req->conn;
5249 files_struct *fsp;
5250 NTSTATUS status;
5252 START_PROFILE(SMBsplclose);
5254 if (req->wct < 1) {
5255 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5256 END_PROFILE(SMBsplclose);
5257 return;
5260 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5262 if (!check_fsp(conn, req, fsp)) {
5263 END_PROFILE(SMBsplclose);
5264 return;
5267 if (!CAN_PRINT(conn)) {
5268 reply_force_doserror(req, ERRSRV, ERRerror);
5269 END_PROFILE(SMBsplclose);
5270 return;
5273 DEBUG(3,("printclose fd=%d fnum=%d\n",
5274 fsp->fh->fd,fsp->fnum));
5276 status = close_file(req, fsp, NORMAL_CLOSE);
5278 if(!NT_STATUS_IS_OK(status)) {
5279 reply_nterror(req, status);
5280 END_PROFILE(SMBsplclose);
5281 return;
5284 reply_outbuf(req, 0, 0);
5286 END_PROFILE(SMBsplclose);
5287 return;
5290 /****************************************************************************
5291 Reply to a printqueue.
5292 ****************************************************************************/
5294 void reply_printqueue(struct smb_request *req)
5296 connection_struct *conn = req->conn;
5297 int max_count;
5298 int start_index;
5300 START_PROFILE(SMBsplretq);
5302 if (req->wct < 2) {
5303 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5304 END_PROFILE(SMBsplretq);
5305 return;
5308 max_count = SVAL(req->vwv+0, 0);
5309 start_index = SVAL(req->vwv+1, 0);
5311 /* we used to allow the client to get the cnum wrong, but that
5312 is really quite gross and only worked when there was only
5313 one printer - I think we should now only accept it if they
5314 get it right (tridge) */
5315 if (!CAN_PRINT(conn)) {
5316 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5317 END_PROFILE(SMBsplretq);
5318 return;
5321 reply_outbuf(req, 2, 3);
5322 SSVAL(req->outbuf,smb_vwv0,0);
5323 SSVAL(req->outbuf,smb_vwv1,0);
5324 SCVAL(smb_buf(req->outbuf),0,1);
5325 SSVAL(smb_buf(req->outbuf),1,0);
5327 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5328 start_index, max_count));
5331 TALLOC_CTX *mem_ctx = talloc_tos();
5332 NTSTATUS status;
5333 WERROR werr;
5334 const char *sharename = lp_servicename(SNUM(conn));
5335 struct rpc_pipe_client *cli = NULL;
5336 struct dcerpc_binding_handle *b = NULL;
5337 struct policy_handle handle;
5338 struct spoolss_DevmodeContainer devmode_ctr;
5339 union spoolss_JobInfo *info;
5340 uint32_t count;
5341 uint32_t num_to_get;
5342 uint32_t first;
5343 uint32_t i;
5345 ZERO_STRUCT(handle);
5347 status = rpc_pipe_open_interface(conn,
5348 &ndr_table_spoolss.syntax_id,
5349 conn->session_info,
5350 &conn->sconn->client_id,
5351 conn->sconn->msg_ctx,
5352 &cli);
5353 if (!NT_STATUS_IS_OK(status)) {
5354 DEBUG(0, ("reply_printqueue: "
5355 "could not connect to spoolss: %s\n",
5356 nt_errstr(status)));
5357 reply_nterror(req, status);
5358 goto out;
5360 b = cli->binding_handle;
5362 ZERO_STRUCT(devmode_ctr);
5364 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5365 sharename,
5366 NULL, devmode_ctr,
5367 SEC_FLAG_MAXIMUM_ALLOWED,
5368 &handle,
5369 &werr);
5370 if (!NT_STATUS_IS_OK(status)) {
5371 reply_nterror(req, status);
5372 goto out;
5374 if (!W_ERROR_IS_OK(werr)) {
5375 reply_nterror(req, werror_to_ntstatus(werr));
5376 goto out;
5379 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5380 &handle,
5381 0, /* firstjob */
5382 0xff, /* numjobs */
5383 2, /* level */
5384 0, /* offered */
5385 &count,
5386 &info);
5387 if (!W_ERROR_IS_OK(werr)) {
5388 reply_nterror(req, werror_to_ntstatus(werr));
5389 goto out;
5392 if (max_count > 0) {
5393 first = start_index;
5394 } else {
5395 first = start_index + max_count + 1;
5398 if (first >= count) {
5399 num_to_get = first;
5400 } else {
5401 num_to_get = first + MIN(ABS(max_count), count - first);
5404 for (i = first; i < num_to_get; i++) {
5405 char blob[28];
5406 char *p = blob;
5407 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
5408 int qstatus;
5409 uint16_t qrapjobid = pjobid_to_rap(sharename,
5410 info[i].info2.job_id);
5412 if (info[i].info2.status == JOB_STATUS_PRINTING) {
5413 qstatus = 2;
5414 } else {
5415 qstatus = 3;
5418 srv_put_dos_date2(p, 0, qtime);
5419 SCVAL(p, 4, qstatus);
5420 SSVAL(p, 5, qrapjobid);
5421 SIVAL(p, 7, info[i].info2.size);
5422 SCVAL(p, 11, 0);
5423 srvstr_push(blob, req->flags2, p+12,
5424 info[i].info2.notify_name, 16, STR_ASCII);
5426 if (message_push_blob(
5427 &req->outbuf,
5428 data_blob_const(
5429 blob, sizeof(blob))) == -1) {
5430 reply_nterror(req, NT_STATUS_NO_MEMORY);
5431 goto out;
5435 if (count > 0) {
5436 SSVAL(req->outbuf,smb_vwv0,count);
5437 SSVAL(req->outbuf,smb_vwv1,
5438 (max_count>0?first+count:first-1));
5439 SCVAL(smb_buf(req->outbuf),0,1);
5440 SSVAL(smb_buf(req->outbuf),1,28*count);
5444 DEBUG(3, ("%u entries returned in queue\n",
5445 (unsigned)count));
5447 out:
5448 if (b && is_valid_policy_hnd(&handle)) {
5449 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5454 END_PROFILE(SMBsplretq);
5455 return;
5458 /****************************************************************************
5459 Reply to a printwrite.
5460 ****************************************************************************/
5462 void reply_printwrite(struct smb_request *req)
5464 connection_struct *conn = req->conn;
5465 int numtowrite;
5466 const char *data;
5467 files_struct *fsp;
5469 START_PROFILE(SMBsplwr);
5471 if (req->wct < 1) {
5472 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5473 END_PROFILE(SMBsplwr);
5474 return;
5477 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5479 if (!check_fsp(conn, req, fsp)) {
5480 END_PROFILE(SMBsplwr);
5481 return;
5484 if (!fsp->print_file) {
5485 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5486 END_PROFILE(SMBsplwr);
5487 return;
5490 if (!CHECK_WRITE(fsp)) {
5491 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5492 END_PROFILE(SMBsplwr);
5493 return;
5496 numtowrite = SVAL(req->buf, 1);
5498 if (req->buflen < numtowrite + 3) {
5499 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5500 END_PROFILE(SMBsplwr);
5501 return;
5504 data = (const char *)req->buf + 3;
5506 if (write_file(req,fsp,data,(SMB_OFF_T)-1,numtowrite) != numtowrite) {
5507 reply_nterror(req, map_nt_error_from_unix(errno));
5508 END_PROFILE(SMBsplwr);
5509 return;
5512 DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
5514 END_PROFILE(SMBsplwr);
5515 return;
5518 /****************************************************************************
5519 Reply to a mkdir.
5520 ****************************************************************************/
5522 void reply_mkdir(struct smb_request *req)
5524 connection_struct *conn = req->conn;
5525 struct smb_filename *smb_dname = NULL;
5526 char *directory = NULL;
5527 NTSTATUS status;
5528 TALLOC_CTX *ctx = talloc_tos();
5530 START_PROFILE(SMBmkdir);
5532 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5533 STR_TERMINATE, &status);
5534 if (!NT_STATUS_IS_OK(status)) {
5535 reply_nterror(req, status);
5536 goto out;
5539 status = filename_convert(ctx, conn,
5540 req->flags2 & FLAGS2_DFS_PATHNAMES,
5541 directory,
5543 NULL,
5544 &smb_dname);
5545 if (!NT_STATUS_IS_OK(status)) {
5546 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5547 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5548 ERRSRV, ERRbadpath);
5549 goto out;
5551 reply_nterror(req, status);
5552 goto out;
5555 status = create_directory(conn, req, smb_dname);
5557 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
5559 if (!NT_STATUS_IS_OK(status)) {
5561 if (!use_nt_status()
5562 && NT_STATUS_EQUAL(status,
5563 NT_STATUS_OBJECT_NAME_COLLISION)) {
5565 * Yes, in the DOS error code case we get a
5566 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
5567 * samba4 torture test.
5569 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
5572 reply_nterror(req, status);
5573 goto out;
5576 reply_outbuf(req, 0, 0);
5578 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
5579 out:
5580 TALLOC_FREE(smb_dname);
5581 END_PROFILE(SMBmkdir);
5582 return;
5585 /****************************************************************************
5586 Reply to a rmdir.
5587 ****************************************************************************/
5589 void reply_rmdir(struct smb_request *req)
5591 connection_struct *conn = req->conn;
5592 struct smb_filename *smb_dname = NULL;
5593 char *directory = NULL;
5594 NTSTATUS status;
5595 TALLOC_CTX *ctx = talloc_tos();
5596 files_struct *fsp = NULL;
5597 int info = 0;
5598 struct smbd_server_connection *sconn = req->sconn;
5600 START_PROFILE(SMBrmdir);
5602 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5603 STR_TERMINATE, &status);
5604 if (!NT_STATUS_IS_OK(status)) {
5605 reply_nterror(req, status);
5606 goto out;
5609 status = filename_convert(ctx, conn,
5610 req->flags2 & FLAGS2_DFS_PATHNAMES,
5611 directory,
5613 NULL,
5614 &smb_dname);
5615 if (!NT_STATUS_IS_OK(status)) {
5616 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5617 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5618 ERRSRV, ERRbadpath);
5619 goto out;
5621 reply_nterror(req, status);
5622 goto out;
5625 if (is_ntfs_stream_smb_fname(smb_dname)) {
5626 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
5627 goto out;
5630 status = SMB_VFS_CREATE_FILE(
5631 conn, /* conn */
5632 req, /* req */
5633 0, /* root_dir_fid */
5634 smb_dname, /* fname */
5635 DELETE_ACCESS, /* access_mask */
5636 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5637 FILE_SHARE_DELETE),
5638 FILE_OPEN, /* create_disposition*/
5639 FILE_DIRECTORY_FILE, /* create_options */
5640 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
5641 0, /* oplock_request */
5642 0, /* allocation_size */
5643 0, /* private_flags */
5644 NULL, /* sd */
5645 NULL, /* ea_list */
5646 &fsp, /* result */
5647 &info); /* pinfo */
5649 if (!NT_STATUS_IS_OK(status)) {
5650 if (open_was_deferred(req->mid)) {
5651 /* We have re-scheduled this call. */
5652 goto out;
5654 reply_nterror(req, status);
5655 goto out;
5658 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
5659 if (!NT_STATUS_IS_OK(status)) {
5660 close_file(req, fsp, ERROR_CLOSE);
5661 reply_nterror(req, status);
5662 goto out;
5665 if (!set_delete_on_close(fsp, true,
5666 conn->session_info->security_token,
5667 &conn->session_info->utok)) {
5668 close_file(req, fsp, ERROR_CLOSE);
5669 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5670 goto out;
5673 status = close_file(req, fsp, NORMAL_CLOSE);
5674 if (!NT_STATUS_IS_OK(status)) {
5675 reply_nterror(req, status);
5676 } else {
5677 reply_outbuf(req, 0, 0);
5680 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
5682 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
5683 out:
5684 TALLOC_FREE(smb_dname);
5685 END_PROFILE(SMBrmdir);
5686 return;
5689 /*******************************************************************
5690 Resolve wildcards in a filename rename.
5691 ********************************************************************/
5693 static bool resolve_wildcards(TALLOC_CTX *ctx,
5694 const char *name1,
5695 const char *name2,
5696 char **pp_newname)
5698 char *name2_copy = NULL;
5699 char *root1 = NULL;
5700 char *root2 = NULL;
5701 char *ext1 = NULL;
5702 char *ext2 = NULL;
5703 char *p,*p2, *pname1, *pname2;
5705 name2_copy = talloc_strdup(ctx, name2);
5706 if (!name2_copy) {
5707 return False;
5710 pname1 = strrchr_m(name1,'/');
5711 pname2 = strrchr_m(name2_copy,'/');
5713 if (!pname1 || !pname2) {
5714 return False;
5717 /* Truncate the copy of name2 at the last '/' */
5718 *pname2 = '\0';
5720 /* Now go past the '/' */
5721 pname1++;
5722 pname2++;
5724 root1 = talloc_strdup(ctx, pname1);
5725 root2 = talloc_strdup(ctx, pname2);
5727 if (!root1 || !root2) {
5728 return False;
5731 p = strrchr_m(root1,'.');
5732 if (p) {
5733 *p = 0;
5734 ext1 = talloc_strdup(ctx, p+1);
5735 } else {
5736 ext1 = talloc_strdup(ctx, "");
5738 p = strrchr_m(root2,'.');
5739 if (p) {
5740 *p = 0;
5741 ext2 = talloc_strdup(ctx, p+1);
5742 } else {
5743 ext2 = talloc_strdup(ctx, "");
5746 if (!ext1 || !ext2) {
5747 return False;
5750 p = root1;
5751 p2 = root2;
5752 while (*p2) {
5753 if (*p2 == '?') {
5754 /* Hmmm. Should this be mb-aware ? */
5755 *p2 = *p;
5756 p2++;
5757 } else if (*p2 == '*') {
5758 *p2 = '\0';
5759 root2 = talloc_asprintf(ctx, "%s%s",
5760 root2,
5762 if (!root2) {
5763 return False;
5765 break;
5766 } else {
5767 p2++;
5769 if (*p) {
5770 p++;
5774 p = ext1;
5775 p2 = ext2;
5776 while (*p2) {
5777 if (*p2 == '?') {
5778 /* Hmmm. Should this be mb-aware ? */
5779 *p2 = *p;
5780 p2++;
5781 } else if (*p2 == '*') {
5782 *p2 = '\0';
5783 ext2 = talloc_asprintf(ctx, "%s%s",
5784 ext2,
5786 if (!ext2) {
5787 return False;
5789 break;
5790 } else {
5791 p2++;
5793 if (*p) {
5794 p++;
5798 if (*ext2) {
5799 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
5800 name2_copy,
5801 root2,
5802 ext2);
5803 } else {
5804 *pp_newname = talloc_asprintf(ctx, "%s/%s",
5805 name2_copy,
5806 root2);
5809 if (!*pp_newname) {
5810 return False;
5813 return True;
5816 /****************************************************************************
5817 Ensure open files have their names updated. Updated to notify other smbd's
5818 asynchronously.
5819 ****************************************************************************/
5821 static void rename_open_files(connection_struct *conn,
5822 struct share_mode_lock *lck,
5823 uint32_t orig_name_hash,
5824 const struct smb_filename *smb_fname_dst)
5826 files_struct *fsp;
5827 bool did_rename = False;
5828 NTSTATUS status;
5829 uint32_t new_name_hash;
5831 for(fsp = file_find_di_first(conn->sconn, lck->id); fsp;
5832 fsp = file_find_di_next(fsp)) {
5833 /* fsp_name is a relative path under the fsp. To change this for other
5834 sharepaths we need to manipulate relative paths. */
5835 /* TODO - create the absolute path and manipulate the newname
5836 relative to the sharepath. */
5837 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
5838 continue;
5840 if (fsp->name_hash != orig_name_hash) {
5841 continue;
5843 DEBUG(10, ("rename_open_files: renaming file fnum %d "
5844 "(file_id %s) from %s -> %s\n", fsp->fnum,
5845 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
5846 smb_fname_str_dbg(smb_fname_dst)));
5848 status = fsp_set_smb_fname(fsp, smb_fname_dst);
5849 if (NT_STATUS_IS_OK(status)) {
5850 did_rename = True;
5851 new_name_hash = fsp->name_hash;
5855 if (!did_rename) {
5856 DEBUG(10, ("rename_open_files: no open files on file_id %s "
5857 "for %s\n", file_id_string_tos(&lck->id),
5858 smb_fname_str_dbg(smb_fname_dst)));
5861 /* Send messages to all smbd's (not ourself) that the name has changed. */
5862 rename_share_filename(conn->sconn->msg_ctx, lck, conn->connectpath,
5863 orig_name_hash, new_name_hash,
5864 smb_fname_dst);
5868 /****************************************************************************
5869 We need to check if the source path is a parent directory of the destination
5870 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
5871 refuse the rename with a sharing violation. Under UNIX the above call can
5872 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
5873 probably need to check that the client is a Windows one before disallowing
5874 this as a UNIX client (one with UNIX extensions) can know the source is a
5875 symlink and make this decision intelligently. Found by an excellent bug
5876 report from <AndyLiebman@aol.com>.
5877 ****************************************************************************/
5879 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
5880 const struct smb_filename *smb_fname_dst)
5882 const char *psrc = smb_fname_src->base_name;
5883 const char *pdst = smb_fname_dst->base_name;
5884 size_t slen;
5886 if (psrc[0] == '.' && psrc[1] == '/') {
5887 psrc += 2;
5889 if (pdst[0] == '.' && pdst[1] == '/') {
5890 pdst += 2;
5892 if ((slen = strlen(psrc)) > strlen(pdst)) {
5893 return False;
5895 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
5899 * Do the notify calls from a rename
5902 static void notify_rename(connection_struct *conn, bool is_dir,
5903 const struct smb_filename *smb_fname_src,
5904 const struct smb_filename *smb_fname_dst)
5906 char *parent_dir_src = NULL;
5907 char *parent_dir_dst = NULL;
5908 uint32 mask;
5910 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
5911 : FILE_NOTIFY_CHANGE_FILE_NAME;
5913 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
5914 &parent_dir_src, NULL) ||
5915 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
5916 &parent_dir_dst, NULL)) {
5917 goto out;
5920 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
5921 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
5922 smb_fname_src->base_name);
5923 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
5924 smb_fname_dst->base_name);
5926 else {
5927 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
5928 smb_fname_src->base_name);
5929 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
5930 smb_fname_dst->base_name);
5933 /* this is a strange one. w2k3 gives an additional event for
5934 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
5935 files, but not directories */
5936 if (!is_dir) {
5937 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
5938 FILE_NOTIFY_CHANGE_ATTRIBUTES
5939 |FILE_NOTIFY_CHANGE_CREATION,
5940 smb_fname_dst->base_name);
5942 out:
5943 TALLOC_FREE(parent_dir_src);
5944 TALLOC_FREE(parent_dir_dst);
5947 /****************************************************************************
5948 Returns an error if the parent directory for a filename is open in an
5949 incompatible way.
5950 ****************************************************************************/
5952 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
5953 const struct smb_filename *smb_fname_dst_in)
5955 char *parent_dir = NULL;
5956 struct smb_filename smb_fname_parent;
5957 struct file_id id;
5958 files_struct *fsp = NULL;
5959 int ret;
5961 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
5962 &parent_dir, NULL)) {
5963 return NT_STATUS_NO_MEMORY;
5965 ZERO_STRUCT(smb_fname_parent);
5966 smb_fname_parent.base_name = parent_dir;
5968 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
5969 if (ret == -1) {
5970 return map_nt_error_from_unix(errno);
5974 * We're only checking on this smbd here, mostly good
5975 * enough.. and will pass tests.
5978 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
5979 for (fsp = file_find_di_first(conn->sconn, id); fsp;
5980 fsp = file_find_di_next(fsp)) {
5981 if (fsp->access_mask & DELETE_ACCESS) {
5982 return NT_STATUS_SHARING_VIOLATION;
5985 return NT_STATUS_OK;
5988 /****************************************************************************
5989 Rename an open file - given an fsp.
5990 ****************************************************************************/
5992 NTSTATUS rename_internals_fsp(connection_struct *conn,
5993 files_struct *fsp,
5994 const struct smb_filename *smb_fname_dst_in,
5995 uint32 attrs,
5996 bool replace_if_exists)
5998 TALLOC_CTX *ctx = talloc_tos();
5999 struct smb_filename *smb_fname_dst = NULL;
6000 NTSTATUS status = NT_STATUS_OK;
6001 struct share_mode_lock *lck = NULL;
6002 bool dst_exists, old_is_stream, new_is_stream;
6004 status = check_name(conn, smb_fname_dst_in->base_name);
6005 if (!NT_STATUS_IS_OK(status)) {
6006 return status;
6009 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
6010 if (!NT_STATUS_IS_OK(status)) {
6011 return status;
6014 /* Make a copy of the dst smb_fname structs */
6016 status = copy_smb_filename(ctx, smb_fname_dst_in, &smb_fname_dst);
6017 if (!NT_STATUS_IS_OK(status)) {
6018 goto out;
6022 * Check for special case with case preserving and not
6023 * case sensitive. If the old last component differs from the original
6024 * last component only by case, then we should allow
6025 * the rename (user is trying to change the case of the
6026 * filename).
6028 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
6029 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6030 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
6031 char *last_slash;
6032 char *fname_dst_lcomp_base_mod = NULL;
6033 struct smb_filename *smb_fname_orig_lcomp = NULL;
6036 * Get the last component of the destination name.
6038 last_slash = strrchr_m(smb_fname_dst->base_name, '/');
6039 if (last_slash) {
6040 fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1);
6041 } else {
6042 fname_dst_lcomp_base_mod = talloc_strdup(ctx, smb_fname_dst->base_name);
6044 if (!fname_dst_lcomp_base_mod) {
6045 status = NT_STATUS_NO_MEMORY;
6046 goto out;
6050 * Create an smb_filename struct using the original last
6051 * component of the destination.
6053 status = create_synthetic_smb_fname_split(ctx,
6054 smb_fname_dst->original_lcomp, NULL,
6055 &smb_fname_orig_lcomp);
6056 if (!NT_STATUS_IS_OK(status)) {
6057 TALLOC_FREE(fname_dst_lcomp_base_mod);
6058 goto out;
6061 /* If the base names only differ by case, use original. */
6062 if(!strcsequal(fname_dst_lcomp_base_mod,
6063 smb_fname_orig_lcomp->base_name)) {
6064 char *tmp;
6066 * Replace the modified last component with the
6067 * original.
6069 if (last_slash) {
6070 *last_slash = '\0'; /* Truncate at the '/' */
6071 tmp = talloc_asprintf(smb_fname_dst,
6072 "%s/%s",
6073 smb_fname_dst->base_name,
6074 smb_fname_orig_lcomp->base_name);
6075 } else {
6076 tmp = talloc_asprintf(smb_fname_dst,
6077 "%s",
6078 smb_fname_orig_lcomp->base_name);
6080 if (tmp == NULL) {
6081 status = NT_STATUS_NO_MEMORY;
6082 TALLOC_FREE(fname_dst_lcomp_base_mod);
6083 TALLOC_FREE(smb_fname_orig_lcomp);
6084 goto out;
6086 TALLOC_FREE(smb_fname_dst->base_name);
6087 smb_fname_dst->base_name = tmp;
6090 /* If the stream_names only differ by case, use original. */
6091 if(!strcsequal(smb_fname_dst->stream_name,
6092 smb_fname_orig_lcomp->stream_name)) {
6093 char *tmp = NULL;
6094 /* Use the original stream. */
6095 tmp = talloc_strdup(smb_fname_dst,
6096 smb_fname_orig_lcomp->stream_name);
6097 if (tmp == NULL) {
6098 status = NT_STATUS_NO_MEMORY;
6099 TALLOC_FREE(fname_dst_lcomp_base_mod);
6100 TALLOC_FREE(smb_fname_orig_lcomp);
6101 goto out;
6103 TALLOC_FREE(smb_fname_dst->stream_name);
6104 smb_fname_dst->stream_name = tmp;
6106 TALLOC_FREE(fname_dst_lcomp_base_mod);
6107 TALLOC_FREE(smb_fname_orig_lcomp);
6111 * If the src and dest names are identical - including case,
6112 * don't do the rename, just return success.
6115 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6116 strcsequal(fsp->fsp_name->stream_name,
6117 smb_fname_dst->stream_name)) {
6118 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6119 "- returning success\n",
6120 smb_fname_str_dbg(smb_fname_dst)));
6121 status = NT_STATUS_OK;
6122 goto out;
6125 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6126 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6128 /* Return the correct error code if both names aren't streams. */
6129 if (!old_is_stream && new_is_stream) {
6130 status = NT_STATUS_OBJECT_NAME_INVALID;
6131 goto out;
6134 if (old_is_stream && !new_is_stream) {
6135 status = NT_STATUS_INVALID_PARAMETER;
6136 goto out;
6139 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6141 if(!replace_if_exists && dst_exists) {
6142 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6143 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6144 smb_fname_str_dbg(smb_fname_dst)));
6145 status = NT_STATUS_OBJECT_NAME_COLLISION;
6146 goto out;
6149 if (dst_exists) {
6150 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6151 &smb_fname_dst->st);
6152 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6153 fileid);
6154 /* The file can be open when renaming a stream */
6155 if (dst_fsp && !new_is_stream) {
6156 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6157 status = NT_STATUS_ACCESS_DENIED;
6158 goto out;
6162 /* Ensure we have a valid stat struct for the source. */
6163 status = vfs_stat_fsp(fsp);
6164 if (!NT_STATUS_IS_OK(status)) {
6165 goto out;
6168 status = can_rename(conn, fsp, attrs);
6170 if (!NT_STATUS_IS_OK(status)) {
6171 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6172 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6173 smb_fname_str_dbg(smb_fname_dst)));
6174 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6175 status = NT_STATUS_ACCESS_DENIED;
6176 goto out;
6179 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6180 status = NT_STATUS_ACCESS_DENIED;
6183 lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
6184 NULL);
6187 * We have the file open ourselves, so not being able to get the
6188 * corresponding share mode lock is a fatal error.
6191 SMB_ASSERT(lck != NULL);
6193 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6194 uint32 create_options = fsp->fh->private_options;
6196 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6197 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6198 smb_fname_str_dbg(smb_fname_dst)));
6200 if (!fsp->is_directory &&
6201 !lp_posix_pathnames() &&
6202 (lp_map_archive(SNUM(conn)) ||
6203 lp_store_dos_attributes(SNUM(conn)))) {
6204 /* We must set the archive bit on the newly
6205 renamed file. */
6206 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6207 uint32_t old_dosmode = dos_mode(conn,
6208 smb_fname_dst);
6209 file_set_dosmode(conn,
6210 smb_fname_dst,
6211 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6212 NULL,
6213 true);
6217 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6218 smb_fname_dst);
6220 rename_open_files(conn, lck, fsp->name_hash, smb_fname_dst);
6223 * A rename acts as a new file create w.r.t. allowing an initial delete
6224 * on close, probably because in Windows there is a new handle to the
6225 * new file. If initial delete on close was requested but not
6226 * originally set, we need to set it here. This is probably not 100% correct,
6227 * but will work for the CIFSFS client which in non-posix mode
6228 * depends on these semantics. JRA.
6231 if (create_options & FILE_DELETE_ON_CLOSE) {
6232 status = can_set_delete_on_close(fsp, 0);
6234 if (NT_STATUS_IS_OK(status)) {
6235 /* Note that here we set the *inital* delete on close flag,
6236 * not the regular one. The magic gets handled in close. */
6237 fsp->initial_delete_on_close = True;
6240 TALLOC_FREE(lck);
6241 status = NT_STATUS_OK;
6242 goto out;
6245 TALLOC_FREE(lck);
6247 if (errno == ENOTDIR || errno == EISDIR) {
6248 status = NT_STATUS_OBJECT_NAME_COLLISION;
6249 } else {
6250 status = map_nt_error_from_unix(errno);
6253 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6254 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6255 smb_fname_str_dbg(smb_fname_dst)));
6257 out:
6258 TALLOC_FREE(smb_fname_dst);
6260 return status;
6263 /****************************************************************************
6264 The guts of the rename command, split out so it may be called by the NT SMB
6265 code.
6266 ****************************************************************************/
6268 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6269 connection_struct *conn,
6270 struct smb_request *req,
6271 struct smb_filename *smb_fname_src,
6272 struct smb_filename *smb_fname_dst,
6273 uint32 attrs,
6274 bool replace_if_exists,
6275 bool src_has_wild,
6276 bool dest_has_wild,
6277 uint32_t access_mask)
6279 char *fname_src_dir = NULL;
6280 char *fname_src_mask = NULL;
6281 int count=0;
6282 NTSTATUS status = NT_STATUS_OK;
6283 struct smb_Dir *dir_hnd = NULL;
6284 const char *dname = NULL;
6285 char *talloced = NULL;
6286 long offset = 0;
6287 int create_options = 0;
6288 bool posix_pathnames = lp_posix_pathnames();
6291 * Split the old name into directory and last component
6292 * strings. Note that unix_convert may have stripped off a
6293 * leading ./ from both name and newname if the rename is
6294 * at the root of the share. We need to make sure either both
6295 * name and newname contain a / character or neither of them do
6296 * as this is checked in resolve_wildcards().
6299 /* Split up the directory from the filename/mask. */
6300 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6301 &fname_src_dir, &fname_src_mask);
6302 if (!NT_STATUS_IS_OK(status)) {
6303 status = NT_STATUS_NO_MEMORY;
6304 goto out;
6308 * We should only check the mangled cache
6309 * here if unix_convert failed. This means
6310 * that the path in 'mask' doesn't exist
6311 * on the file system and so we need to look
6312 * for a possible mangle. This patch from
6313 * Tine Smukavec <valentin.smukavec@hermes.si>.
6316 if (!VALID_STAT(smb_fname_src->st) &&
6317 mangle_is_mangled(fname_src_mask, conn->params)) {
6318 char *new_mask = NULL;
6319 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6320 conn->params);
6321 if (new_mask) {
6322 TALLOC_FREE(fname_src_mask);
6323 fname_src_mask = new_mask;
6327 if (!src_has_wild) {
6328 files_struct *fsp;
6331 * Only one file needs to be renamed. Append the mask back
6332 * onto the directory.
6334 TALLOC_FREE(smb_fname_src->base_name);
6335 if (ISDOT(fname_src_dir)) {
6336 /* Ensure we use canonical names on open. */
6337 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6338 "%s",
6339 fname_src_mask);
6340 } else {
6341 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6342 "%s/%s",
6343 fname_src_dir,
6344 fname_src_mask);
6346 if (!smb_fname_src->base_name) {
6347 status = NT_STATUS_NO_MEMORY;
6348 goto out;
6351 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6352 "case_preserve = %d, short case preserve = %d, "
6353 "directory = %s, newname = %s, "
6354 "last_component_dest = %s\n",
6355 conn->case_sensitive, conn->case_preserve,
6356 conn->short_case_preserve,
6357 smb_fname_str_dbg(smb_fname_src),
6358 smb_fname_str_dbg(smb_fname_dst),
6359 smb_fname_dst->original_lcomp));
6361 /* The dest name still may have wildcards. */
6362 if (dest_has_wild) {
6363 char *fname_dst_mod = NULL;
6364 if (!resolve_wildcards(smb_fname_dst,
6365 smb_fname_src->base_name,
6366 smb_fname_dst->base_name,
6367 &fname_dst_mod)) {
6368 DEBUG(6, ("rename_internals: resolve_wildcards "
6369 "%s %s failed\n",
6370 smb_fname_src->base_name,
6371 smb_fname_dst->base_name));
6372 status = NT_STATUS_NO_MEMORY;
6373 goto out;
6375 TALLOC_FREE(smb_fname_dst->base_name);
6376 smb_fname_dst->base_name = fname_dst_mod;
6379 ZERO_STRUCT(smb_fname_src->st);
6380 if (posix_pathnames) {
6381 SMB_VFS_LSTAT(conn, smb_fname_src);
6382 } else {
6383 SMB_VFS_STAT(conn, smb_fname_src);
6386 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6387 create_options |= FILE_DIRECTORY_FILE;
6390 status = SMB_VFS_CREATE_FILE(
6391 conn, /* conn */
6392 req, /* req */
6393 0, /* root_dir_fid */
6394 smb_fname_src, /* fname */
6395 access_mask, /* access_mask */
6396 (FILE_SHARE_READ | /* share_access */
6397 FILE_SHARE_WRITE),
6398 FILE_OPEN, /* create_disposition*/
6399 create_options, /* create_options */
6400 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6401 0, /* oplock_request */
6402 0, /* allocation_size */
6403 0, /* private_flags */
6404 NULL, /* sd */
6405 NULL, /* ea_list */
6406 &fsp, /* result */
6407 NULL); /* pinfo */
6409 if (!NT_STATUS_IS_OK(status)) {
6410 DEBUG(3, ("Could not open rename source %s: %s\n",
6411 smb_fname_str_dbg(smb_fname_src),
6412 nt_errstr(status)));
6413 goto out;
6416 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6417 attrs, replace_if_exists);
6419 close_file(req, fsp, NORMAL_CLOSE);
6421 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
6422 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
6423 smb_fname_str_dbg(smb_fname_dst)));
6425 goto out;
6429 * Wildcards - process each file that matches.
6431 if (strequal(fname_src_mask, "????????.???")) {
6432 TALLOC_FREE(fname_src_mask);
6433 fname_src_mask = talloc_strdup(ctx, "*");
6434 if (!fname_src_mask) {
6435 status = NT_STATUS_NO_MEMORY;
6436 goto out;
6440 status = check_name(conn, fname_src_dir);
6441 if (!NT_STATUS_IS_OK(status)) {
6442 goto out;
6445 dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask,
6446 attrs);
6447 if (dir_hnd == NULL) {
6448 status = map_nt_error_from_unix(errno);
6449 goto out;
6452 status = NT_STATUS_NO_SUCH_FILE;
6454 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
6455 * - gentest fix. JRA
6458 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
6459 &talloced))) {
6460 files_struct *fsp = NULL;
6461 char *destname = NULL;
6462 bool sysdir_entry = False;
6464 /* Quick check for "." and ".." */
6465 if (ISDOT(dname) || ISDOTDOT(dname)) {
6466 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
6467 sysdir_entry = True;
6468 } else {
6469 TALLOC_FREE(talloced);
6470 continue;
6474 if (!is_visible_file(conn, fname_src_dir, dname,
6475 &smb_fname_src->st, false)) {
6476 TALLOC_FREE(talloced);
6477 continue;
6480 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
6481 TALLOC_FREE(talloced);
6482 continue;
6485 if (sysdir_entry) {
6486 status = NT_STATUS_OBJECT_NAME_INVALID;
6487 break;
6490 TALLOC_FREE(smb_fname_src->base_name);
6491 if (ISDOT(fname_src_dir)) {
6492 /* Ensure we use canonical names on open. */
6493 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6494 "%s",
6495 dname);
6496 } else {
6497 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6498 "%s/%s",
6499 fname_src_dir,
6500 dname);
6502 if (!smb_fname_src->base_name) {
6503 status = NT_STATUS_NO_MEMORY;
6504 goto out;
6507 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6508 smb_fname_dst->base_name,
6509 &destname)) {
6510 DEBUG(6, ("resolve_wildcards %s %s failed\n",
6511 smb_fname_src->base_name, destname));
6512 TALLOC_FREE(talloced);
6513 continue;
6515 if (!destname) {
6516 status = NT_STATUS_NO_MEMORY;
6517 goto out;
6520 TALLOC_FREE(smb_fname_dst->base_name);
6521 smb_fname_dst->base_name = destname;
6523 ZERO_STRUCT(smb_fname_src->st);
6524 if (posix_pathnames) {
6525 SMB_VFS_LSTAT(conn, smb_fname_src);
6526 } else {
6527 SMB_VFS_STAT(conn, smb_fname_src);
6530 create_options = 0;
6532 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6533 create_options |= FILE_DIRECTORY_FILE;
6536 status = SMB_VFS_CREATE_FILE(
6537 conn, /* conn */
6538 req, /* req */
6539 0, /* root_dir_fid */
6540 smb_fname_src, /* fname */
6541 access_mask, /* access_mask */
6542 (FILE_SHARE_READ | /* share_access */
6543 FILE_SHARE_WRITE),
6544 FILE_OPEN, /* create_disposition*/
6545 create_options, /* create_options */
6546 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6547 0, /* oplock_request */
6548 0, /* allocation_size */
6549 0, /* private_flags */
6550 NULL, /* sd */
6551 NULL, /* ea_list */
6552 &fsp, /* result */
6553 NULL); /* pinfo */
6555 if (!NT_STATUS_IS_OK(status)) {
6556 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
6557 "returned %s rename %s -> %s\n",
6558 nt_errstr(status),
6559 smb_fname_str_dbg(smb_fname_src),
6560 smb_fname_str_dbg(smb_fname_dst)));
6561 break;
6564 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6565 dname);
6566 if (!smb_fname_dst->original_lcomp) {
6567 status = NT_STATUS_NO_MEMORY;
6568 goto out;
6571 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6572 attrs, replace_if_exists);
6574 close_file(req, fsp, NORMAL_CLOSE);
6576 if (!NT_STATUS_IS_OK(status)) {
6577 DEBUG(3, ("rename_internals_fsp returned %s for "
6578 "rename %s -> %s\n", nt_errstr(status),
6579 smb_fname_str_dbg(smb_fname_src),
6580 smb_fname_str_dbg(smb_fname_dst)));
6581 break;
6584 count++;
6586 DEBUG(3,("rename_internals: doing rename on %s -> "
6587 "%s\n", smb_fname_str_dbg(smb_fname_src),
6588 smb_fname_str_dbg(smb_fname_src)));
6589 TALLOC_FREE(talloced);
6591 TALLOC_FREE(dir_hnd);
6593 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
6594 status = map_nt_error_from_unix(errno);
6597 out:
6598 TALLOC_FREE(talloced);
6599 TALLOC_FREE(fname_src_dir);
6600 TALLOC_FREE(fname_src_mask);
6601 return status;
6604 /****************************************************************************
6605 Reply to a mv.
6606 ****************************************************************************/
6608 void reply_mv(struct smb_request *req)
6610 connection_struct *conn = req->conn;
6611 char *name = NULL;
6612 char *newname = NULL;
6613 const char *p;
6614 uint32 attrs;
6615 NTSTATUS status;
6616 bool src_has_wcard = False;
6617 bool dest_has_wcard = False;
6618 TALLOC_CTX *ctx = talloc_tos();
6619 struct smb_filename *smb_fname_src = NULL;
6620 struct smb_filename *smb_fname_dst = NULL;
6621 uint32_t src_ucf_flags = lp_posix_pathnames() ? UCF_UNIX_NAME_LOOKUP : UCF_COND_ALLOW_WCARD_LCOMP;
6622 uint32_t dst_ucf_flags = UCF_SAVE_LCOMP | (lp_posix_pathnames() ? 0 : UCF_COND_ALLOW_WCARD_LCOMP);
6623 bool stream_rename = false;
6625 START_PROFILE(SMBmv);
6627 if (req->wct < 1) {
6628 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6629 goto out;
6632 attrs = SVAL(req->vwv+0, 0);
6634 p = (const char *)req->buf + 1;
6635 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
6636 &status, &src_has_wcard);
6637 if (!NT_STATUS_IS_OK(status)) {
6638 reply_nterror(req, status);
6639 goto out;
6641 p++;
6642 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
6643 &status, &dest_has_wcard);
6644 if (!NT_STATUS_IS_OK(status)) {
6645 reply_nterror(req, status);
6646 goto out;
6649 if (!lp_posix_pathnames()) {
6650 /* The newname must begin with a ':' if the
6651 name contains a ':'. */
6652 if (strchr_m(name, ':')) {
6653 if (newname[0] != ':') {
6654 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6655 goto out;
6657 stream_rename = true;
6661 status = filename_convert(ctx,
6662 conn,
6663 req->flags2 & FLAGS2_DFS_PATHNAMES,
6664 name,
6665 src_ucf_flags,
6666 &src_has_wcard,
6667 &smb_fname_src);
6669 if (!NT_STATUS_IS_OK(status)) {
6670 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6671 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6672 ERRSRV, ERRbadpath);
6673 goto out;
6675 reply_nterror(req, status);
6676 goto out;
6679 status = filename_convert(ctx,
6680 conn,
6681 req->flags2 & FLAGS2_DFS_PATHNAMES,
6682 newname,
6683 dst_ucf_flags,
6684 &dest_has_wcard,
6685 &smb_fname_dst);
6687 if (!NT_STATUS_IS_OK(status)) {
6688 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6689 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6690 ERRSRV, ERRbadpath);
6691 goto out;
6693 reply_nterror(req, status);
6694 goto out;
6697 if (stream_rename) {
6698 /* smb_fname_dst->base_name must be the same as
6699 smb_fname_src->base_name. */
6700 TALLOC_FREE(smb_fname_dst->base_name);
6701 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
6702 smb_fname_src->base_name);
6703 if (!smb_fname_dst->base_name) {
6704 reply_nterror(req, NT_STATUS_NO_MEMORY);
6705 goto out;
6709 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
6710 smb_fname_str_dbg(smb_fname_dst)));
6712 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
6713 attrs, False, src_has_wcard, dest_has_wcard,
6714 DELETE_ACCESS);
6715 if (!NT_STATUS_IS_OK(status)) {
6716 if (open_was_deferred(req->mid)) {
6717 /* We have re-scheduled this call. */
6718 goto out;
6720 reply_nterror(req, status);
6721 goto out;
6724 reply_outbuf(req, 0, 0);
6725 out:
6726 TALLOC_FREE(smb_fname_src);
6727 TALLOC_FREE(smb_fname_dst);
6728 END_PROFILE(SMBmv);
6729 return;
6732 /*******************************************************************
6733 Copy a file as part of a reply_copy.
6734 ******************************************************************/
6737 * TODO: check error codes on all callers
6740 NTSTATUS copy_file(TALLOC_CTX *ctx,
6741 connection_struct *conn,
6742 struct smb_filename *smb_fname_src,
6743 struct smb_filename *smb_fname_dst,
6744 int ofun,
6745 int count,
6746 bool target_is_directory)
6748 struct smb_filename *smb_fname_dst_tmp = NULL;
6749 SMB_OFF_T ret=-1;
6750 files_struct *fsp1,*fsp2;
6751 uint32 dosattrs;
6752 uint32 new_create_disposition;
6753 NTSTATUS status;
6756 status = copy_smb_filename(ctx, smb_fname_dst, &smb_fname_dst_tmp);
6757 if (!NT_STATUS_IS_OK(status)) {
6758 return status;
6762 * If the target is a directory, extract the last component from the
6763 * src filename and append it to the dst filename
6765 if (target_is_directory) {
6766 const char *p;
6768 /* dest/target can't be a stream if it's a directory. */
6769 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
6771 p = strrchr_m(smb_fname_src->base_name,'/');
6772 if (p) {
6773 p++;
6774 } else {
6775 p = smb_fname_src->base_name;
6777 smb_fname_dst_tmp->base_name =
6778 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
6780 if (!smb_fname_dst_tmp->base_name) {
6781 status = NT_STATUS_NO_MEMORY;
6782 goto out;
6786 status = vfs_file_exist(conn, smb_fname_src);
6787 if (!NT_STATUS_IS_OK(status)) {
6788 goto out;
6791 if (!target_is_directory && count) {
6792 new_create_disposition = FILE_OPEN;
6793 } else {
6794 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
6795 0, ofun,
6796 NULL, NULL,
6797 &new_create_disposition,
6798 NULL,
6799 NULL)) {
6800 status = NT_STATUS_INVALID_PARAMETER;
6801 goto out;
6805 /* Open the src file for reading. */
6806 status = SMB_VFS_CREATE_FILE(
6807 conn, /* conn */
6808 NULL, /* req */
6809 0, /* root_dir_fid */
6810 smb_fname_src, /* fname */
6811 FILE_GENERIC_READ, /* access_mask */
6812 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6813 FILE_OPEN, /* create_disposition*/
6814 0, /* create_options */
6815 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
6816 INTERNAL_OPEN_ONLY, /* oplock_request */
6817 0, /* allocation_size */
6818 0, /* private_flags */
6819 NULL, /* sd */
6820 NULL, /* ea_list */
6821 &fsp1, /* result */
6822 NULL); /* psbuf */
6824 if (!NT_STATUS_IS_OK(status)) {
6825 goto out;
6828 dosattrs = dos_mode(conn, smb_fname_src);
6830 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
6831 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
6834 /* Open the dst file for writing. */
6835 status = SMB_VFS_CREATE_FILE(
6836 conn, /* conn */
6837 NULL, /* req */
6838 0, /* root_dir_fid */
6839 smb_fname_dst, /* fname */
6840 FILE_GENERIC_WRITE, /* access_mask */
6841 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6842 new_create_disposition, /* create_disposition*/
6843 0, /* create_options */
6844 dosattrs, /* file_attributes */
6845 INTERNAL_OPEN_ONLY, /* oplock_request */
6846 0, /* allocation_size */
6847 0, /* private_flags */
6848 NULL, /* sd */
6849 NULL, /* ea_list */
6850 &fsp2, /* result */
6851 NULL); /* psbuf */
6853 if (!NT_STATUS_IS_OK(status)) {
6854 close_file(NULL, fsp1, ERROR_CLOSE);
6855 goto out;
6858 if (ofun & OPENX_FILE_EXISTS_OPEN) {
6859 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
6860 if (ret == -1) {
6861 DEBUG(0, ("error - vfs lseek returned error %s\n",
6862 strerror(errno)));
6863 status = map_nt_error_from_unix(errno);
6864 close_file(NULL, fsp1, ERROR_CLOSE);
6865 close_file(NULL, fsp2, ERROR_CLOSE);
6866 goto out;
6870 /* Do the actual copy. */
6871 if (smb_fname_src->st.st_ex_size) {
6872 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
6873 } else {
6874 ret = 0;
6877 close_file(NULL, fsp1, NORMAL_CLOSE);
6879 /* Ensure the modtime is set correctly on the destination file. */
6880 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
6883 * As we are opening fsp1 read-only we only expect
6884 * an error on close on fsp2 if we are out of space.
6885 * Thus we don't look at the error return from the
6886 * close of fsp1.
6888 status = close_file(NULL, fsp2, NORMAL_CLOSE);
6890 if (!NT_STATUS_IS_OK(status)) {
6891 goto out;
6894 if (ret != (SMB_OFF_T)smb_fname_src->st.st_ex_size) {
6895 status = NT_STATUS_DISK_FULL;
6896 goto out;
6899 status = NT_STATUS_OK;
6901 out:
6902 TALLOC_FREE(smb_fname_dst_tmp);
6903 return status;
6906 /****************************************************************************
6907 Reply to a file copy.
6908 ****************************************************************************/
6910 void reply_copy(struct smb_request *req)
6912 connection_struct *conn = req->conn;
6913 struct smb_filename *smb_fname_src = NULL;
6914 struct smb_filename *smb_fname_dst = NULL;
6915 char *fname_src = NULL;
6916 char *fname_dst = NULL;
6917 char *fname_src_mask = NULL;
6918 char *fname_src_dir = NULL;
6919 const char *p;
6920 int count=0;
6921 int error = ERRnoaccess;
6922 int tid2;
6923 int ofun;
6924 int flags;
6925 bool target_is_directory=False;
6926 bool source_has_wild = False;
6927 bool dest_has_wild = False;
6928 NTSTATUS status;
6929 TALLOC_CTX *ctx = talloc_tos();
6931 START_PROFILE(SMBcopy);
6933 if (req->wct < 3) {
6934 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6935 goto out;
6938 tid2 = SVAL(req->vwv+0, 0);
6939 ofun = SVAL(req->vwv+1, 0);
6940 flags = SVAL(req->vwv+2, 0);
6942 p = (const char *)req->buf;
6943 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
6944 &status, &source_has_wild);
6945 if (!NT_STATUS_IS_OK(status)) {
6946 reply_nterror(req, status);
6947 goto out;
6949 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
6950 &status, &dest_has_wild);
6951 if (!NT_STATUS_IS_OK(status)) {
6952 reply_nterror(req, status);
6953 goto out;
6956 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
6958 if (tid2 != conn->cnum) {
6959 /* can't currently handle inter share copies XXXX */
6960 DEBUG(3,("Rejecting inter-share copy\n"));
6961 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
6962 goto out;
6965 status = filename_convert(ctx, conn,
6966 req->flags2 & FLAGS2_DFS_PATHNAMES,
6967 fname_src,
6968 UCF_COND_ALLOW_WCARD_LCOMP,
6969 &source_has_wild,
6970 &smb_fname_src);
6971 if (!NT_STATUS_IS_OK(status)) {
6972 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6973 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6974 ERRSRV, ERRbadpath);
6975 goto out;
6977 reply_nterror(req, status);
6978 goto out;
6981 status = filename_convert(ctx, conn,
6982 req->flags2 & FLAGS2_DFS_PATHNAMES,
6983 fname_dst,
6984 UCF_COND_ALLOW_WCARD_LCOMP,
6985 &dest_has_wild,
6986 &smb_fname_dst);
6987 if (!NT_STATUS_IS_OK(status)) {
6988 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6989 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6990 ERRSRV, ERRbadpath);
6991 goto out;
6993 reply_nterror(req, status);
6994 goto out;
6997 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
6999 if ((flags&1) && target_is_directory) {
7000 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
7001 goto out;
7004 if ((flags&2) && !target_is_directory) {
7005 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
7006 goto out;
7009 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
7010 /* wants a tree copy! XXXX */
7011 DEBUG(3,("Rejecting tree copy\n"));
7012 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7013 goto out;
7016 /* Split up the directory from the filename/mask. */
7017 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7018 &fname_src_dir, &fname_src_mask);
7019 if (!NT_STATUS_IS_OK(status)) {
7020 reply_nterror(req, NT_STATUS_NO_MEMORY);
7021 goto out;
7025 * We should only check the mangled cache
7026 * here if unix_convert failed. This means
7027 * that the path in 'mask' doesn't exist
7028 * on the file system and so we need to look
7029 * for a possible mangle. This patch from
7030 * Tine Smukavec <valentin.smukavec@hermes.si>.
7032 if (!VALID_STAT(smb_fname_src->st) &&
7033 mangle_is_mangled(fname_src_mask, conn->params)) {
7034 char *new_mask = NULL;
7035 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
7036 &new_mask, conn->params);
7038 /* Use demangled name if one was successfully found. */
7039 if (new_mask) {
7040 TALLOC_FREE(fname_src_mask);
7041 fname_src_mask = new_mask;
7045 if (!source_has_wild) {
7048 * Only one file needs to be copied. Append the mask back onto
7049 * the directory.
7051 TALLOC_FREE(smb_fname_src->base_name);
7052 if (ISDOT(fname_src_dir)) {
7053 /* Ensure we use canonical names on open. */
7054 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7055 "%s",
7056 fname_src_mask);
7057 } else {
7058 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7059 "%s/%s",
7060 fname_src_dir,
7061 fname_src_mask);
7063 if (!smb_fname_src->base_name) {
7064 reply_nterror(req, NT_STATUS_NO_MEMORY);
7065 goto out;
7068 if (dest_has_wild) {
7069 char *fname_dst_mod = NULL;
7070 if (!resolve_wildcards(smb_fname_dst,
7071 smb_fname_src->base_name,
7072 smb_fname_dst->base_name,
7073 &fname_dst_mod)) {
7074 reply_nterror(req, NT_STATUS_NO_MEMORY);
7075 goto out;
7077 TALLOC_FREE(smb_fname_dst->base_name);
7078 smb_fname_dst->base_name = fname_dst_mod;
7081 status = check_name(conn, smb_fname_src->base_name);
7082 if (!NT_STATUS_IS_OK(status)) {
7083 reply_nterror(req, status);
7084 goto out;
7087 status = check_name(conn, smb_fname_dst->base_name);
7088 if (!NT_STATUS_IS_OK(status)) {
7089 reply_nterror(req, status);
7090 goto out;
7093 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7094 ofun, count, target_is_directory);
7096 if(!NT_STATUS_IS_OK(status)) {
7097 reply_nterror(req, status);
7098 goto out;
7099 } else {
7100 count++;
7102 } else {
7103 struct smb_Dir *dir_hnd = NULL;
7104 const char *dname = NULL;
7105 char *talloced = NULL;
7106 long offset = 0;
7109 * There is a wildcard that requires us to actually read the
7110 * src dir and copy each file matching the mask to the dst.
7111 * Right now streams won't be copied, but this could
7112 * presumably be added with a nested loop for reach dir entry.
7114 SMB_ASSERT(!smb_fname_src->stream_name);
7115 SMB_ASSERT(!smb_fname_dst->stream_name);
7117 smb_fname_src->stream_name = NULL;
7118 smb_fname_dst->stream_name = NULL;
7120 if (strequal(fname_src_mask,"????????.???")) {
7121 TALLOC_FREE(fname_src_mask);
7122 fname_src_mask = talloc_strdup(ctx, "*");
7123 if (!fname_src_mask) {
7124 reply_nterror(req, NT_STATUS_NO_MEMORY);
7125 goto out;
7129 status = check_name(conn, fname_src_dir);
7130 if (!NT_STATUS_IS_OK(status)) {
7131 reply_nterror(req, status);
7132 goto out;
7135 dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0);
7136 if (dir_hnd == NULL) {
7137 status = map_nt_error_from_unix(errno);
7138 reply_nterror(req, status);
7139 goto out;
7142 error = ERRbadfile;
7144 /* Iterate over the src dir copying each entry to the dst. */
7145 while ((dname = ReadDirName(dir_hnd, &offset,
7146 &smb_fname_src->st, &talloced))) {
7147 char *destname = NULL;
7149 if (ISDOT(dname) || ISDOTDOT(dname)) {
7150 TALLOC_FREE(talloced);
7151 continue;
7154 if (!is_visible_file(conn, fname_src_dir, dname,
7155 &smb_fname_src->st, false)) {
7156 TALLOC_FREE(talloced);
7157 continue;
7160 if(!mask_match(dname, fname_src_mask,
7161 conn->case_sensitive)) {
7162 TALLOC_FREE(talloced);
7163 continue;
7166 error = ERRnoaccess;
7168 /* Get the src smb_fname struct setup. */
7169 TALLOC_FREE(smb_fname_src->base_name);
7170 if (ISDOT(fname_src_dir)) {
7171 /* Ensure we use canonical names on open. */
7172 smb_fname_src->base_name =
7173 talloc_asprintf(smb_fname_src, "%s",
7174 dname);
7175 } else {
7176 smb_fname_src->base_name =
7177 talloc_asprintf(smb_fname_src, "%s/%s",
7178 fname_src_dir, dname);
7181 if (!smb_fname_src->base_name) {
7182 TALLOC_FREE(dir_hnd);
7183 TALLOC_FREE(talloced);
7184 reply_nterror(req, NT_STATUS_NO_MEMORY);
7185 goto out;
7188 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7189 smb_fname_dst->base_name,
7190 &destname)) {
7191 TALLOC_FREE(talloced);
7192 continue;
7194 if (!destname) {
7195 TALLOC_FREE(dir_hnd);
7196 TALLOC_FREE(talloced);
7197 reply_nterror(req, NT_STATUS_NO_MEMORY);
7198 goto out;
7201 TALLOC_FREE(smb_fname_dst->base_name);
7202 smb_fname_dst->base_name = destname;
7204 status = check_name(conn, smb_fname_src->base_name);
7205 if (!NT_STATUS_IS_OK(status)) {
7206 TALLOC_FREE(dir_hnd);
7207 TALLOC_FREE(talloced);
7208 reply_nterror(req, status);
7209 goto out;
7212 status = check_name(conn, smb_fname_dst->base_name);
7213 if (!NT_STATUS_IS_OK(status)) {
7214 TALLOC_FREE(dir_hnd);
7215 TALLOC_FREE(talloced);
7216 reply_nterror(req, status);
7217 goto out;
7220 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7221 smb_fname_src->base_name,
7222 smb_fname_dst->base_name));
7224 status = copy_file(ctx, conn, smb_fname_src,
7225 smb_fname_dst, ofun, count,
7226 target_is_directory);
7227 if (NT_STATUS_IS_OK(status)) {
7228 count++;
7231 TALLOC_FREE(talloced);
7233 TALLOC_FREE(dir_hnd);
7236 if (count == 0) {
7237 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7238 goto out;
7241 reply_outbuf(req, 1, 0);
7242 SSVAL(req->outbuf,smb_vwv0,count);
7243 out:
7244 TALLOC_FREE(smb_fname_src);
7245 TALLOC_FREE(smb_fname_dst);
7246 TALLOC_FREE(fname_src);
7247 TALLOC_FREE(fname_dst);
7248 TALLOC_FREE(fname_src_mask);
7249 TALLOC_FREE(fname_src_dir);
7251 END_PROFILE(SMBcopy);
7252 return;
7255 #undef DBGC_CLASS
7256 #define DBGC_CLASS DBGC_LOCKING
7258 /****************************************************************************
7259 Get a lock pid, dealing with large count requests.
7260 ****************************************************************************/
7262 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7263 bool large_file_format)
7265 if(!large_file_format)
7266 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7267 else
7268 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7271 /****************************************************************************
7272 Get a lock count, dealing with large count requests.
7273 ****************************************************************************/
7275 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7276 bool large_file_format)
7278 uint64_t count = 0;
7280 if(!large_file_format) {
7281 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7282 } else {
7284 #if defined(HAVE_LONGLONG)
7285 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7286 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7287 #else /* HAVE_LONGLONG */
7290 * NT4.x seems to be broken in that it sends large file (64 bit)
7291 * lockingX calls even if the CAP_LARGE_FILES was *not*
7292 * negotiated. For boxes without large unsigned ints truncate the
7293 * lock count by dropping the top 32 bits.
7296 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
7297 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
7298 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
7299 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
7300 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
7303 count = (uint64_t)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
7304 #endif /* HAVE_LONGLONG */
7307 return count;
7310 #if !defined(HAVE_LONGLONG)
7311 /****************************************************************************
7312 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
7313 ****************************************************************************/
7315 static uint32 map_lock_offset(uint32 high, uint32 low)
7317 unsigned int i;
7318 uint32 mask = 0;
7319 uint32 highcopy = high;
7322 * Try and find out how many significant bits there are in high.
7325 for(i = 0; highcopy; i++)
7326 highcopy >>= 1;
7329 * We use 31 bits not 32 here as POSIX
7330 * lock offsets may not be negative.
7333 mask = (~0) << (31 - i);
7335 if(low & mask)
7336 return 0; /* Fail. */
7338 high <<= (31 - i);
7340 return (high|low);
7342 #endif /* !defined(HAVE_LONGLONG) */
7344 /****************************************************************************
7345 Get a lock offset, dealing with large offset requests.
7346 ****************************************************************************/
7348 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7349 bool large_file_format, bool *err)
7351 uint64_t offset = 0;
7353 *err = False;
7355 if(!large_file_format) {
7356 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7357 } else {
7359 #if defined(HAVE_LONGLONG)
7360 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7361 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7362 #else /* HAVE_LONGLONG */
7365 * NT4.x seems to be broken in that it sends large file (64 bit)
7366 * lockingX calls even if the CAP_LARGE_FILES was *not*
7367 * negotiated. For boxes without large unsigned ints mangle the
7368 * lock offset by mapping the top 32 bits onto the lower 32.
7371 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
7372 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7373 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
7374 uint32 new_low = 0;
7376 if((new_low = map_lock_offset(high, low)) == 0) {
7377 *err = True;
7378 return (uint64_t)-1;
7381 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
7382 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
7383 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
7384 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
7387 offset = (uint64_t)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7388 #endif /* HAVE_LONGLONG */
7391 return offset;
7394 NTSTATUS smbd_do_locking(struct smb_request *req,
7395 files_struct *fsp,
7396 uint8_t type,
7397 int32_t timeout,
7398 uint16_t num_ulocks,
7399 struct smbd_lock_element *ulocks,
7400 uint16_t num_locks,
7401 struct smbd_lock_element *locks,
7402 bool *async)
7404 connection_struct *conn = req->conn;
7405 int i;
7406 NTSTATUS status = NT_STATUS_OK;
7408 *async = false;
7410 /* Data now points at the beginning of the list
7411 of smb_unlkrng structs */
7412 for(i = 0; i < (int)num_ulocks; i++) {
7413 struct smbd_lock_element *e = &ulocks[i];
7415 DEBUG(10,("smbd_do_locking: unlock start=%.0f, len=%.0f for "
7416 "pid %u, file %s\n",
7417 (double)e->offset,
7418 (double)e->count,
7419 (unsigned int)e->smblctx,
7420 fsp_str_dbg(fsp)));
7422 if (e->brltype != UNLOCK_LOCK) {
7423 /* this can only happen with SMB2 */
7424 return NT_STATUS_INVALID_PARAMETER;
7427 status = do_unlock(req->sconn->msg_ctx,
7428 fsp,
7429 e->smblctx,
7430 e->count,
7431 e->offset,
7432 WINDOWS_LOCK);
7434 DEBUG(10, ("smbd_do_locking: unlock returned %s\n",
7435 nt_errstr(status)));
7437 if (!NT_STATUS_IS_OK(status)) {
7438 return status;
7442 /* Setup the timeout in seconds. */
7444 if (!lp_blocking_locks(SNUM(conn))) {
7445 timeout = 0;
7448 /* Data now points at the beginning of the list
7449 of smb_lkrng structs */
7451 for(i = 0; i < (int)num_locks; i++) {
7452 struct smbd_lock_element *e = &locks[i];
7454 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
7455 "%llu, file %s timeout = %d\n",
7456 (double)e->offset,
7457 (double)e->count,
7458 (unsigned long long)e->smblctx,
7459 fsp_str_dbg(fsp),
7460 (int)timeout));
7462 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7463 struct blocking_lock_record *blr = NULL;
7465 if (num_locks > 1) {
7467 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
7468 * if the lock vector contains one entry. When given mutliple cancel
7469 * requests in a single PDU we expect the server to return an
7470 * error. Windows servers seem to accept the request but only
7471 * cancel the first lock.
7472 * JRA - Do what Windows does (tm) :-).
7475 #if 0
7476 /* MS-CIFS (2.2.4.32.1) behavior. */
7477 return NT_STATUS_DOS(ERRDOS,
7478 ERRcancelviolation);
7479 #else
7480 /* Windows behavior. */
7481 if (i != 0) {
7482 DEBUG(10,("smbd_do_locking: ignoring subsequent "
7483 "cancel request\n"));
7484 continue;
7486 #endif
7489 if (lp_blocking_locks(SNUM(conn))) {
7491 /* Schedule a message to ourselves to
7492 remove the blocking lock record and
7493 return the right error. */
7495 blr = blocking_lock_cancel_smb1(fsp,
7496 e->smblctx,
7497 e->offset,
7498 e->count,
7499 WINDOWS_LOCK,
7500 type,
7501 NT_STATUS_FILE_LOCK_CONFLICT);
7502 if (blr == NULL) {
7503 return NT_STATUS_DOS(
7504 ERRDOS,
7505 ERRcancelviolation);
7508 /* Remove a matching pending lock. */
7509 status = do_lock_cancel(fsp,
7510 e->smblctx,
7511 e->count,
7512 e->offset,
7513 WINDOWS_LOCK,
7514 blr);
7515 } else {
7516 bool blocking_lock = timeout ? true : false;
7517 bool defer_lock = false;
7518 struct byte_range_lock *br_lck;
7519 uint64_t block_smblctx;
7521 br_lck = do_lock(req->sconn->msg_ctx,
7522 fsp,
7523 e->smblctx,
7524 e->count,
7525 e->offset,
7526 e->brltype,
7527 WINDOWS_LOCK,
7528 blocking_lock,
7529 &status,
7530 &block_smblctx,
7531 NULL);
7533 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
7534 /* Windows internal resolution for blocking locks seems
7535 to be about 200ms... Don't wait for less than that. JRA. */
7536 if (timeout != -1 && timeout < lp_lock_spin_time()) {
7537 timeout = lp_lock_spin_time();
7539 defer_lock = true;
7542 /* If a lock sent with timeout of zero would fail, and
7543 * this lock has been requested multiple times,
7544 * according to brl_lock_failed() we convert this
7545 * request to a blocking lock with a timeout of between
7546 * 150 - 300 milliseconds.
7548 * If lp_lock_spin_time() has been set to 0, we skip
7549 * this blocking retry and fail immediately.
7551 * Replacement for do_lock_spin(). JRA. */
7553 if (!req->sconn->using_smb2 &&
7554 br_lck && lp_blocking_locks(SNUM(conn)) &&
7555 lp_lock_spin_time() && !blocking_lock &&
7556 NT_STATUS_EQUAL((status),
7557 NT_STATUS_FILE_LOCK_CONFLICT))
7559 defer_lock = true;
7560 timeout = lp_lock_spin_time();
7563 if (br_lck && defer_lock) {
7565 * A blocking lock was requested. Package up
7566 * this smb into a queued request and push it
7567 * onto the blocking lock queue.
7569 if(push_blocking_lock_request(br_lck,
7570 req,
7571 fsp,
7572 timeout,
7574 e->smblctx,
7575 e->brltype,
7576 WINDOWS_LOCK,
7577 e->offset,
7578 e->count,
7579 block_smblctx)) {
7580 TALLOC_FREE(br_lck);
7581 *async = true;
7582 return NT_STATUS_OK;
7586 TALLOC_FREE(br_lck);
7589 if (!NT_STATUS_IS_OK(status)) {
7590 break;
7594 /* If any of the above locks failed, then we must unlock
7595 all of the previous locks (X/Open spec). */
7597 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
7599 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7600 i = -1; /* we want to skip the for loop */
7604 * Ensure we don't do a remove on the lock that just failed,
7605 * as under POSIX rules, if we have a lock already there, we
7606 * will delete it (and we shouldn't) .....
7608 for(i--; i >= 0; i--) {
7609 struct smbd_lock_element *e = &locks[i];
7611 do_unlock(req->sconn->msg_ctx,
7612 fsp,
7613 e->smblctx,
7614 e->count,
7615 e->offset,
7616 WINDOWS_LOCK);
7618 return status;
7621 DEBUG(3, ("smbd_do_locking: fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
7622 fsp->fnum, (unsigned int)type, num_locks, num_ulocks));
7624 return NT_STATUS_OK;
7627 /****************************************************************************
7628 Reply to a lockingX request.
7629 ****************************************************************************/
7631 void reply_lockingX(struct smb_request *req)
7633 connection_struct *conn = req->conn;
7634 files_struct *fsp;
7635 unsigned char locktype;
7636 unsigned char oplocklevel;
7637 uint16 num_ulocks;
7638 uint16 num_locks;
7639 int32 lock_timeout;
7640 int i;
7641 const uint8_t *data;
7642 bool large_file_format;
7643 bool err;
7644 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
7645 struct smbd_lock_element *ulocks;
7646 struct smbd_lock_element *locks;
7647 bool async = false;
7649 START_PROFILE(SMBlockingX);
7651 if (req->wct < 8) {
7652 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7653 END_PROFILE(SMBlockingX);
7654 return;
7657 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
7658 locktype = CVAL(req->vwv+3, 0);
7659 oplocklevel = CVAL(req->vwv+3, 1);
7660 num_ulocks = SVAL(req->vwv+6, 0);
7661 num_locks = SVAL(req->vwv+7, 0);
7662 lock_timeout = IVAL(req->vwv+4, 0);
7663 large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
7665 if (!check_fsp(conn, req, fsp)) {
7666 END_PROFILE(SMBlockingX);
7667 return;
7670 data = req->buf;
7672 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
7673 /* we don't support these - and CANCEL_LOCK makes w2k
7674 and XP reboot so I don't really want to be
7675 compatible! (tridge) */
7676 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
7677 END_PROFILE(SMBlockingX);
7678 return;
7681 /* Check if this is an oplock break on a file
7682 we have granted an oplock on.
7684 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
7685 /* Client can insist on breaking to none. */
7686 bool break_to_none = (oplocklevel == 0);
7687 bool result;
7689 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
7690 "for fnum = %d\n", (unsigned int)oplocklevel,
7691 fsp->fnum ));
7694 * Make sure we have granted an exclusive or batch oplock on
7695 * this file.
7698 if (fsp->oplock_type == 0) {
7700 /* The Samba4 nbench simulator doesn't understand
7701 the difference between break to level2 and break
7702 to none from level2 - it sends oplock break
7703 replies in both cases. Don't keep logging an error
7704 message here - just ignore it. JRA. */
7706 DEBUG(5,("reply_lockingX: Error : oplock break from "
7707 "client for fnum = %d (oplock=%d) and no "
7708 "oplock granted on this file (%s).\n",
7709 fsp->fnum, fsp->oplock_type,
7710 fsp_str_dbg(fsp)));
7712 /* if this is a pure oplock break request then don't
7713 * send a reply */
7714 if (num_locks == 0 && num_ulocks == 0) {
7715 END_PROFILE(SMBlockingX);
7716 return;
7717 } else {
7718 END_PROFILE(SMBlockingX);
7719 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
7720 return;
7724 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
7725 (break_to_none)) {
7726 result = remove_oplock(fsp);
7727 } else {
7728 result = downgrade_oplock(fsp);
7731 if (!result) {
7732 DEBUG(0, ("reply_lockingX: error in removing "
7733 "oplock on file %s\n", fsp_str_dbg(fsp)));
7734 /* Hmmm. Is this panic justified? */
7735 smb_panic("internal tdb error");
7738 reply_to_oplock_break_requests(fsp);
7740 /* if this is a pure oplock break request then don't send a
7741 * reply */
7742 if (num_locks == 0 && num_ulocks == 0) {
7743 /* Sanity check - ensure a pure oplock break is not a
7744 chained request. */
7745 if(CVAL(req->vwv+0, 0) != 0xff)
7746 DEBUG(0,("reply_lockingX: Error : pure oplock "
7747 "break is a chained %d request !\n",
7748 (unsigned int)CVAL(req->vwv+0, 0)));
7749 END_PROFILE(SMBlockingX);
7750 return;
7754 if (req->buflen <
7755 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
7756 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7757 END_PROFILE(SMBlockingX);
7758 return;
7761 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
7762 if (ulocks == NULL) {
7763 reply_nterror(req, NT_STATUS_NO_MEMORY);
7764 END_PROFILE(SMBlockingX);
7765 return;
7768 locks = talloc_array(req, struct smbd_lock_element, num_locks);
7769 if (locks == NULL) {
7770 reply_nterror(req, NT_STATUS_NO_MEMORY);
7771 END_PROFILE(SMBlockingX);
7772 return;
7775 /* Data now points at the beginning of the list
7776 of smb_unlkrng structs */
7777 for(i = 0; i < (int)num_ulocks; i++) {
7778 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
7779 ulocks[i].count = get_lock_count(data, i, large_file_format);
7780 ulocks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7781 ulocks[i].brltype = UNLOCK_LOCK;
7784 * There is no error code marked "stupid client bug".... :-).
7786 if(err) {
7787 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7788 END_PROFILE(SMBlockingX);
7789 return;
7793 /* Now do any requested locks */
7794 data += ((large_file_format ? 20 : 10)*num_ulocks);
7796 /* Data now points at the beginning of the list
7797 of smb_lkrng structs */
7799 for(i = 0; i < (int)num_locks; i++) {
7800 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
7801 locks[i].count = get_lock_count(data, i, large_file_format);
7802 locks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7804 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
7805 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7806 locks[i].brltype = PENDING_READ_LOCK;
7807 } else {
7808 locks[i].brltype = READ_LOCK;
7810 } else {
7811 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7812 locks[i].brltype = PENDING_WRITE_LOCK;
7813 } else {
7814 locks[i].brltype = WRITE_LOCK;
7819 * There is no error code marked "stupid client bug".... :-).
7821 if(err) {
7822 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7823 END_PROFILE(SMBlockingX);
7824 return;
7828 status = smbd_do_locking(req, fsp,
7829 locktype, lock_timeout,
7830 num_ulocks, ulocks,
7831 num_locks, locks,
7832 &async);
7833 if (!NT_STATUS_IS_OK(status)) {
7834 END_PROFILE(SMBlockingX);
7835 reply_nterror(req, status);
7836 return;
7838 if (async) {
7839 END_PROFILE(SMBlockingX);
7840 return;
7843 reply_outbuf(req, 2, 0);
7845 DEBUG(3, ("lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
7846 fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks));
7848 END_PROFILE(SMBlockingX);
7849 chain_reply(req);
7852 #undef DBGC_CLASS
7853 #define DBGC_CLASS DBGC_ALL
7855 /****************************************************************************
7856 Reply to a SMBreadbmpx (read block multiplex) request.
7857 Always reply with an error, if someone has a platform really needs this,
7858 please contact vl@samba.org
7859 ****************************************************************************/
7861 void reply_readbmpx(struct smb_request *req)
7863 START_PROFILE(SMBreadBmpx);
7864 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7865 END_PROFILE(SMBreadBmpx);
7866 return;
7869 /****************************************************************************
7870 Reply to a SMBreadbs (read block multiplex secondary) request.
7871 Always reply with an error, if someone has a platform really needs this,
7872 please contact vl@samba.org
7873 ****************************************************************************/
7875 void reply_readbs(struct smb_request *req)
7877 START_PROFILE(SMBreadBs);
7878 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7879 END_PROFILE(SMBreadBs);
7880 return;
7883 /****************************************************************************
7884 Reply to a SMBsetattrE.
7885 ****************************************************************************/
7887 void reply_setattrE(struct smb_request *req)
7889 connection_struct *conn = req->conn;
7890 struct smb_file_time ft;
7891 files_struct *fsp;
7892 NTSTATUS status;
7894 START_PROFILE(SMBsetattrE);
7895 ZERO_STRUCT(ft);
7897 if (req->wct < 7) {
7898 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7899 goto out;
7902 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
7904 if(!fsp || (fsp->conn != conn)) {
7905 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
7906 goto out;
7910 * Convert the DOS times into unix times.
7913 ft.atime = convert_time_t_to_timespec(
7914 srv_make_unix_date2(req->vwv+3));
7915 ft.mtime = convert_time_t_to_timespec(
7916 srv_make_unix_date2(req->vwv+5));
7917 ft.create_time = convert_time_t_to_timespec(
7918 srv_make_unix_date2(req->vwv+1));
7920 reply_outbuf(req, 0, 0);
7923 * Patch from Ray Frush <frush@engr.colostate.edu>
7924 * Sometimes times are sent as zero - ignore them.
7927 /* Ensure we have a valid stat struct for the source. */
7928 status = vfs_stat_fsp(fsp);
7929 if (!NT_STATUS_IS_OK(status)) {
7930 reply_nterror(req, status);
7931 goto out;
7934 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
7935 if (!NT_STATUS_IS_OK(status)) {
7936 reply_nterror(req, status);
7937 goto out;
7940 DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u "
7941 " createtime=%u\n",
7942 fsp->fnum,
7943 (unsigned int)ft.atime.tv_sec,
7944 (unsigned int)ft.mtime.tv_sec,
7945 (unsigned int)ft.create_time.tv_sec
7947 out:
7948 END_PROFILE(SMBsetattrE);
7949 return;
7953 /* Back from the dead for OS/2..... JRA. */
7955 /****************************************************************************
7956 Reply to a SMBwritebmpx (write block multiplex primary) request.
7957 Always reply with an error, if someone has a platform really needs this,
7958 please contact vl@samba.org
7959 ****************************************************************************/
7961 void reply_writebmpx(struct smb_request *req)
7963 START_PROFILE(SMBwriteBmpx);
7964 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7965 END_PROFILE(SMBwriteBmpx);
7966 return;
7969 /****************************************************************************
7970 Reply to a SMBwritebs (write block multiplex secondary) request.
7971 Always reply with an error, if someone has a platform really needs this,
7972 please contact vl@samba.org
7973 ****************************************************************************/
7975 void reply_writebs(struct smb_request *req)
7977 START_PROFILE(SMBwriteBs);
7978 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7979 END_PROFILE(SMBwriteBs);
7980 return;
7983 /****************************************************************************
7984 Reply to a SMBgetattrE.
7985 ****************************************************************************/
7987 void reply_getattrE(struct smb_request *req)
7989 connection_struct *conn = req->conn;
7990 int mode;
7991 files_struct *fsp;
7992 struct timespec create_ts;
7994 START_PROFILE(SMBgetattrE);
7996 if (req->wct < 1) {
7997 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7998 END_PROFILE(SMBgetattrE);
7999 return;
8002 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8004 if(!fsp || (fsp->conn != conn)) {
8005 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8006 END_PROFILE(SMBgetattrE);
8007 return;
8010 /* Do an fstat on this file */
8011 if(fsp_stat(fsp)) {
8012 reply_nterror(req, map_nt_error_from_unix(errno));
8013 END_PROFILE(SMBgetattrE);
8014 return;
8017 mode = dos_mode(conn, fsp->fsp_name);
8020 * Convert the times into dos times. Set create
8021 * date to be last modify date as UNIX doesn't save
8022 * this.
8025 reply_outbuf(req, 11, 0);
8027 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
8028 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
8029 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
8030 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
8031 /* Should we check pending modtime here ? JRA */
8032 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
8033 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
8035 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
8036 SIVAL(req->outbuf, smb_vwv6, 0);
8037 SIVAL(req->outbuf, smb_vwv8, 0);
8038 } else {
8039 uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8040 SIVAL(req->outbuf, smb_vwv6, (uint32)fsp->fsp_name->st.st_ex_size);
8041 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8043 SSVAL(req->outbuf,smb_vwv10, mode);
8045 DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
8047 END_PROFILE(SMBgetattrE);
8048 return;