Fix bug #9587 - archive flag is always set on directories.
[Samba.git] / source3 / smbd / reply.c
bloba708fd83dd2d99a157ab75f234f032a2470fc8d0
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 *fname = NULL;
2243 uint32 fattr;
2244 files_struct *fsp;
2245 int oplock_request;
2246 int tmpfd;
2247 char *s;
2248 NTSTATUS status;
2249 TALLOC_CTX *ctx = talloc_tos();
2251 START_PROFILE(SMBctemp);
2253 if (req->wct < 3) {
2254 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2255 goto out;
2258 fattr = SVAL(req->vwv+0, 0);
2259 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2261 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
2262 STR_TERMINATE, &status);
2263 if (!NT_STATUS_IS_OK(status)) {
2264 reply_nterror(req, status);
2265 goto out;
2267 if (*fname) {
2268 fname = talloc_asprintf(ctx,
2269 "%s/TMXXXXXX",
2270 fname);
2271 } else {
2272 fname = talloc_strdup(ctx, "TMXXXXXX");
2275 if (!fname) {
2276 reply_nterror(req, NT_STATUS_NO_MEMORY);
2277 goto out;
2280 status = filename_convert(ctx, conn,
2281 req->flags2 & FLAGS2_DFS_PATHNAMES,
2282 fname,
2284 NULL,
2285 &smb_fname);
2286 if (!NT_STATUS_IS_OK(status)) {
2287 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2288 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2289 ERRSRV, ERRbadpath);
2290 goto out;
2292 reply_nterror(req, status);
2293 goto out;
2296 tmpfd = mkstemp(smb_fname->base_name);
2297 if (tmpfd == -1) {
2298 reply_nterror(req, map_nt_error_from_unix(errno));
2299 goto out;
2302 SMB_VFS_STAT(conn, smb_fname);
2304 /* We should fail if file does not exist. */
2305 status = SMB_VFS_CREATE_FILE(
2306 conn, /* conn */
2307 req, /* req */
2308 0, /* root_dir_fid */
2309 smb_fname, /* fname */
2310 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2311 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2312 FILE_OPEN, /* create_disposition*/
2313 0, /* create_options */
2314 fattr, /* file_attributes */
2315 oplock_request, /* oplock_request */
2316 0, /* allocation_size */
2317 0, /* private_flags */
2318 NULL, /* sd */
2319 NULL, /* ea_list */
2320 &fsp, /* result */
2321 NULL); /* pinfo */
2323 /* close fd from mkstemp() */
2324 close(tmpfd);
2326 if (!NT_STATUS_IS_OK(status)) {
2327 if (open_was_deferred(req->mid)) {
2328 /* We have re-scheduled this call. */
2329 goto out;
2331 reply_openerror(req, status);
2332 goto out;
2335 reply_outbuf(req, 1, 0);
2336 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2338 /* the returned filename is relative to the directory */
2339 s = strrchr_m(fsp->fsp_name->base_name, '/');
2340 if (!s) {
2341 s = fsp->fsp_name->base_name;
2342 } else {
2343 s++;
2346 #if 0
2347 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2348 thing in the byte section. JRA */
2349 SSVALS(p, 0, -1); /* what is this? not in spec */
2350 #endif
2351 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2352 == -1) {
2353 reply_nterror(req, NT_STATUS_NO_MEMORY);
2354 goto out;
2357 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2358 SCVAL(req->outbuf, smb_flg,
2359 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2362 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2363 SCVAL(req->outbuf, smb_flg,
2364 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2367 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2368 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2369 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2370 out:
2371 TALLOC_FREE(smb_fname);
2372 END_PROFILE(SMBctemp);
2373 return;
2376 /*******************************************************************
2377 Check if a user is allowed to rename a file.
2378 ********************************************************************/
2380 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2381 uint16 dirtype)
2383 if (!CAN_WRITE(conn)) {
2384 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2387 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
2388 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2389 /* Only bother to read the DOS attribute if we might deny the
2390 rename on the grounds of attribute missmatch. */
2391 uint32_t fmode = dos_mode(conn, fsp->fsp_name);
2392 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2393 return NT_STATUS_NO_SUCH_FILE;
2397 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2398 if (fsp->posix_open) {
2399 return NT_STATUS_OK;
2402 /* If no pathnames are open below this
2403 directory, allow the rename. */
2405 if (file_find_subpath(fsp)) {
2406 return NT_STATUS_ACCESS_DENIED;
2408 return NT_STATUS_OK;
2411 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2412 return NT_STATUS_OK;
2415 return NT_STATUS_ACCESS_DENIED;
2418 /*******************************************************************
2419 * unlink a file with all relevant access checks
2420 *******************************************************************/
2422 static NTSTATUS do_unlink(connection_struct *conn,
2423 struct smb_request *req,
2424 struct smb_filename *smb_fname,
2425 uint32 dirtype)
2427 uint32 fattr;
2428 files_struct *fsp;
2429 uint32 dirtype_orig = dirtype;
2430 NTSTATUS status;
2431 int ret;
2432 bool posix_paths = lp_posix_pathnames();
2434 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2435 smb_fname_str_dbg(smb_fname),
2436 dirtype));
2438 if (!CAN_WRITE(conn)) {
2439 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2442 if (posix_paths) {
2443 ret = SMB_VFS_LSTAT(conn, smb_fname);
2444 } else {
2445 ret = SMB_VFS_STAT(conn, smb_fname);
2447 if (ret != 0) {
2448 return map_nt_error_from_unix(errno);
2451 fattr = dos_mode(conn, smb_fname);
2453 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2454 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
2457 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
2458 if (!dirtype) {
2459 return NT_STATUS_NO_SUCH_FILE;
2462 if (!dir_check_ftype(conn, fattr, dirtype)) {
2463 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2464 return NT_STATUS_FILE_IS_A_DIRECTORY;
2466 return NT_STATUS_NO_SUCH_FILE;
2469 if (dirtype_orig & 0x8000) {
2470 /* These will never be set for POSIX. */
2471 return NT_STATUS_NO_SUCH_FILE;
2474 #if 0
2475 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2476 return NT_STATUS_FILE_IS_A_DIRECTORY;
2479 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2480 return NT_STATUS_NO_SUCH_FILE;
2483 if (dirtype & 0xFF00) {
2484 /* These will never be set for POSIX. */
2485 return NT_STATUS_NO_SUCH_FILE;
2488 dirtype &= 0xFF;
2489 if (!dirtype) {
2490 return NT_STATUS_NO_SUCH_FILE;
2493 /* Can't delete a directory. */
2494 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2495 return NT_STATUS_FILE_IS_A_DIRECTORY;
2497 #endif
2499 #if 0 /* JRATEST */
2500 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
2501 return NT_STATUS_OBJECT_NAME_INVALID;
2502 #endif /* JRATEST */
2504 /* On open checks the open itself will check the share mode, so
2505 don't do it here as we'll get it wrong. */
2507 status = SMB_VFS_CREATE_FILE
2508 (conn, /* conn */
2509 req, /* req */
2510 0, /* root_dir_fid */
2511 smb_fname, /* fname */
2512 DELETE_ACCESS, /* access_mask */
2513 FILE_SHARE_NONE, /* share_access */
2514 FILE_OPEN, /* create_disposition*/
2515 FILE_NON_DIRECTORY_FILE, /* create_options */
2516 /* file_attributes */
2517 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2518 FILE_ATTRIBUTE_NORMAL,
2519 0, /* oplock_request */
2520 0, /* allocation_size */
2521 0, /* private_flags */
2522 NULL, /* sd */
2523 NULL, /* ea_list */
2524 &fsp, /* result */
2525 NULL); /* pinfo */
2527 if (!NT_STATUS_IS_OK(status)) {
2528 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2529 nt_errstr(status)));
2530 return status;
2533 status = can_set_delete_on_close(fsp, fattr);
2534 if (!NT_STATUS_IS_OK(status)) {
2535 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2536 "(%s)\n",
2537 smb_fname_str_dbg(smb_fname),
2538 nt_errstr(status)));
2539 close_file(req, fsp, NORMAL_CLOSE);
2540 return status;
2543 /* The set is across all open files on this dev/inode pair. */
2544 if (!set_delete_on_close(fsp, true,
2545 conn->session_info->security_token,
2546 &conn->session_info->utok)) {
2547 close_file(req, fsp, NORMAL_CLOSE);
2548 return NT_STATUS_ACCESS_DENIED;
2551 return close_file(req, fsp, NORMAL_CLOSE);
2554 /****************************************************************************
2555 The guts of the unlink command, split out so it may be called by the NT SMB
2556 code.
2557 ****************************************************************************/
2559 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2560 uint32 dirtype, struct smb_filename *smb_fname,
2561 bool has_wild)
2563 char *fname_dir = NULL;
2564 char *fname_mask = NULL;
2565 int count=0;
2566 NTSTATUS status = NT_STATUS_OK;
2567 TALLOC_CTX *ctx = talloc_tos();
2569 /* Split up the directory from the filename/mask. */
2570 status = split_fname_dir_mask(ctx, smb_fname->base_name,
2571 &fname_dir, &fname_mask);
2572 if (!NT_STATUS_IS_OK(status)) {
2573 goto out;
2577 * We should only check the mangled cache
2578 * here if unix_convert failed. This means
2579 * that the path in 'mask' doesn't exist
2580 * on the file system and so we need to look
2581 * for a possible mangle. This patch from
2582 * Tine Smukavec <valentin.smukavec@hermes.si>.
2585 if (!VALID_STAT(smb_fname->st) &&
2586 mangle_is_mangled(fname_mask, conn->params)) {
2587 char *new_mask = NULL;
2588 mangle_lookup_name_from_8_3(ctx, fname_mask,
2589 &new_mask, conn->params);
2590 if (new_mask) {
2591 TALLOC_FREE(fname_mask);
2592 fname_mask = new_mask;
2596 if (!has_wild) {
2599 * Only one file needs to be unlinked. Append the mask back
2600 * onto the directory.
2602 TALLOC_FREE(smb_fname->base_name);
2603 if (ISDOT(fname_dir)) {
2604 /* Ensure we use canonical names on open. */
2605 smb_fname->base_name = talloc_asprintf(smb_fname,
2606 "%s",
2607 fname_mask);
2608 } else {
2609 smb_fname->base_name = talloc_asprintf(smb_fname,
2610 "%s/%s",
2611 fname_dir,
2612 fname_mask);
2614 if (!smb_fname->base_name) {
2615 status = NT_STATUS_NO_MEMORY;
2616 goto out;
2618 if (dirtype == 0) {
2619 dirtype = FILE_ATTRIBUTE_NORMAL;
2622 status = check_name(conn, smb_fname->base_name);
2623 if (!NT_STATUS_IS_OK(status)) {
2624 goto out;
2627 status = do_unlink(conn, req, smb_fname, dirtype);
2628 if (!NT_STATUS_IS_OK(status)) {
2629 goto out;
2632 count++;
2633 } else {
2634 struct smb_Dir *dir_hnd = NULL;
2635 long offset = 0;
2636 const char *dname = NULL;
2637 char *talloced = NULL;
2639 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
2640 status = NT_STATUS_OBJECT_NAME_INVALID;
2641 goto out;
2644 if (strequal(fname_mask,"????????.???")) {
2645 TALLOC_FREE(fname_mask);
2646 fname_mask = talloc_strdup(ctx, "*");
2647 if (!fname_mask) {
2648 status = NT_STATUS_NO_MEMORY;
2649 goto out;
2653 status = check_name(conn, fname_dir);
2654 if (!NT_STATUS_IS_OK(status)) {
2655 goto out;
2658 dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask,
2659 dirtype);
2660 if (dir_hnd == NULL) {
2661 status = map_nt_error_from_unix(errno);
2662 goto out;
2665 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2666 the pattern matches against the long name, otherwise the short name
2667 We don't implement this yet XXXX
2670 status = NT_STATUS_NO_SUCH_FILE;
2672 while ((dname = ReadDirName(dir_hnd, &offset,
2673 &smb_fname->st, &talloced))) {
2674 TALLOC_CTX *frame = talloc_stackframe();
2676 if (!is_visible_file(conn, fname_dir, dname,
2677 &smb_fname->st, true)) {
2678 TALLOC_FREE(frame);
2679 TALLOC_FREE(talloced);
2680 continue;
2683 /* Quick check for "." and ".." */
2684 if (ISDOT(dname) || ISDOTDOT(dname)) {
2685 TALLOC_FREE(frame);
2686 TALLOC_FREE(talloced);
2687 continue;
2690 if(!mask_match(dname, fname_mask,
2691 conn->case_sensitive)) {
2692 TALLOC_FREE(frame);
2693 TALLOC_FREE(talloced);
2694 continue;
2697 TALLOC_FREE(smb_fname->base_name);
2698 if (ISDOT(fname_dir)) {
2699 /* Ensure we use canonical names on open. */
2700 smb_fname->base_name =
2701 talloc_asprintf(smb_fname, "%s",
2702 dname);
2703 } else {
2704 smb_fname->base_name =
2705 talloc_asprintf(smb_fname, "%s/%s",
2706 fname_dir, dname);
2709 if (!smb_fname->base_name) {
2710 TALLOC_FREE(dir_hnd);
2711 status = NT_STATUS_NO_MEMORY;
2712 TALLOC_FREE(frame);
2713 TALLOC_FREE(talloced);
2714 goto out;
2717 status = check_name(conn, smb_fname->base_name);
2718 if (!NT_STATUS_IS_OK(status)) {
2719 TALLOC_FREE(dir_hnd);
2720 TALLOC_FREE(frame);
2721 TALLOC_FREE(talloced);
2722 goto out;
2725 status = do_unlink(conn, req, smb_fname, dirtype);
2726 if (!NT_STATUS_IS_OK(status)) {
2727 TALLOC_FREE(frame);
2728 TALLOC_FREE(talloced);
2729 continue;
2732 count++;
2733 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
2734 smb_fname->base_name));
2736 TALLOC_FREE(frame);
2737 TALLOC_FREE(talloced);
2739 TALLOC_FREE(dir_hnd);
2742 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
2743 status = map_nt_error_from_unix(errno);
2746 out:
2747 TALLOC_FREE(fname_dir);
2748 TALLOC_FREE(fname_mask);
2749 return status;
2752 /****************************************************************************
2753 Reply to a unlink
2754 ****************************************************************************/
2756 void reply_unlink(struct smb_request *req)
2758 connection_struct *conn = req->conn;
2759 char *name = NULL;
2760 struct smb_filename *smb_fname = NULL;
2761 uint32 dirtype;
2762 NTSTATUS status;
2763 bool path_contains_wcard = False;
2764 TALLOC_CTX *ctx = talloc_tos();
2766 START_PROFILE(SMBunlink);
2768 if (req->wct < 1) {
2769 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2770 goto out;
2773 dirtype = SVAL(req->vwv+0, 0);
2775 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
2776 STR_TERMINATE, &status,
2777 &path_contains_wcard);
2778 if (!NT_STATUS_IS_OK(status)) {
2779 reply_nterror(req, status);
2780 goto out;
2783 status = filename_convert(ctx, conn,
2784 req->flags2 & FLAGS2_DFS_PATHNAMES,
2785 name,
2786 UCF_COND_ALLOW_WCARD_LCOMP,
2787 &path_contains_wcard,
2788 &smb_fname);
2789 if (!NT_STATUS_IS_OK(status)) {
2790 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2791 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2792 ERRSRV, ERRbadpath);
2793 goto out;
2795 reply_nterror(req, status);
2796 goto out;
2799 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
2801 status = unlink_internals(conn, req, dirtype, smb_fname,
2802 path_contains_wcard);
2803 if (!NT_STATUS_IS_OK(status)) {
2804 if (open_was_deferred(req->mid)) {
2805 /* We have re-scheduled this call. */
2806 goto out;
2808 reply_nterror(req, status);
2809 goto out;
2812 reply_outbuf(req, 0, 0);
2813 out:
2814 TALLOC_FREE(smb_fname);
2815 END_PROFILE(SMBunlink);
2816 return;
2819 /****************************************************************************
2820 Fail for readbraw.
2821 ****************************************************************************/
2823 static void fail_readraw(void)
2825 const char *errstr = talloc_asprintf(talloc_tos(),
2826 "FAIL ! reply_readbraw: socket write fail (%s)",
2827 strerror(errno));
2828 if (!errstr) {
2829 errstr = "";
2831 exit_server_cleanly(errstr);
2834 /****************************************************************************
2835 Fake (read/write) sendfile. Returns -1 on read or write fail.
2836 ****************************************************************************/
2838 ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos, size_t nread)
2840 size_t bufsize;
2841 size_t tosend = nread;
2842 char *buf;
2844 if (nread == 0) {
2845 return 0;
2848 bufsize = MIN(nread, 65536);
2850 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
2851 return -1;
2854 while (tosend > 0) {
2855 ssize_t ret;
2856 size_t cur_read;
2858 if (tosend > bufsize) {
2859 cur_read = bufsize;
2860 } else {
2861 cur_read = tosend;
2863 ret = read_file(fsp,buf,startpos,cur_read);
2864 if (ret == -1) {
2865 SAFE_FREE(buf);
2866 return -1;
2869 /* If we had a short read, fill with zeros. */
2870 if (ret < cur_read) {
2871 memset(buf + ret, '\0', cur_read - ret);
2874 if (write_data(fsp->conn->sconn->sock, buf, cur_read)
2875 != cur_read) {
2876 char addr[INET6_ADDRSTRLEN];
2878 * Try and give an error message saying what
2879 * client failed.
2881 DEBUG(0, ("write_data failed for client %s. "
2882 "Error %s\n",
2883 get_peer_addr(fsp->conn->sconn->sock, addr,
2884 sizeof(addr)),
2885 strerror(errno)));
2886 SAFE_FREE(buf);
2887 return -1;
2889 tosend -= cur_read;
2890 startpos += cur_read;
2893 SAFE_FREE(buf);
2894 return (ssize_t)nread;
2897 /****************************************************************************
2898 Deal with the case of sendfile reading less bytes from the file than
2899 requested. Fill with zeros (all we can do).
2900 ****************************************************************************/
2902 void sendfile_short_send(files_struct *fsp,
2903 ssize_t nread,
2904 size_t headersize,
2905 size_t smb_maxcnt)
2907 #define SHORT_SEND_BUFSIZE 1024
2908 if (nread < headersize) {
2909 DEBUG(0,("sendfile_short_send: sendfile failed to send "
2910 "header for file %s (%s). Terminating\n",
2911 fsp_str_dbg(fsp), strerror(errno)));
2912 exit_server_cleanly("sendfile_short_send failed");
2915 nread -= headersize;
2917 if (nread < smb_maxcnt) {
2918 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
2919 if (!buf) {
2920 exit_server_cleanly("sendfile_short_send: "
2921 "malloc failed");
2924 DEBUG(0,("sendfile_short_send: filling truncated file %s "
2925 "with zeros !\n", fsp_str_dbg(fsp)));
2927 while (nread < smb_maxcnt) {
2929 * We asked for the real file size and told sendfile
2930 * to not go beyond the end of the file. But it can
2931 * happen that in between our fstat call and the
2932 * sendfile call the file was truncated. This is very
2933 * bad because we have already announced the larger
2934 * number of bytes to the client.
2936 * The best we can do now is to send 0-bytes, just as
2937 * a read from a hole in a sparse file would do.
2939 * This should happen rarely enough that I don't care
2940 * about efficiency here :-)
2942 size_t to_write;
2944 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
2945 if (write_data(fsp->conn->sconn->sock, buf, to_write)
2946 != to_write) {
2947 char addr[INET6_ADDRSTRLEN];
2949 * Try and give an error message saying what
2950 * client failed.
2952 DEBUG(0, ("write_data failed for client %s. "
2953 "Error %s\n",
2954 get_peer_addr(
2955 fsp->conn->sconn->sock, addr,
2956 sizeof(addr)),
2957 strerror(errno)));
2958 exit_server_cleanly("sendfile_short_send: "
2959 "write_data failed");
2961 nread += to_write;
2963 SAFE_FREE(buf);
2967 /****************************************************************************
2968 Return a readbraw error (4 bytes of zero).
2969 ****************************************************************************/
2971 static void reply_readbraw_error(struct smbd_server_connection *sconn)
2973 char header[4];
2975 SIVAL(header,0,0);
2977 smbd_lock_socket(sconn);
2978 if (write_data(sconn->sock,header,4) != 4) {
2979 char addr[INET6_ADDRSTRLEN];
2981 * Try and give an error message saying what
2982 * client failed.
2984 DEBUG(0, ("write_data failed for client %s. "
2985 "Error %s\n",
2986 get_peer_addr(sconn->sock, addr, sizeof(addr)),
2987 strerror(errno)));
2989 fail_readraw();
2991 smbd_unlock_socket(sconn);
2994 /****************************************************************************
2995 Use sendfile in readbraw.
2996 ****************************************************************************/
2998 static void send_file_readbraw(connection_struct *conn,
2999 struct smb_request *req,
3000 files_struct *fsp,
3001 SMB_OFF_T startpos,
3002 size_t nread,
3003 ssize_t mincount)
3005 struct smbd_server_connection *sconn = req->sconn;
3006 char *outbuf = NULL;
3007 ssize_t ret=0;
3010 * We can only use sendfile on a non-chained packet
3011 * but we can use on a non-oplocked file. tridge proved this
3012 * on a train in Germany :-). JRA.
3013 * reply_readbraw has already checked the length.
3016 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3017 (fsp->wcp == NULL) &&
3018 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3019 ssize_t sendfile_read = -1;
3020 char header[4];
3021 DATA_BLOB header_blob;
3023 _smb_setlen(header,nread);
3024 header_blob = data_blob_const(header, 4);
3026 sendfile_read = SMB_VFS_SENDFILE(sconn->sock, fsp,
3027 &header_blob, startpos,
3028 nread);
3029 if (sendfile_read == -1) {
3030 /* Returning ENOSYS means no data at all was sent.
3031 * Do this as a normal read. */
3032 if (errno == ENOSYS) {
3033 goto normal_readbraw;
3037 * Special hack for broken Linux with no working sendfile. If we
3038 * return EINTR we sent the header but not the rest of the data.
3039 * Fake this up by doing read/write calls.
3041 if (errno == EINTR) {
3042 /* Ensure we don't do this again. */
3043 set_use_sendfile(SNUM(conn), False);
3044 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3046 if (fake_sendfile(fsp, startpos, nread) == -1) {
3047 DEBUG(0,("send_file_readbraw: "
3048 "fake_sendfile failed for "
3049 "file %s (%s).\n",
3050 fsp_str_dbg(fsp),
3051 strerror(errno)));
3052 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3054 return;
3057 DEBUG(0,("send_file_readbraw: sendfile failed for "
3058 "file %s (%s). Terminating\n",
3059 fsp_str_dbg(fsp), strerror(errno)));
3060 exit_server_cleanly("send_file_readbraw sendfile failed");
3061 } else if (sendfile_read == 0) {
3063 * Some sendfile implementations return 0 to indicate
3064 * that there was a short read, but nothing was
3065 * actually written to the socket. In this case,
3066 * fallback to the normal read path so the header gets
3067 * the correct byte count.
3069 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3070 "bytes falling back to the normal read: "
3071 "%s\n", fsp_str_dbg(fsp)));
3072 goto normal_readbraw;
3075 /* Deal with possible short send. */
3076 if (sendfile_read != 4+nread) {
3077 sendfile_short_send(fsp, sendfile_read, 4, nread);
3079 return;
3082 normal_readbraw:
3084 outbuf = TALLOC_ARRAY(NULL, char, nread+4);
3085 if (!outbuf) {
3086 DEBUG(0,("send_file_readbraw: TALLOC_ARRAY failed for size %u.\n",
3087 (unsigned)(nread+4)));
3088 reply_readbraw_error(sconn);
3089 return;
3092 if (nread > 0) {
3093 ret = read_file(fsp,outbuf+4,startpos,nread);
3094 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3095 if (ret < mincount)
3096 ret = 0;
3097 #else
3098 if (ret < nread)
3099 ret = 0;
3100 #endif
3103 _smb_setlen(outbuf,ret);
3104 if (write_data(sconn->sock, outbuf, 4+ret) != 4+ret) {
3105 char addr[INET6_ADDRSTRLEN];
3107 * Try and give an error message saying what
3108 * client failed.
3110 DEBUG(0, ("write_data failed for client %s. "
3111 "Error %s\n",
3112 get_peer_addr(fsp->conn->sconn->sock, addr,
3113 sizeof(addr)),
3114 strerror(errno)));
3116 fail_readraw();
3119 TALLOC_FREE(outbuf);
3122 /****************************************************************************
3123 Reply to a readbraw (core+ protocol).
3124 ****************************************************************************/
3126 void reply_readbraw(struct smb_request *req)
3128 connection_struct *conn = req->conn;
3129 struct smbd_server_connection *sconn = req->sconn;
3130 ssize_t maxcount,mincount;
3131 size_t nread = 0;
3132 SMB_OFF_T startpos;
3133 files_struct *fsp;
3134 struct lock_struct lock;
3135 SMB_OFF_T size = 0;
3137 START_PROFILE(SMBreadbraw);
3139 if (srv_is_signing_active(sconn) ||
3140 is_encrypted_packet(req->inbuf)) {
3141 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3142 "raw reads/writes are disallowed.");
3145 if (req->wct < 8) {
3146 reply_readbraw_error(sconn);
3147 END_PROFILE(SMBreadbraw);
3148 return;
3151 if (sconn->smb1.echo_handler.trusted_fde) {
3152 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3153 "'async smb echo handler = yes'\n"));
3154 reply_readbraw_error(sconn);
3155 END_PROFILE(SMBreadbraw);
3156 return;
3160 * Special check if an oplock break has been issued
3161 * and the readraw request croses on the wire, we must
3162 * return a zero length response here.
3165 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3168 * We have to do a check_fsp by hand here, as
3169 * we must always return 4 zero bytes on error,
3170 * not a NTSTATUS.
3173 if (!fsp || !conn || conn != fsp->conn ||
3174 req->vuid != fsp->vuid ||
3175 fsp->is_directory || fsp->fh->fd == -1) {
3177 * fsp could be NULL here so use the value from the packet. JRA.
3179 DEBUG(3,("reply_readbraw: fnum %d not valid "
3180 "- cache prime?\n",
3181 (int)SVAL(req->vwv+0, 0)));
3182 reply_readbraw_error(sconn);
3183 END_PROFILE(SMBreadbraw);
3184 return;
3187 /* Do a "by hand" version of CHECK_READ. */
3188 if (!(fsp->can_read ||
3189 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3190 (fsp->access_mask & FILE_EXECUTE)))) {
3191 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3192 (int)SVAL(req->vwv+0, 0)));
3193 reply_readbraw_error(sconn);
3194 END_PROFILE(SMBreadbraw);
3195 return;
3198 flush_write_cache(fsp, READRAW_FLUSH);
3200 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3201 if(req->wct == 10) {
3203 * This is a large offset (64 bit) read.
3205 #ifdef LARGE_SMB_OFF_T
3207 startpos |= (((SMB_OFF_T)IVAL(req->vwv+8, 0)) << 32);
3209 #else /* !LARGE_SMB_OFF_T */
3212 * Ensure we haven't been sent a >32 bit offset.
3215 if(IVAL(req->vwv+8, 0) != 0) {
3216 DEBUG(0,("reply_readbraw: large offset "
3217 "(%x << 32) used and we don't support "
3218 "64 bit offsets.\n",
3219 (unsigned int)IVAL(req->vwv+8, 0) ));
3220 reply_readbraw_error(sconn);
3221 END_PROFILE(SMBreadbraw);
3222 return;
3225 #endif /* LARGE_SMB_OFF_T */
3227 if(startpos < 0) {
3228 DEBUG(0,("reply_readbraw: negative 64 bit "
3229 "readraw offset (%.0f) !\n",
3230 (double)startpos ));
3231 reply_readbraw_error(sconn);
3232 END_PROFILE(SMBreadbraw);
3233 return;
3237 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3238 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3240 /* ensure we don't overrun the packet size */
3241 maxcount = MIN(65535,maxcount);
3243 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3244 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3245 &lock);
3247 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3248 reply_readbraw_error(sconn);
3249 END_PROFILE(SMBreadbraw);
3250 return;
3253 if (fsp_stat(fsp) == 0) {
3254 size = fsp->fsp_name->st.st_ex_size;
3257 if (startpos >= size) {
3258 nread = 0;
3259 } else {
3260 nread = MIN(maxcount,(size - startpos));
3263 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3264 if (nread < mincount)
3265 nread = 0;
3266 #endif
3268 DEBUG( 3, ( "reply_readbraw: fnum=%d start=%.0f max=%lu "
3269 "min=%lu nread=%lu\n",
3270 fsp->fnum, (double)startpos,
3271 (unsigned long)maxcount,
3272 (unsigned long)mincount,
3273 (unsigned long)nread ) );
3275 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3277 DEBUG(5,("reply_readbraw finished\n"));
3279 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3281 END_PROFILE(SMBreadbraw);
3282 return;
3285 #undef DBGC_CLASS
3286 #define DBGC_CLASS DBGC_LOCKING
3288 /****************************************************************************
3289 Reply to a lockread (core+ protocol).
3290 ****************************************************************************/
3292 void reply_lockread(struct smb_request *req)
3294 connection_struct *conn = req->conn;
3295 ssize_t nread = -1;
3296 char *data;
3297 SMB_OFF_T startpos;
3298 size_t numtoread;
3299 NTSTATUS status;
3300 files_struct *fsp;
3301 struct byte_range_lock *br_lck = NULL;
3302 char *p = NULL;
3303 struct smbd_server_connection *sconn = req->sconn;
3305 START_PROFILE(SMBlockread);
3307 if (req->wct < 5) {
3308 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3309 END_PROFILE(SMBlockread);
3310 return;
3313 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3315 if (!check_fsp(conn, req, fsp)) {
3316 END_PROFILE(SMBlockread);
3317 return;
3320 if (!CHECK_READ(fsp,req)) {
3321 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3322 END_PROFILE(SMBlockread);
3323 return;
3326 numtoread = SVAL(req->vwv+1, 0);
3327 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3329 numtoread = MIN(BUFFER_SIZE - (smb_size + 3*2 + 3), numtoread);
3331 reply_outbuf(req, 5, numtoread + 3);
3333 data = smb_buf(req->outbuf) + 3;
3336 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3337 * protocol request that predates the read/write lock concept.
3338 * Thus instead of asking for a read lock here we need to ask
3339 * for a write lock. JRA.
3340 * Note that the requested lock size is unaffected by max_recv.
3343 br_lck = do_lock(req->sconn->msg_ctx,
3344 fsp,
3345 (uint64_t)req->smbpid,
3346 (uint64_t)numtoread,
3347 (uint64_t)startpos,
3348 WRITE_LOCK,
3349 WINDOWS_LOCK,
3350 False, /* Non-blocking lock. */
3351 &status,
3352 NULL,
3353 NULL);
3354 TALLOC_FREE(br_lck);
3356 if (NT_STATUS_V(status)) {
3357 reply_nterror(req, status);
3358 END_PROFILE(SMBlockread);
3359 return;
3363 * However the requested READ size IS affected by max_recv. Insanity.... JRA.
3366 if (numtoread > sconn->smb1.negprot.max_recv) {
3367 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \
3368 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3369 (unsigned int)numtoread,
3370 (unsigned int)sconn->smb1.negprot.max_recv));
3371 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3373 nread = read_file(fsp,data,startpos,numtoread);
3375 if (nread < 0) {
3376 reply_nterror(req, map_nt_error_from_unix(errno));
3377 END_PROFILE(SMBlockread);
3378 return;
3381 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3383 SSVAL(req->outbuf,smb_vwv0,nread);
3384 SSVAL(req->outbuf,smb_vwv5,nread+3);
3385 p = smb_buf(req->outbuf);
3386 SCVAL(p,0,0); /* pad byte. */
3387 SSVAL(p,1,nread);
3389 DEBUG(3,("lockread fnum=%d num=%d nread=%d\n",
3390 fsp->fnum, (int)numtoread, (int)nread));
3392 END_PROFILE(SMBlockread);
3393 return;
3396 #undef DBGC_CLASS
3397 #define DBGC_CLASS DBGC_ALL
3399 /****************************************************************************
3400 Reply to a read.
3401 ****************************************************************************/
3403 void reply_read(struct smb_request *req)
3405 connection_struct *conn = req->conn;
3406 size_t numtoread;
3407 ssize_t nread = 0;
3408 char *data;
3409 SMB_OFF_T startpos;
3410 int outsize = 0;
3411 files_struct *fsp;
3412 struct lock_struct lock;
3413 struct smbd_server_connection *sconn = req->sconn;
3415 START_PROFILE(SMBread);
3417 if (req->wct < 3) {
3418 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3419 END_PROFILE(SMBread);
3420 return;
3423 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3425 if (!check_fsp(conn, req, fsp)) {
3426 END_PROFILE(SMBread);
3427 return;
3430 if (!CHECK_READ(fsp,req)) {
3431 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3432 END_PROFILE(SMBread);
3433 return;
3436 numtoread = SVAL(req->vwv+1, 0);
3437 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3439 numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
3442 * The requested read size cannot be greater than max_recv. JRA.
3444 if (numtoread > sconn->smb1.negprot.max_recv) {
3445 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \
3446 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3447 (unsigned int)numtoread,
3448 (unsigned int)sconn->smb1.negprot.max_recv));
3449 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3452 reply_outbuf(req, 5, numtoread+3);
3454 data = smb_buf(req->outbuf) + 3;
3456 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3457 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3458 &lock);
3460 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3461 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3462 END_PROFILE(SMBread);
3463 return;
3466 if (numtoread > 0)
3467 nread = read_file(fsp,data,startpos,numtoread);
3469 if (nread < 0) {
3470 reply_nterror(req, map_nt_error_from_unix(errno));
3471 goto strict_unlock;
3474 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3476 SSVAL(req->outbuf,smb_vwv0,nread);
3477 SSVAL(req->outbuf,smb_vwv5,nread+3);
3478 SCVAL(smb_buf(req->outbuf),0,1);
3479 SSVAL(smb_buf(req->outbuf),1,nread);
3481 DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
3482 fsp->fnum, (int)numtoread, (int)nread ) );
3484 strict_unlock:
3485 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3487 END_PROFILE(SMBread);
3488 return;
3491 /****************************************************************************
3492 Setup readX header.
3493 ****************************************************************************/
3495 static int setup_readX_header(struct smb_request *req, char *outbuf,
3496 size_t smb_maxcnt)
3498 int outsize;
3499 char *data;
3501 outsize = srv_set_message(outbuf,12,smb_maxcnt,False);
3502 data = smb_buf(outbuf);
3504 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3506 SCVAL(outbuf,smb_vwv0,0xFF);
3507 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3508 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3509 SSVAL(outbuf,smb_vwv6,
3510 req_wct_ofs(req)
3511 + 1 /* the wct field */
3512 + 12 * sizeof(uint16_t) /* vwv */
3513 + 2); /* the buflen field */
3514 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3515 SSVAL(outbuf,smb_vwv11,smb_maxcnt);
3516 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3517 _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
3518 return outsize;
3521 /****************************************************************************
3522 Reply to a read and X - possibly using sendfile.
3523 ****************************************************************************/
3525 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3526 files_struct *fsp, SMB_OFF_T startpos,
3527 size_t smb_maxcnt)
3529 ssize_t nread = -1;
3530 struct lock_struct lock;
3531 int saved_errno = 0;
3533 if(fsp_stat(fsp) == -1) {
3534 reply_nterror(req, map_nt_error_from_unix(errno));
3535 return;
3538 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3539 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3540 &lock);
3542 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3543 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3544 return;
3547 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3548 (startpos > fsp->fsp_name->st.st_ex_size)
3549 || (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3551 * We already know that we would do a short read, so don't
3552 * try the sendfile() path.
3554 goto nosendfile_read;
3558 * We can only use sendfile on a non-chained packet
3559 * but we can use on a non-oplocked file. tridge proved this
3560 * on a train in Germany :-). JRA.
3563 if (!req_is_in_chain(req) &&
3564 !is_encrypted_packet(req->inbuf) && (fsp->base_fsp == NULL) &&
3565 (fsp->wcp == NULL) &&
3566 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3567 uint8 headerbuf[smb_size + 12 * 2];
3568 DATA_BLOB header;
3571 * Set up the packet header before send. We
3572 * assume here the sendfile will work (get the
3573 * correct amount of data).
3576 header = data_blob_const(headerbuf, sizeof(headerbuf));
3578 construct_reply_common_req(req, (char *)headerbuf);
3579 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3581 nread = SMB_VFS_SENDFILE(req->sconn->sock, fsp, &header,
3582 startpos, smb_maxcnt);
3583 if (nread == -1) {
3584 /* Returning ENOSYS means no data at all was sent.
3585 Do this as a normal read. */
3586 if (errno == ENOSYS) {
3587 goto normal_read;
3591 * Special hack for broken Linux with no working sendfile. If we
3592 * return EINTR we sent the header but not the rest of the data.
3593 * Fake this up by doing read/write calls.
3596 if (errno == EINTR) {
3597 /* Ensure we don't do this again. */
3598 set_use_sendfile(SNUM(conn), False);
3599 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3600 nread = fake_sendfile(fsp, startpos,
3601 smb_maxcnt);
3602 if (nread == -1) {
3603 DEBUG(0,("send_file_readX: "
3604 "fake_sendfile failed for "
3605 "file %s (%s).\n",
3606 fsp_str_dbg(fsp),
3607 strerror(errno)));
3608 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3610 DEBUG( 3, ( "send_file_readX: fake_sendfile fnum=%d max=%d nread=%d\n",
3611 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3612 /* No outbuf here means successful sendfile. */
3613 goto strict_unlock;
3616 DEBUG(0,("send_file_readX: sendfile failed for file "
3617 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3618 strerror(errno)));
3619 exit_server_cleanly("send_file_readX sendfile failed");
3620 } else if (nread == 0) {
3622 * Some sendfile implementations return 0 to indicate
3623 * that there was a short read, but nothing was
3624 * actually written to the socket. In this case,
3625 * fallback to the normal read path so the header gets
3626 * the correct byte count.
3628 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
3629 "falling back to the normal read: %s\n",
3630 fsp_str_dbg(fsp)));
3631 goto normal_read;
3634 DEBUG( 3, ( "send_file_readX: sendfile fnum=%d max=%d nread=%d\n",
3635 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3637 /* Deal with possible short send. */
3638 if (nread != smb_maxcnt + sizeof(headerbuf)) {
3639 sendfile_short_send(fsp, nread, sizeof(headerbuf), smb_maxcnt);
3641 /* No outbuf here means successful sendfile. */
3642 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
3643 SMB_PERFCOUNT_END(&req->pcd);
3644 goto strict_unlock;
3647 normal_read:
3649 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3650 uint8 headerbuf[smb_size + 2*12];
3652 construct_reply_common_req(req, (char *)headerbuf);
3653 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3655 /* Send out the header. */
3656 if (write_data(req->sconn->sock, (char *)headerbuf,
3657 sizeof(headerbuf)) != sizeof(headerbuf)) {
3659 char addr[INET6_ADDRSTRLEN];
3661 * Try and give an error message saying what
3662 * client failed.
3664 DEBUG(0, ("write_data failed for client %s. "
3665 "Error %s\n",
3666 get_peer_addr(req->sconn->sock, addr,
3667 sizeof(addr)),
3668 strerror(errno)));
3670 DEBUG(0,("send_file_readX: write_data failed for file "
3671 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3672 strerror(errno)));
3673 exit_server_cleanly("send_file_readX sendfile failed");
3675 nread = fake_sendfile(fsp, startpos, smb_maxcnt);
3676 if (nread == -1) {
3677 DEBUG(0,("send_file_readX: fake_sendfile failed for "
3678 "file %s (%s).\n", fsp_str_dbg(fsp),
3679 strerror(errno)));
3680 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3682 goto strict_unlock;
3685 nosendfile_read:
3687 reply_outbuf(req, 12, smb_maxcnt);
3689 nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt);
3690 saved_errno = errno;
3692 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3694 if (nread < 0) {
3695 reply_nterror(req, map_nt_error_from_unix(saved_errno));
3696 return;
3699 setup_readX_header(req, (char *)req->outbuf, nread);
3701 DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
3702 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3704 chain_reply(req);
3705 return;
3707 strict_unlock:
3708 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3709 TALLOC_FREE(req->outbuf);
3710 return;
3713 /****************************************************************************
3714 Reply to a read and X.
3715 ****************************************************************************/
3717 void reply_read_and_X(struct smb_request *req)
3719 connection_struct *conn = req->conn;
3720 files_struct *fsp;
3721 SMB_OFF_T startpos;
3722 size_t smb_maxcnt;
3723 bool big_readX = False;
3724 #if 0
3725 size_t smb_mincnt = SVAL(req->vwv+6, 0);
3726 #endif
3728 START_PROFILE(SMBreadX);
3730 if ((req->wct != 10) && (req->wct != 12)) {
3731 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3732 return;
3735 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
3736 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3737 smb_maxcnt = SVAL(req->vwv+5, 0);
3739 /* If it's an IPC, pass off the pipe handler. */
3740 if (IS_IPC(conn)) {
3741 reply_pipe_read_and_X(req);
3742 END_PROFILE(SMBreadX);
3743 return;
3746 if (!check_fsp(conn, req, fsp)) {
3747 END_PROFILE(SMBreadX);
3748 return;
3751 if (!CHECK_READ(fsp,req)) {
3752 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3753 END_PROFILE(SMBreadX);
3754 return;
3757 if (global_client_caps & CAP_LARGE_READX) {
3758 size_t upper_size = SVAL(req->vwv+7, 0);
3759 smb_maxcnt |= (upper_size<<16);
3760 if (upper_size > 1) {
3761 /* Can't do this on a chained packet. */
3762 if ((CVAL(req->vwv+0, 0) != 0xFF)) {
3763 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3764 END_PROFILE(SMBreadX);
3765 return;
3767 /* We currently don't do this on signed or sealed data. */
3768 if (srv_is_signing_active(req->sconn) ||
3769 is_encrypted_packet(req->inbuf)) {
3770 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3771 END_PROFILE(SMBreadX);
3772 return;
3774 /* Is there room in the reply for this data ? */
3775 if (smb_maxcnt > (0xFFFFFF - (smb_size -4 + 12*2))) {
3776 reply_nterror(req,
3777 NT_STATUS_INVALID_PARAMETER);
3778 END_PROFILE(SMBreadX);
3779 return;
3781 big_readX = True;
3785 if (req->wct == 12) {
3786 #ifdef LARGE_SMB_OFF_T
3788 * This is a large offset (64 bit) read.
3790 startpos |= (((SMB_OFF_T)IVAL(req->vwv+10, 0)) << 32);
3792 #else /* !LARGE_SMB_OFF_T */
3795 * Ensure we haven't been sent a >32 bit offset.
3798 if(IVAL(req->vwv+10, 0) != 0) {
3799 DEBUG(0,("reply_read_and_X - large offset (%x << 32) "
3800 "used and we don't support 64 bit offsets.\n",
3801 (unsigned int)IVAL(req->vwv+10, 0) ));
3802 END_PROFILE(SMBreadX);
3803 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3804 return;
3807 #endif /* LARGE_SMB_OFF_T */
3811 if (!big_readX) {
3812 NTSTATUS status = schedule_aio_read_and_X(conn,
3813 req,
3814 fsp,
3815 startpos,
3816 smb_maxcnt);
3817 if (NT_STATUS_IS_OK(status)) {
3818 /* Read scheduled - we're done. */
3819 goto out;
3821 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
3822 /* Real error - report to client. */
3823 END_PROFILE(SMBreadX);
3824 reply_nterror(req, status);
3825 return;
3827 /* NT_STATUS_RETRY - fall back to sync read. */
3830 smbd_lock_socket(req->sconn);
3831 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
3832 smbd_unlock_socket(req->sconn);
3834 out:
3835 END_PROFILE(SMBreadX);
3836 return;
3839 /****************************************************************************
3840 Error replies to writebraw must have smb_wct == 1. Fix this up.
3841 ****************************************************************************/
3843 void error_to_writebrawerr(struct smb_request *req)
3845 uint8 *old_outbuf = req->outbuf;
3847 reply_outbuf(req, 1, 0);
3849 memcpy(req->outbuf, old_outbuf, smb_size);
3850 TALLOC_FREE(old_outbuf);
3853 /****************************************************************************
3854 Read 4 bytes of a smb packet and return the smb length of the packet.
3855 Store the result in the buffer. This version of the function will
3856 never return a session keepalive (length of zero).
3857 Timeout is in milliseconds.
3858 ****************************************************************************/
3860 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
3861 size_t *len)
3863 uint8_t msgtype = SMBkeepalive;
3865 while (msgtype == SMBkeepalive) {
3866 NTSTATUS status;
3868 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
3869 len);
3870 if (!NT_STATUS_IS_OK(status)) {
3871 char addr[INET6_ADDRSTRLEN];
3872 /* Try and give an error message
3873 * saying what client failed. */
3874 DEBUG(0, ("read_fd_with_timeout failed for "
3875 "client %s read error = %s.\n",
3876 get_peer_addr(fd,addr,sizeof(addr)),
3877 nt_errstr(status)));
3878 return status;
3881 msgtype = CVAL(inbuf, 0);
3884 DEBUG(10,("read_smb_length: got smb length of %lu\n",
3885 (unsigned long)len));
3887 return NT_STATUS_OK;
3890 /****************************************************************************
3891 Reply to a writebraw (core+ or LANMAN1.0 protocol).
3892 ****************************************************************************/
3894 void reply_writebraw(struct smb_request *req)
3896 connection_struct *conn = req->conn;
3897 char *buf = NULL;
3898 ssize_t nwritten=0;
3899 ssize_t total_written=0;
3900 size_t numtowrite=0;
3901 size_t tcount;
3902 SMB_OFF_T startpos;
3903 char *data=NULL;
3904 bool write_through;
3905 files_struct *fsp;
3906 struct lock_struct lock;
3907 NTSTATUS status;
3909 START_PROFILE(SMBwritebraw);
3912 * If we ever reply with an error, it must have the SMB command
3913 * type of SMBwritec, not SMBwriteBraw, as this tells the client
3914 * we're finished.
3916 SCVAL(req->inbuf,smb_com,SMBwritec);
3918 if (srv_is_signing_active(req->sconn)) {
3919 END_PROFILE(SMBwritebraw);
3920 exit_server_cleanly("reply_writebraw: SMB signing is active - "
3921 "raw reads/writes are disallowed.");
3924 if (req->wct < 12) {
3925 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3926 error_to_writebrawerr(req);
3927 END_PROFILE(SMBwritebraw);
3928 return;
3931 if (req->sconn->smb1.echo_handler.trusted_fde) {
3932 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
3933 "'async smb echo handler = yes'\n"));
3934 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3935 error_to_writebrawerr(req);
3936 END_PROFILE(SMBwritebraw);
3937 return;
3940 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3941 if (!check_fsp(conn, req, fsp)) {
3942 error_to_writebrawerr(req);
3943 END_PROFILE(SMBwritebraw);
3944 return;
3947 if (!CHECK_WRITE(fsp)) {
3948 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3949 error_to_writebrawerr(req);
3950 END_PROFILE(SMBwritebraw);
3951 return;
3954 tcount = IVAL(req->vwv+1, 0);
3955 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3956 write_through = BITSETW(req->vwv+7,0);
3958 /* We have to deal with slightly different formats depending
3959 on whether we are using the core+ or lanman1.0 protocol */
3961 if(get_Protocol() <= PROTOCOL_COREPLUS) {
3962 numtowrite = SVAL(smb_buf(req->inbuf),-2);
3963 data = smb_buf(req->inbuf);
3964 } else {
3965 numtowrite = SVAL(req->vwv+10, 0);
3966 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
3969 /* Ensure we don't write bytes past the end of this packet. */
3970 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
3971 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3972 error_to_writebrawerr(req);
3973 END_PROFILE(SMBwritebraw);
3974 return;
3977 if (!fsp->print_file) {
3978 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3979 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
3980 &lock);
3982 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3983 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3984 error_to_writebrawerr(req);
3985 END_PROFILE(SMBwritebraw);
3986 return;
3990 if (numtowrite>0) {
3991 nwritten = write_file(req,fsp,data,startpos,numtowrite);
3994 DEBUG(3,("reply_writebraw: initial write fnum=%d start=%.0f num=%d "
3995 "wrote=%d sync=%d\n",
3996 fsp->fnum, (double)startpos, (int)numtowrite,
3997 (int)nwritten, (int)write_through));
3999 if (nwritten < (ssize_t)numtowrite) {
4000 reply_nterror(req, NT_STATUS_DISK_FULL);
4001 error_to_writebrawerr(req);
4002 goto strict_unlock;
4005 total_written = nwritten;
4007 /* Allocate a buffer of 64k + length. */
4008 buf = TALLOC_ARRAY(NULL, char, 65540);
4009 if (!buf) {
4010 reply_nterror(req, NT_STATUS_NO_MEMORY);
4011 error_to_writebrawerr(req);
4012 goto strict_unlock;
4015 /* Return a SMBwritebraw message to the redirector to tell
4016 * it to send more bytes */
4018 memcpy(buf, req->inbuf, smb_size);
4019 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4020 SCVAL(buf,smb_com,SMBwritebraw);
4021 SSVALS(buf,smb_vwv0,0xFFFF);
4022 show_msg(buf);
4023 if (!srv_send_smb(req->sconn,
4024 buf,
4025 false, 0, /* no signing */
4026 IS_CONN_ENCRYPTED(conn),
4027 &req->pcd)) {
4028 exit_server_cleanly("reply_writebraw: srv_send_smb "
4029 "failed.");
4032 /* Now read the raw data into the buffer and write it */
4033 status = read_smb_length(req->sconn->sock, buf, SMB_SECONDARY_WAIT,
4034 &numtowrite);
4035 if (!NT_STATUS_IS_OK(status)) {
4036 exit_server_cleanly("secondary writebraw failed");
4039 /* Set up outbuf to return the correct size */
4040 reply_outbuf(req, 1, 0);
4042 if (numtowrite != 0) {
4044 if (numtowrite > 0xFFFF) {
4045 DEBUG(0,("reply_writebraw: Oversize secondary write "
4046 "raw requested (%u). Terminating\n",
4047 (unsigned int)numtowrite ));
4048 exit_server_cleanly("secondary writebraw failed");
4051 if (tcount > nwritten+numtowrite) {
4052 DEBUG(3,("reply_writebraw: Client overestimated the "
4053 "write %d %d %d\n",
4054 (int)tcount,(int)nwritten,(int)numtowrite));
4057 status = read_data(req->sconn->sock, buf+4, numtowrite);
4059 if (!NT_STATUS_IS_OK(status)) {
4060 char addr[INET6_ADDRSTRLEN];
4061 /* Try and give an error message
4062 * saying what client failed. */
4063 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4064 "raw read failed (%s) for client %s. "
4065 "Terminating\n", nt_errstr(status),
4066 get_peer_addr(req->sconn->sock, addr,
4067 sizeof(addr))));
4068 exit_server_cleanly("secondary writebraw failed");
4071 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4072 if (nwritten == -1) {
4073 TALLOC_FREE(buf);
4074 reply_nterror(req, map_nt_error_from_unix(errno));
4075 error_to_writebrawerr(req);
4076 goto strict_unlock;
4079 if (nwritten < (ssize_t)numtowrite) {
4080 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4081 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4084 if (nwritten > 0) {
4085 total_written += nwritten;
4089 TALLOC_FREE(buf);
4090 SSVAL(req->outbuf,smb_vwv0,total_written);
4092 status = sync_file(conn, fsp, write_through);
4093 if (!NT_STATUS_IS_OK(status)) {
4094 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4095 fsp_str_dbg(fsp), nt_errstr(status)));
4096 reply_nterror(req, status);
4097 error_to_writebrawerr(req);
4098 goto strict_unlock;
4101 DEBUG(3,("reply_writebraw: secondart write fnum=%d start=%.0f num=%d "
4102 "wrote=%d\n",
4103 fsp->fnum, (double)startpos, (int)numtowrite,
4104 (int)total_written));
4106 if (!fsp->print_file) {
4107 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4110 /* We won't return a status if write through is not selected - this
4111 * follows what WfWg does */
4112 END_PROFILE(SMBwritebraw);
4114 if (!write_through && total_written==tcount) {
4116 #if RABBIT_PELLET_FIX
4118 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4119 * sending a SMBkeepalive. Thanks to DaveCB at Sun for this.
4120 * JRA.
4122 if (!send_keepalive(req->sconn->sock)) {
4123 exit_server_cleanly("reply_writebraw: send of "
4124 "keepalive failed");
4126 #endif
4127 TALLOC_FREE(req->outbuf);
4129 return;
4131 strict_unlock:
4132 if (!fsp->print_file) {
4133 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4136 END_PROFILE(SMBwritebraw);
4137 return;
4140 #undef DBGC_CLASS
4141 #define DBGC_CLASS DBGC_LOCKING
4143 /****************************************************************************
4144 Reply to a writeunlock (core+).
4145 ****************************************************************************/
4147 void reply_writeunlock(struct smb_request *req)
4149 connection_struct *conn = req->conn;
4150 ssize_t nwritten = -1;
4151 size_t numtowrite;
4152 SMB_OFF_T startpos;
4153 const char *data;
4154 NTSTATUS status = NT_STATUS_OK;
4155 files_struct *fsp;
4156 struct lock_struct lock;
4157 int saved_errno = 0;
4159 START_PROFILE(SMBwriteunlock);
4161 if (req->wct < 5) {
4162 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4163 END_PROFILE(SMBwriteunlock);
4164 return;
4167 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4169 if (!check_fsp(conn, req, fsp)) {
4170 END_PROFILE(SMBwriteunlock);
4171 return;
4174 if (!CHECK_WRITE(fsp)) {
4175 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4176 END_PROFILE(SMBwriteunlock);
4177 return;
4180 numtowrite = SVAL(req->vwv+1, 0);
4181 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4182 data = (const char *)req->buf + 3;
4184 if (!fsp->print_file && numtowrite > 0) {
4185 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4186 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4187 &lock);
4189 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4190 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4191 END_PROFILE(SMBwriteunlock);
4192 return;
4196 /* The special X/Open SMB protocol handling of
4197 zero length writes is *NOT* done for
4198 this call */
4199 if(numtowrite == 0) {
4200 nwritten = 0;
4201 } else {
4202 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4203 saved_errno = errno;
4206 status = sync_file(conn, fsp, False /* write through */);
4207 if (!NT_STATUS_IS_OK(status)) {
4208 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4209 fsp_str_dbg(fsp), nt_errstr(status)));
4210 reply_nterror(req, status);
4211 goto strict_unlock;
4214 if(nwritten < 0) {
4215 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4216 goto strict_unlock;
4219 if((nwritten < numtowrite) && (numtowrite != 0)) {
4220 reply_nterror(req, NT_STATUS_DISK_FULL);
4221 goto strict_unlock;
4224 if (numtowrite && !fsp->print_file) {
4225 status = do_unlock(req->sconn->msg_ctx,
4226 fsp,
4227 (uint64_t)req->smbpid,
4228 (uint64_t)numtowrite,
4229 (uint64_t)startpos,
4230 WINDOWS_LOCK);
4232 if (NT_STATUS_V(status)) {
4233 reply_nterror(req, status);
4234 goto strict_unlock;
4238 reply_outbuf(req, 1, 0);
4240 SSVAL(req->outbuf,smb_vwv0,nwritten);
4242 DEBUG(3,("writeunlock fnum=%d num=%d wrote=%d\n",
4243 fsp->fnum, (int)numtowrite, (int)nwritten));
4245 strict_unlock:
4246 if (numtowrite && !fsp->print_file) {
4247 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4250 END_PROFILE(SMBwriteunlock);
4251 return;
4254 #undef DBGC_CLASS
4255 #define DBGC_CLASS DBGC_ALL
4257 /****************************************************************************
4258 Reply to a write.
4259 ****************************************************************************/
4261 void reply_write(struct smb_request *req)
4263 connection_struct *conn = req->conn;
4264 size_t numtowrite;
4265 ssize_t nwritten = -1;
4266 SMB_OFF_T startpos;
4267 const char *data;
4268 files_struct *fsp;
4269 struct lock_struct lock;
4270 NTSTATUS status;
4271 int saved_errno = 0;
4273 START_PROFILE(SMBwrite);
4275 if (req->wct < 5) {
4276 END_PROFILE(SMBwrite);
4277 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4278 return;
4281 /* If it's an IPC, pass off the pipe handler. */
4282 if (IS_IPC(conn)) {
4283 reply_pipe_write(req);
4284 END_PROFILE(SMBwrite);
4285 return;
4288 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4290 if (!check_fsp(conn, req, fsp)) {
4291 END_PROFILE(SMBwrite);
4292 return;
4295 if (!CHECK_WRITE(fsp)) {
4296 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4297 END_PROFILE(SMBwrite);
4298 return;
4301 numtowrite = SVAL(req->vwv+1, 0);
4302 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4303 data = (const char *)req->buf + 3;
4305 if (!fsp->print_file) {
4306 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4307 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4308 &lock);
4310 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4311 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4312 END_PROFILE(SMBwrite);
4313 return;
4318 * X/Open SMB protocol says that if smb_vwv1 is
4319 * zero then the file size should be extended or
4320 * truncated to the size given in smb_vwv[2-3].
4323 if(numtowrite == 0) {
4325 * This is actually an allocate call, and set EOF. JRA.
4327 nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos);
4328 if (nwritten < 0) {
4329 reply_nterror(req, NT_STATUS_DISK_FULL);
4330 goto strict_unlock;
4332 nwritten = vfs_set_filelen(fsp, (SMB_OFF_T)startpos);
4333 if (nwritten < 0) {
4334 reply_nterror(req, NT_STATUS_DISK_FULL);
4335 goto strict_unlock;
4337 trigger_write_time_update_immediate(fsp);
4338 } else {
4339 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4342 status = sync_file(conn, fsp, False);
4343 if (!NT_STATUS_IS_OK(status)) {
4344 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4345 fsp_str_dbg(fsp), nt_errstr(status)));
4346 reply_nterror(req, status);
4347 goto strict_unlock;
4350 if(nwritten < 0) {
4351 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4352 goto strict_unlock;
4355 if((nwritten == 0) && (numtowrite != 0)) {
4356 reply_nterror(req, NT_STATUS_DISK_FULL);
4357 goto strict_unlock;
4360 reply_outbuf(req, 1, 0);
4362 SSVAL(req->outbuf,smb_vwv0,nwritten);
4364 if (nwritten < (ssize_t)numtowrite) {
4365 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4366 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4369 DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten));
4371 strict_unlock:
4372 if (!fsp->print_file) {
4373 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4376 END_PROFILE(SMBwrite);
4377 return;
4380 /****************************************************************************
4381 Ensure a buffer is a valid writeX for recvfile purposes.
4382 ****************************************************************************/
4384 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4385 (2*14) + /* word count (including bcc) */ \
4386 1 /* pad byte */)
4388 bool is_valid_writeX_buffer(struct smbd_server_connection *sconn,
4389 const uint8_t *inbuf)
4391 size_t numtowrite;
4392 connection_struct *conn = NULL;
4393 unsigned int doff = 0;
4394 size_t len = smb_len_large(inbuf);
4396 if (is_encrypted_packet(inbuf)) {
4397 /* Can't do this on encrypted
4398 * connections. */
4399 return false;
4402 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4403 return false;
4406 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4407 CVAL(inbuf,smb_wct) != 14) {
4408 DEBUG(10,("is_valid_writeX_buffer: chained or "
4409 "invalid word length.\n"));
4410 return false;
4413 conn = conn_find(sconn, SVAL(inbuf, smb_tid));
4414 if (conn == NULL) {
4415 DEBUG(10,("is_valid_writeX_buffer: bad tid\n"));
4416 return false;
4418 if (IS_IPC(conn)) {
4419 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4420 return false;
4422 if (IS_PRINT(conn)) {
4423 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4424 return false;
4426 doff = SVAL(inbuf,smb_vwv11);
4428 numtowrite = SVAL(inbuf,smb_vwv10);
4430 if (len > doff && len - doff > 0xFFFF) {
4431 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4434 if (numtowrite == 0) {
4435 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4436 return false;
4439 /* Ensure the sizes match up. */
4440 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4441 /* no pad byte...old smbclient :-( */
4442 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4443 (unsigned int)doff,
4444 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4445 return false;
4448 if (len - doff != numtowrite) {
4449 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4450 "len = %u, doff = %u, numtowrite = %u\n",
4451 (unsigned int)len,
4452 (unsigned int)doff,
4453 (unsigned int)numtowrite ));
4454 return false;
4457 DEBUG(10,("is_valid_writeX_buffer: true "
4458 "len = %u, doff = %u, numtowrite = %u\n",
4459 (unsigned int)len,
4460 (unsigned int)doff,
4461 (unsigned int)numtowrite ));
4463 return true;
4466 /****************************************************************************
4467 Reply to a write and X.
4468 ****************************************************************************/
4470 void reply_write_and_X(struct smb_request *req)
4472 connection_struct *conn = req->conn;
4473 files_struct *fsp;
4474 struct lock_struct lock;
4475 SMB_OFF_T startpos;
4476 size_t numtowrite;
4477 bool write_through;
4478 ssize_t nwritten;
4479 unsigned int smb_doff;
4480 unsigned int smblen;
4481 char *data;
4482 NTSTATUS status;
4483 int saved_errno = 0;
4485 START_PROFILE(SMBwriteX);
4487 if ((req->wct != 12) && (req->wct != 14)) {
4488 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4489 END_PROFILE(SMBwriteX);
4490 return;
4493 numtowrite = SVAL(req->vwv+10, 0);
4494 smb_doff = SVAL(req->vwv+11, 0);
4495 smblen = smb_len(req->inbuf);
4497 if (req->unread_bytes > 0xFFFF ||
4498 (smblen > smb_doff &&
4499 smblen - smb_doff > 0xFFFF)) {
4500 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
4503 if (req->unread_bytes) {
4504 /* Can't do a recvfile write on IPC$ */
4505 if (IS_IPC(conn)) {
4506 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4507 END_PROFILE(SMBwriteX);
4508 return;
4510 if (numtowrite != req->unread_bytes) {
4511 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4512 END_PROFILE(SMBwriteX);
4513 return;
4515 } else {
4516 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4517 smb_doff + numtowrite > smblen) {
4518 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4519 END_PROFILE(SMBwriteX);
4520 return;
4524 /* If it's an IPC, pass off the pipe handler. */
4525 if (IS_IPC(conn)) {
4526 if (req->unread_bytes) {
4527 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4528 END_PROFILE(SMBwriteX);
4529 return;
4531 reply_pipe_write_and_X(req);
4532 END_PROFILE(SMBwriteX);
4533 return;
4536 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4537 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4538 write_through = BITSETW(req->vwv+7,0);
4540 if (!check_fsp(conn, req, fsp)) {
4541 END_PROFILE(SMBwriteX);
4542 return;
4545 if (!CHECK_WRITE(fsp)) {
4546 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4547 END_PROFILE(SMBwriteX);
4548 return;
4551 data = smb_base(req->inbuf) + smb_doff;
4553 if(req->wct == 14) {
4554 #ifdef LARGE_SMB_OFF_T
4556 * This is a large offset (64 bit) write.
4558 startpos |= (((SMB_OFF_T)IVAL(req->vwv+12, 0)) << 32);
4560 #else /* !LARGE_SMB_OFF_T */
4563 * Ensure we haven't been sent a >32 bit offset.
4566 if(IVAL(req->vwv+12, 0) != 0) {
4567 DEBUG(0,("reply_write_and_X - large offset (%x << 32) "
4568 "used and we don't support 64 bit offsets.\n",
4569 (unsigned int)IVAL(req->vwv+12, 0) ));
4570 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4571 END_PROFILE(SMBwriteX);
4572 return;
4575 #endif /* LARGE_SMB_OFF_T */
4578 /* X/Open SMB protocol says that, unlike SMBwrite
4579 if the length is zero then NO truncation is
4580 done, just a write of zero. To truncate a file,
4581 use SMBwrite. */
4583 if(numtowrite == 0) {
4584 nwritten = 0;
4585 } else {
4586 if (req->unread_bytes == 0) {
4587 status = schedule_aio_write_and_X(conn,
4588 req,
4589 fsp,
4590 data,
4591 startpos,
4592 numtowrite);
4594 if (NT_STATUS_IS_OK(status)) {
4595 /* write scheduled - we're done. */
4596 goto out;
4598 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4599 /* Real error - report to client. */
4600 reply_nterror(req, status);
4601 goto out;
4603 /* NT_STATUS_RETRY - fall through to sync write. */
4606 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4607 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4608 &lock);
4610 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4611 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4612 goto out;
4615 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4616 saved_errno = errno;
4618 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4621 if(nwritten < 0) {
4622 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4623 goto out;
4626 if((nwritten == 0) && (numtowrite != 0)) {
4627 reply_nterror(req, NT_STATUS_DISK_FULL);
4628 goto out;
4631 reply_outbuf(req, 6, 0);
4632 SSVAL(req->outbuf,smb_vwv2,nwritten);
4633 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4635 DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
4636 fsp->fnum, (int)numtowrite, (int)nwritten));
4638 status = sync_file(conn, fsp, write_through);
4639 if (!NT_STATUS_IS_OK(status)) {
4640 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4641 fsp_str_dbg(fsp), nt_errstr(status)));
4642 reply_nterror(req, status);
4643 goto out;
4646 END_PROFILE(SMBwriteX);
4647 chain_reply(req);
4648 return;
4650 out:
4651 END_PROFILE(SMBwriteX);
4652 return;
4655 /****************************************************************************
4656 Reply to a lseek.
4657 ****************************************************************************/
4659 void reply_lseek(struct smb_request *req)
4661 connection_struct *conn = req->conn;
4662 SMB_OFF_T startpos;
4663 SMB_OFF_T res= -1;
4664 int mode,umode;
4665 files_struct *fsp;
4667 START_PROFILE(SMBlseek);
4669 if (req->wct < 4) {
4670 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4671 END_PROFILE(SMBlseek);
4672 return;
4675 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4677 if (!check_fsp(conn, req, fsp)) {
4678 return;
4681 flush_write_cache(fsp, SEEK_FLUSH);
4683 mode = SVAL(req->vwv+1, 0) & 3;
4684 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4685 startpos = (SMB_OFF_T)IVALS(req->vwv+2, 0);
4687 switch (mode) {
4688 case 0:
4689 umode = SEEK_SET;
4690 res = startpos;
4691 break;
4692 case 1:
4693 umode = SEEK_CUR;
4694 res = fsp->fh->pos + startpos;
4695 break;
4696 case 2:
4697 umode = SEEK_END;
4698 break;
4699 default:
4700 umode = SEEK_SET;
4701 res = startpos;
4702 break;
4705 if (umode == SEEK_END) {
4706 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
4707 if(errno == EINVAL) {
4708 SMB_OFF_T current_pos = startpos;
4710 if(fsp_stat(fsp) == -1) {
4711 reply_nterror(req,
4712 map_nt_error_from_unix(errno));
4713 END_PROFILE(SMBlseek);
4714 return;
4717 current_pos += fsp->fsp_name->st.st_ex_size;
4718 if(current_pos < 0)
4719 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
4723 if(res == -1) {
4724 reply_nterror(req, map_nt_error_from_unix(errno));
4725 END_PROFILE(SMBlseek);
4726 return;
4730 fsp->fh->pos = res;
4732 reply_outbuf(req, 2, 0);
4733 SIVAL(req->outbuf,smb_vwv0,res);
4735 DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
4736 fsp->fnum, (double)startpos, (double)res, mode));
4738 END_PROFILE(SMBlseek);
4739 return;
4742 /****************************************************************************
4743 Reply to a flush.
4744 ****************************************************************************/
4746 void reply_flush(struct smb_request *req)
4748 connection_struct *conn = req->conn;
4749 uint16 fnum;
4750 files_struct *fsp;
4752 START_PROFILE(SMBflush);
4754 if (req->wct < 1) {
4755 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4756 return;
4759 fnum = SVAL(req->vwv+0, 0);
4760 fsp = file_fsp(req, fnum);
4762 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
4763 return;
4766 if (!fsp) {
4767 file_sync_all(conn);
4768 } else {
4769 NTSTATUS status = sync_file(conn, fsp, True);
4770 if (!NT_STATUS_IS_OK(status)) {
4771 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
4772 fsp_str_dbg(fsp), nt_errstr(status)));
4773 reply_nterror(req, status);
4774 END_PROFILE(SMBflush);
4775 return;
4779 reply_outbuf(req, 0, 0);
4781 DEBUG(3,("flush\n"));
4782 END_PROFILE(SMBflush);
4783 return;
4786 /****************************************************************************
4787 Reply to a exit.
4788 conn POINTER CAN BE NULL HERE !
4789 ****************************************************************************/
4791 void reply_exit(struct smb_request *req)
4793 START_PROFILE(SMBexit);
4795 file_close_pid(req->sconn, req->smbpid, req->vuid);
4797 reply_outbuf(req, 0, 0);
4799 DEBUG(3,("exit\n"));
4801 END_PROFILE(SMBexit);
4802 return;
4805 /****************************************************************************
4806 Reply to a close - has to deal with closing a directory opened by NT SMB's.
4807 ****************************************************************************/
4809 void reply_close(struct smb_request *req)
4811 connection_struct *conn = req->conn;
4812 NTSTATUS status = NT_STATUS_OK;
4813 files_struct *fsp = NULL;
4814 START_PROFILE(SMBclose);
4816 if (req->wct < 3) {
4817 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4818 END_PROFILE(SMBclose);
4819 return;
4822 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4825 * We can only use check_fsp if we know it's not a directory.
4828 if (!check_fsp_open(conn, req, fsp)) {
4829 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
4830 END_PROFILE(SMBclose);
4831 return;
4834 if(fsp->is_directory) {
4836 * Special case - close NT SMB directory handle.
4838 DEBUG(3,("close directory fnum=%d\n", fsp->fnum));
4839 status = close_file(req, fsp, NORMAL_CLOSE);
4840 } else {
4841 time_t t;
4843 * Close ordinary file.
4846 DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
4847 fsp->fh->fd, fsp->fnum,
4848 conn->num_files_open));
4851 * Take care of any time sent in the close.
4854 t = srv_make_unix_date3(req->vwv+1);
4855 set_close_write_time(fsp, convert_time_t_to_timespec(t));
4858 * close_file() returns the unix errno if an error
4859 * was detected on close - normally this is due to
4860 * a disk full error. If not then it was probably an I/O error.
4863 status = close_file(req, fsp, NORMAL_CLOSE);
4866 if (!NT_STATUS_IS_OK(status)) {
4867 reply_nterror(req, status);
4868 END_PROFILE(SMBclose);
4869 return;
4872 reply_outbuf(req, 0, 0);
4873 END_PROFILE(SMBclose);
4874 return;
4877 /****************************************************************************
4878 Reply to a writeclose (Core+ protocol).
4879 ****************************************************************************/
4881 void reply_writeclose(struct smb_request *req)
4883 connection_struct *conn = req->conn;
4884 size_t numtowrite;
4885 ssize_t nwritten = -1;
4886 NTSTATUS close_status = NT_STATUS_OK;
4887 SMB_OFF_T startpos;
4888 const char *data;
4889 struct timespec mtime;
4890 files_struct *fsp;
4891 struct lock_struct lock;
4893 START_PROFILE(SMBwriteclose);
4895 if (req->wct < 6) {
4896 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4897 END_PROFILE(SMBwriteclose);
4898 return;
4901 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4903 if (!check_fsp(conn, req, fsp)) {
4904 END_PROFILE(SMBwriteclose);
4905 return;
4907 if (!CHECK_WRITE(fsp)) {
4908 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4909 END_PROFILE(SMBwriteclose);
4910 return;
4913 numtowrite = SVAL(req->vwv+1, 0);
4914 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4915 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
4916 data = (const char *)req->buf + 1;
4918 if (!fsp->print_file) {
4919 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4920 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4921 &lock);
4923 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4924 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4925 END_PROFILE(SMBwriteclose);
4926 return;
4930 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4932 set_close_write_time(fsp, mtime);
4935 * More insanity. W2K only closes the file if writelen > 0.
4936 * JRA.
4939 if (numtowrite) {
4940 DEBUG(3,("reply_writeclose: zero length write doesn't close "
4941 "file %s\n", fsp_str_dbg(fsp)));
4942 close_status = close_file(req, fsp, NORMAL_CLOSE);
4945 DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
4946 fsp->fnum, (int)numtowrite, (int)nwritten,
4947 conn->num_files_open));
4949 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
4950 reply_nterror(req, NT_STATUS_DISK_FULL);
4951 goto strict_unlock;
4954 if(!NT_STATUS_IS_OK(close_status)) {
4955 reply_nterror(req, close_status);
4956 goto strict_unlock;
4959 reply_outbuf(req, 1, 0);
4961 SSVAL(req->outbuf,smb_vwv0,nwritten);
4963 strict_unlock:
4964 if (numtowrite && !fsp->print_file) {
4965 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4968 END_PROFILE(SMBwriteclose);
4969 return;
4972 #undef DBGC_CLASS
4973 #define DBGC_CLASS DBGC_LOCKING
4975 /****************************************************************************
4976 Reply to a lock.
4977 ****************************************************************************/
4979 void reply_lock(struct smb_request *req)
4981 connection_struct *conn = req->conn;
4982 uint64_t count,offset;
4983 NTSTATUS status;
4984 files_struct *fsp;
4985 struct byte_range_lock *br_lck = NULL;
4987 START_PROFILE(SMBlock);
4989 if (req->wct < 5) {
4990 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4991 END_PROFILE(SMBlock);
4992 return;
4995 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4997 if (!check_fsp(conn, req, fsp)) {
4998 END_PROFILE(SMBlock);
4999 return;
5002 count = (uint64_t)IVAL(req->vwv+1, 0);
5003 offset = (uint64_t)IVAL(req->vwv+3, 0);
5005 DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
5006 fsp->fh->fd, fsp->fnum, (double)offset, (double)count));
5008 br_lck = do_lock(req->sconn->msg_ctx,
5009 fsp,
5010 (uint64_t)req->smbpid,
5011 count,
5012 offset,
5013 WRITE_LOCK,
5014 WINDOWS_LOCK,
5015 False, /* Non-blocking lock. */
5016 &status,
5017 NULL,
5018 NULL);
5020 TALLOC_FREE(br_lck);
5022 if (NT_STATUS_V(status)) {
5023 reply_nterror(req, status);
5024 END_PROFILE(SMBlock);
5025 return;
5028 reply_outbuf(req, 0, 0);
5030 END_PROFILE(SMBlock);
5031 return;
5034 /****************************************************************************
5035 Reply to a unlock.
5036 ****************************************************************************/
5038 void reply_unlock(struct smb_request *req)
5040 connection_struct *conn = req->conn;
5041 uint64_t count,offset;
5042 NTSTATUS status;
5043 files_struct *fsp;
5045 START_PROFILE(SMBunlock);
5047 if (req->wct < 5) {
5048 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5049 END_PROFILE(SMBunlock);
5050 return;
5053 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5055 if (!check_fsp(conn, req, fsp)) {
5056 END_PROFILE(SMBunlock);
5057 return;
5060 count = (uint64_t)IVAL(req->vwv+1, 0);
5061 offset = (uint64_t)IVAL(req->vwv+3, 0);
5063 status = do_unlock(req->sconn->msg_ctx,
5064 fsp,
5065 (uint64_t)req->smbpid,
5066 count,
5067 offset,
5068 WINDOWS_LOCK);
5070 if (NT_STATUS_V(status)) {
5071 reply_nterror(req, status);
5072 END_PROFILE(SMBunlock);
5073 return;
5076 DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
5077 fsp->fh->fd, fsp->fnum, (double)offset, (double)count ) );
5079 reply_outbuf(req, 0, 0);
5081 END_PROFILE(SMBunlock);
5082 return;
5085 #undef DBGC_CLASS
5086 #define DBGC_CLASS DBGC_ALL
5088 /****************************************************************************
5089 Reply to a tdis.
5090 conn POINTER CAN BE NULL HERE !
5091 ****************************************************************************/
5093 void reply_tdis(struct smb_request *req)
5095 connection_struct *conn = req->conn;
5096 START_PROFILE(SMBtdis);
5098 if (!conn) {
5099 DEBUG(4,("Invalid connection in tdis\n"));
5100 reply_nterror(req, NT_STATUS_NETWORK_NAME_DELETED);
5101 END_PROFILE(SMBtdis);
5102 return;
5105 conn->used = False;
5107 close_cnum(conn,req->vuid);
5108 req->conn = NULL;
5110 reply_outbuf(req, 0, 0);
5111 END_PROFILE(SMBtdis);
5112 return;
5115 /****************************************************************************
5116 Reply to a echo.
5117 conn POINTER CAN BE NULL HERE !
5118 ****************************************************************************/
5120 void reply_echo(struct smb_request *req)
5122 connection_struct *conn = req->conn;
5123 struct smb_perfcount_data local_pcd;
5124 struct smb_perfcount_data *cur_pcd;
5125 int smb_reverb;
5126 int seq_num;
5128 START_PROFILE(SMBecho);
5130 smb_init_perfcount_data(&local_pcd);
5132 if (req->wct < 1) {
5133 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5134 END_PROFILE(SMBecho);
5135 return;
5138 smb_reverb = SVAL(req->vwv+0, 0);
5140 reply_outbuf(req, 1, req->buflen);
5142 /* copy any incoming data back out */
5143 if (req->buflen > 0) {
5144 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5147 if (smb_reverb > 100) {
5148 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5149 smb_reverb = 100;
5152 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5154 /* this makes sure we catch the request pcd */
5155 if (seq_num == smb_reverb) {
5156 cur_pcd = &req->pcd;
5157 } else {
5158 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5159 cur_pcd = &local_pcd;
5162 SSVAL(req->outbuf,smb_vwv0,seq_num);
5164 show_msg((char *)req->outbuf);
5165 if (!srv_send_smb(req->sconn,
5166 (char *)req->outbuf,
5167 true, req->seqnum+1,
5168 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5169 cur_pcd))
5170 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5173 DEBUG(3,("echo %d times\n", smb_reverb));
5175 TALLOC_FREE(req->outbuf);
5177 END_PROFILE(SMBecho);
5178 return;
5181 /****************************************************************************
5182 Reply to a printopen.
5183 ****************************************************************************/
5185 void reply_printopen(struct smb_request *req)
5187 connection_struct *conn = req->conn;
5188 files_struct *fsp;
5189 NTSTATUS status;
5191 START_PROFILE(SMBsplopen);
5193 if (req->wct < 2) {
5194 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5195 END_PROFILE(SMBsplopen);
5196 return;
5199 if (!CAN_PRINT(conn)) {
5200 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5201 END_PROFILE(SMBsplopen);
5202 return;
5205 status = file_new(req, conn, &fsp);
5206 if(!NT_STATUS_IS_OK(status)) {
5207 reply_nterror(req, status);
5208 END_PROFILE(SMBsplopen);
5209 return;
5212 /* Open for exclusive use, write only. */
5213 status = print_spool_open(fsp, NULL, req->vuid);
5215 if (!NT_STATUS_IS_OK(status)) {
5216 file_free(req, fsp);
5217 reply_nterror(req, status);
5218 END_PROFILE(SMBsplopen);
5219 return;
5222 reply_outbuf(req, 1, 0);
5223 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5225 DEBUG(3,("openprint fd=%d fnum=%d\n",
5226 fsp->fh->fd, fsp->fnum));
5228 END_PROFILE(SMBsplopen);
5229 return;
5232 /****************************************************************************
5233 Reply to a printclose.
5234 ****************************************************************************/
5236 void reply_printclose(struct smb_request *req)
5238 connection_struct *conn = req->conn;
5239 files_struct *fsp;
5240 NTSTATUS status;
5242 START_PROFILE(SMBsplclose);
5244 if (req->wct < 1) {
5245 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5246 END_PROFILE(SMBsplclose);
5247 return;
5250 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5252 if (!check_fsp(conn, req, fsp)) {
5253 END_PROFILE(SMBsplclose);
5254 return;
5257 if (!CAN_PRINT(conn)) {
5258 reply_force_doserror(req, ERRSRV, ERRerror);
5259 END_PROFILE(SMBsplclose);
5260 return;
5263 DEBUG(3,("printclose fd=%d fnum=%d\n",
5264 fsp->fh->fd,fsp->fnum));
5266 status = close_file(req, fsp, NORMAL_CLOSE);
5268 if(!NT_STATUS_IS_OK(status)) {
5269 reply_nterror(req, status);
5270 END_PROFILE(SMBsplclose);
5271 return;
5274 reply_outbuf(req, 0, 0);
5276 END_PROFILE(SMBsplclose);
5277 return;
5280 /****************************************************************************
5281 Reply to a printqueue.
5282 ****************************************************************************/
5284 void reply_printqueue(struct smb_request *req)
5286 connection_struct *conn = req->conn;
5287 int max_count;
5288 int start_index;
5290 START_PROFILE(SMBsplretq);
5292 if (req->wct < 2) {
5293 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5294 END_PROFILE(SMBsplretq);
5295 return;
5298 max_count = SVAL(req->vwv+0, 0);
5299 start_index = SVAL(req->vwv+1, 0);
5301 /* we used to allow the client to get the cnum wrong, but that
5302 is really quite gross and only worked when there was only
5303 one printer - I think we should now only accept it if they
5304 get it right (tridge) */
5305 if (!CAN_PRINT(conn)) {
5306 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5307 END_PROFILE(SMBsplretq);
5308 return;
5311 reply_outbuf(req, 2, 3);
5312 SSVAL(req->outbuf,smb_vwv0,0);
5313 SSVAL(req->outbuf,smb_vwv1,0);
5314 SCVAL(smb_buf(req->outbuf),0,1);
5315 SSVAL(smb_buf(req->outbuf),1,0);
5317 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5318 start_index, max_count));
5321 TALLOC_CTX *mem_ctx = talloc_tos();
5322 NTSTATUS status;
5323 WERROR werr;
5324 const char *sharename = lp_servicename(SNUM(conn));
5325 struct rpc_pipe_client *cli = NULL;
5326 struct dcerpc_binding_handle *b = NULL;
5327 struct policy_handle handle;
5328 struct spoolss_DevmodeContainer devmode_ctr;
5329 union spoolss_JobInfo *info;
5330 uint32_t count;
5331 uint32_t num_to_get;
5332 uint32_t first;
5333 uint32_t i;
5335 ZERO_STRUCT(handle);
5337 status = rpc_pipe_open_interface(conn,
5338 &ndr_table_spoolss.syntax_id,
5339 conn->session_info,
5340 &conn->sconn->client_id,
5341 conn->sconn->msg_ctx,
5342 &cli);
5343 if (!NT_STATUS_IS_OK(status)) {
5344 DEBUG(0, ("reply_printqueue: "
5345 "could not connect to spoolss: %s\n",
5346 nt_errstr(status)));
5347 reply_nterror(req, status);
5348 goto out;
5350 b = cli->binding_handle;
5352 ZERO_STRUCT(devmode_ctr);
5354 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5355 sharename,
5356 NULL, devmode_ctr,
5357 SEC_FLAG_MAXIMUM_ALLOWED,
5358 &handle,
5359 &werr);
5360 if (!NT_STATUS_IS_OK(status)) {
5361 reply_nterror(req, status);
5362 goto out;
5364 if (!W_ERROR_IS_OK(werr)) {
5365 reply_nterror(req, werror_to_ntstatus(werr));
5366 goto out;
5369 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5370 &handle,
5371 0, /* firstjob */
5372 0xff, /* numjobs */
5373 2, /* level */
5374 0, /* offered */
5375 &count,
5376 &info);
5377 if (!W_ERROR_IS_OK(werr)) {
5378 reply_nterror(req, werror_to_ntstatus(werr));
5379 goto out;
5382 if (max_count > 0) {
5383 first = start_index;
5384 } else {
5385 first = start_index + max_count + 1;
5388 if (first >= count) {
5389 num_to_get = first;
5390 } else {
5391 num_to_get = first + MIN(ABS(max_count), count - first);
5394 for (i = first; i < num_to_get; i++) {
5395 char blob[28];
5396 char *p = blob;
5397 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
5398 int qstatus;
5399 uint16_t qrapjobid = pjobid_to_rap(sharename,
5400 info[i].info2.job_id);
5402 if (info[i].info2.status == JOB_STATUS_PRINTING) {
5403 qstatus = 2;
5404 } else {
5405 qstatus = 3;
5408 srv_put_dos_date2(p, 0, qtime);
5409 SCVAL(p, 4, qstatus);
5410 SSVAL(p, 5, qrapjobid);
5411 SIVAL(p, 7, info[i].info2.size);
5412 SCVAL(p, 11, 0);
5413 srvstr_push(blob, req->flags2, p+12,
5414 info[i].info2.notify_name, 16, STR_ASCII);
5416 if (message_push_blob(
5417 &req->outbuf,
5418 data_blob_const(
5419 blob, sizeof(blob))) == -1) {
5420 reply_nterror(req, NT_STATUS_NO_MEMORY);
5421 goto out;
5425 if (count > 0) {
5426 SSVAL(req->outbuf,smb_vwv0,count);
5427 SSVAL(req->outbuf,smb_vwv1,
5428 (max_count>0?first+count:first-1));
5429 SCVAL(smb_buf(req->outbuf),0,1);
5430 SSVAL(smb_buf(req->outbuf),1,28*count);
5434 DEBUG(3, ("%u entries returned in queue\n",
5435 (unsigned)count));
5437 out:
5438 if (b && is_valid_policy_hnd(&handle)) {
5439 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5444 END_PROFILE(SMBsplretq);
5445 return;
5448 /****************************************************************************
5449 Reply to a printwrite.
5450 ****************************************************************************/
5452 void reply_printwrite(struct smb_request *req)
5454 connection_struct *conn = req->conn;
5455 int numtowrite;
5456 const char *data;
5457 files_struct *fsp;
5459 START_PROFILE(SMBsplwr);
5461 if (req->wct < 1) {
5462 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5463 END_PROFILE(SMBsplwr);
5464 return;
5467 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5469 if (!check_fsp(conn, req, fsp)) {
5470 END_PROFILE(SMBsplwr);
5471 return;
5474 if (!fsp->print_file) {
5475 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5476 END_PROFILE(SMBsplwr);
5477 return;
5480 if (!CHECK_WRITE(fsp)) {
5481 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5482 END_PROFILE(SMBsplwr);
5483 return;
5486 numtowrite = SVAL(req->buf, 1);
5488 if (req->buflen < numtowrite + 3) {
5489 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5490 END_PROFILE(SMBsplwr);
5491 return;
5494 data = (const char *)req->buf + 3;
5496 if (write_file(req,fsp,data,(SMB_OFF_T)-1,numtowrite) != numtowrite) {
5497 reply_nterror(req, map_nt_error_from_unix(errno));
5498 END_PROFILE(SMBsplwr);
5499 return;
5502 DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
5504 END_PROFILE(SMBsplwr);
5505 return;
5508 /****************************************************************************
5509 Reply to a mkdir.
5510 ****************************************************************************/
5512 void reply_mkdir(struct smb_request *req)
5514 connection_struct *conn = req->conn;
5515 struct smb_filename *smb_dname = NULL;
5516 char *directory = NULL;
5517 NTSTATUS status;
5518 TALLOC_CTX *ctx = talloc_tos();
5520 START_PROFILE(SMBmkdir);
5522 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5523 STR_TERMINATE, &status);
5524 if (!NT_STATUS_IS_OK(status)) {
5525 reply_nterror(req, status);
5526 goto out;
5529 status = filename_convert(ctx, conn,
5530 req->flags2 & FLAGS2_DFS_PATHNAMES,
5531 directory,
5533 NULL,
5534 &smb_dname);
5535 if (!NT_STATUS_IS_OK(status)) {
5536 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5537 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5538 ERRSRV, ERRbadpath);
5539 goto out;
5541 reply_nterror(req, status);
5542 goto out;
5545 status = create_directory(conn, req, smb_dname);
5547 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
5549 if (!NT_STATUS_IS_OK(status)) {
5551 if (!use_nt_status()
5552 && NT_STATUS_EQUAL(status,
5553 NT_STATUS_OBJECT_NAME_COLLISION)) {
5555 * Yes, in the DOS error code case we get a
5556 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
5557 * samba4 torture test.
5559 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
5562 reply_nterror(req, status);
5563 goto out;
5566 reply_outbuf(req, 0, 0);
5568 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
5569 out:
5570 TALLOC_FREE(smb_dname);
5571 END_PROFILE(SMBmkdir);
5572 return;
5575 /****************************************************************************
5576 Reply to a rmdir.
5577 ****************************************************************************/
5579 void reply_rmdir(struct smb_request *req)
5581 connection_struct *conn = req->conn;
5582 struct smb_filename *smb_dname = NULL;
5583 char *directory = NULL;
5584 NTSTATUS status;
5585 TALLOC_CTX *ctx = talloc_tos();
5586 files_struct *fsp = NULL;
5587 int info = 0;
5588 struct smbd_server_connection *sconn = req->sconn;
5590 START_PROFILE(SMBrmdir);
5592 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5593 STR_TERMINATE, &status);
5594 if (!NT_STATUS_IS_OK(status)) {
5595 reply_nterror(req, status);
5596 goto out;
5599 status = filename_convert(ctx, conn,
5600 req->flags2 & FLAGS2_DFS_PATHNAMES,
5601 directory,
5603 NULL,
5604 &smb_dname);
5605 if (!NT_STATUS_IS_OK(status)) {
5606 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5607 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5608 ERRSRV, ERRbadpath);
5609 goto out;
5611 reply_nterror(req, status);
5612 goto out;
5615 if (is_ntfs_stream_smb_fname(smb_dname)) {
5616 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
5617 goto out;
5620 status = SMB_VFS_CREATE_FILE(
5621 conn, /* conn */
5622 req, /* req */
5623 0, /* root_dir_fid */
5624 smb_dname, /* fname */
5625 DELETE_ACCESS, /* access_mask */
5626 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5627 FILE_SHARE_DELETE),
5628 FILE_OPEN, /* create_disposition*/
5629 FILE_DIRECTORY_FILE, /* create_options */
5630 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
5631 0, /* oplock_request */
5632 0, /* allocation_size */
5633 0, /* private_flags */
5634 NULL, /* sd */
5635 NULL, /* ea_list */
5636 &fsp, /* result */
5637 &info); /* pinfo */
5639 if (!NT_STATUS_IS_OK(status)) {
5640 if (open_was_deferred(req->mid)) {
5641 /* We have re-scheduled this call. */
5642 goto out;
5644 reply_nterror(req, status);
5645 goto out;
5648 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
5649 if (!NT_STATUS_IS_OK(status)) {
5650 close_file(req, fsp, ERROR_CLOSE);
5651 reply_nterror(req, status);
5652 goto out;
5655 if (!set_delete_on_close(fsp, true,
5656 conn->session_info->security_token,
5657 &conn->session_info->utok)) {
5658 close_file(req, fsp, ERROR_CLOSE);
5659 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5660 goto out;
5663 status = close_file(req, fsp, NORMAL_CLOSE);
5664 if (!NT_STATUS_IS_OK(status)) {
5665 reply_nterror(req, status);
5666 } else {
5667 reply_outbuf(req, 0, 0);
5670 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
5672 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
5673 out:
5674 TALLOC_FREE(smb_dname);
5675 END_PROFILE(SMBrmdir);
5676 return;
5679 /*******************************************************************
5680 Resolve wildcards in a filename rename.
5681 ********************************************************************/
5683 static bool resolve_wildcards(TALLOC_CTX *ctx,
5684 const char *name1,
5685 const char *name2,
5686 char **pp_newname)
5688 char *name2_copy = NULL;
5689 char *root1 = NULL;
5690 char *root2 = NULL;
5691 char *ext1 = NULL;
5692 char *ext2 = NULL;
5693 char *p,*p2, *pname1, *pname2;
5695 name2_copy = talloc_strdup(ctx, name2);
5696 if (!name2_copy) {
5697 return False;
5700 pname1 = strrchr_m(name1,'/');
5701 pname2 = strrchr_m(name2_copy,'/');
5703 if (!pname1 || !pname2) {
5704 return False;
5707 /* Truncate the copy of name2 at the last '/' */
5708 *pname2 = '\0';
5710 /* Now go past the '/' */
5711 pname1++;
5712 pname2++;
5714 root1 = talloc_strdup(ctx, pname1);
5715 root2 = talloc_strdup(ctx, pname2);
5717 if (!root1 || !root2) {
5718 return False;
5721 p = strrchr_m(root1,'.');
5722 if (p) {
5723 *p = 0;
5724 ext1 = talloc_strdup(ctx, p+1);
5725 } else {
5726 ext1 = talloc_strdup(ctx, "");
5728 p = strrchr_m(root2,'.');
5729 if (p) {
5730 *p = 0;
5731 ext2 = talloc_strdup(ctx, p+1);
5732 } else {
5733 ext2 = talloc_strdup(ctx, "");
5736 if (!ext1 || !ext2) {
5737 return False;
5740 p = root1;
5741 p2 = root2;
5742 while (*p2) {
5743 if (*p2 == '?') {
5744 /* Hmmm. Should this be mb-aware ? */
5745 *p2 = *p;
5746 p2++;
5747 } else if (*p2 == '*') {
5748 *p2 = '\0';
5749 root2 = talloc_asprintf(ctx, "%s%s",
5750 root2,
5752 if (!root2) {
5753 return False;
5755 break;
5756 } else {
5757 p2++;
5759 if (*p) {
5760 p++;
5764 p = ext1;
5765 p2 = ext2;
5766 while (*p2) {
5767 if (*p2 == '?') {
5768 /* Hmmm. Should this be mb-aware ? */
5769 *p2 = *p;
5770 p2++;
5771 } else if (*p2 == '*') {
5772 *p2 = '\0';
5773 ext2 = talloc_asprintf(ctx, "%s%s",
5774 ext2,
5776 if (!ext2) {
5777 return False;
5779 break;
5780 } else {
5781 p2++;
5783 if (*p) {
5784 p++;
5788 if (*ext2) {
5789 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
5790 name2_copy,
5791 root2,
5792 ext2);
5793 } else {
5794 *pp_newname = talloc_asprintf(ctx, "%s/%s",
5795 name2_copy,
5796 root2);
5799 if (!*pp_newname) {
5800 return False;
5803 return True;
5806 /****************************************************************************
5807 Ensure open files have their names updated. Updated to notify other smbd's
5808 asynchronously.
5809 ****************************************************************************/
5811 static void rename_open_files(connection_struct *conn,
5812 struct share_mode_lock *lck,
5813 uint32_t orig_name_hash,
5814 const struct smb_filename *smb_fname_dst)
5816 files_struct *fsp;
5817 bool did_rename = False;
5818 NTSTATUS status;
5819 uint32_t new_name_hash;
5821 for(fsp = file_find_di_first(conn->sconn, lck->id); fsp;
5822 fsp = file_find_di_next(fsp)) {
5823 /* fsp_name is a relative path under the fsp. To change this for other
5824 sharepaths we need to manipulate relative paths. */
5825 /* TODO - create the absolute path and manipulate the newname
5826 relative to the sharepath. */
5827 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
5828 continue;
5830 if (fsp->name_hash != orig_name_hash) {
5831 continue;
5833 DEBUG(10, ("rename_open_files: renaming file fnum %d "
5834 "(file_id %s) from %s -> %s\n", fsp->fnum,
5835 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
5836 smb_fname_str_dbg(smb_fname_dst)));
5838 status = fsp_set_smb_fname(fsp, smb_fname_dst);
5839 if (NT_STATUS_IS_OK(status)) {
5840 did_rename = True;
5841 new_name_hash = fsp->name_hash;
5845 if (!did_rename) {
5846 DEBUG(10, ("rename_open_files: no open files on file_id %s "
5847 "for %s\n", file_id_string_tos(&lck->id),
5848 smb_fname_str_dbg(smb_fname_dst)));
5851 /* Send messages to all smbd's (not ourself) that the name has changed. */
5852 rename_share_filename(conn->sconn->msg_ctx, lck, conn->connectpath,
5853 orig_name_hash, new_name_hash,
5854 smb_fname_dst);
5858 /****************************************************************************
5859 We need to check if the source path is a parent directory of the destination
5860 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
5861 refuse the rename with a sharing violation. Under UNIX the above call can
5862 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
5863 probably need to check that the client is a Windows one before disallowing
5864 this as a UNIX client (one with UNIX extensions) can know the source is a
5865 symlink and make this decision intelligently. Found by an excellent bug
5866 report from <AndyLiebman@aol.com>.
5867 ****************************************************************************/
5869 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
5870 const struct smb_filename *smb_fname_dst)
5872 const char *psrc = smb_fname_src->base_name;
5873 const char *pdst = smb_fname_dst->base_name;
5874 size_t slen;
5876 if (psrc[0] == '.' && psrc[1] == '/') {
5877 psrc += 2;
5879 if (pdst[0] == '.' && pdst[1] == '/') {
5880 pdst += 2;
5882 if ((slen = strlen(psrc)) > strlen(pdst)) {
5883 return False;
5885 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
5889 * Do the notify calls from a rename
5892 static void notify_rename(connection_struct *conn, bool is_dir,
5893 const struct smb_filename *smb_fname_src,
5894 const struct smb_filename *smb_fname_dst)
5896 char *parent_dir_src = NULL;
5897 char *parent_dir_dst = NULL;
5898 uint32 mask;
5900 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
5901 : FILE_NOTIFY_CHANGE_FILE_NAME;
5903 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
5904 &parent_dir_src, NULL) ||
5905 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
5906 &parent_dir_dst, NULL)) {
5907 goto out;
5910 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
5911 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
5912 smb_fname_src->base_name);
5913 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
5914 smb_fname_dst->base_name);
5916 else {
5917 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
5918 smb_fname_src->base_name);
5919 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
5920 smb_fname_dst->base_name);
5923 /* this is a strange one. w2k3 gives an additional event for
5924 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
5925 files, but not directories */
5926 if (!is_dir) {
5927 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
5928 FILE_NOTIFY_CHANGE_ATTRIBUTES
5929 |FILE_NOTIFY_CHANGE_CREATION,
5930 smb_fname_dst->base_name);
5932 out:
5933 TALLOC_FREE(parent_dir_src);
5934 TALLOC_FREE(parent_dir_dst);
5937 /****************************************************************************
5938 Returns an error if the parent directory for a filename is open in an
5939 incompatible way.
5940 ****************************************************************************/
5942 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
5943 const struct smb_filename *smb_fname_dst_in)
5945 char *parent_dir = NULL;
5946 struct smb_filename smb_fname_parent;
5947 struct file_id id;
5948 files_struct *fsp = NULL;
5949 int ret;
5951 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
5952 &parent_dir, NULL)) {
5953 return NT_STATUS_NO_MEMORY;
5955 ZERO_STRUCT(smb_fname_parent);
5956 smb_fname_parent.base_name = parent_dir;
5958 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
5959 if (ret == -1) {
5960 return map_nt_error_from_unix(errno);
5964 * We're only checking on this smbd here, mostly good
5965 * enough.. and will pass tests.
5968 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
5969 for (fsp = file_find_di_first(conn->sconn, id); fsp;
5970 fsp = file_find_di_next(fsp)) {
5971 if (fsp->access_mask & DELETE_ACCESS) {
5972 return NT_STATUS_SHARING_VIOLATION;
5975 return NT_STATUS_OK;
5978 /****************************************************************************
5979 Rename an open file - given an fsp.
5980 ****************************************************************************/
5982 NTSTATUS rename_internals_fsp(connection_struct *conn,
5983 files_struct *fsp,
5984 const struct smb_filename *smb_fname_dst_in,
5985 uint32 attrs,
5986 bool replace_if_exists)
5988 TALLOC_CTX *ctx = talloc_tos();
5989 struct smb_filename *smb_fname_dst = NULL;
5990 NTSTATUS status = NT_STATUS_OK;
5991 struct share_mode_lock *lck = NULL;
5992 bool dst_exists, old_is_stream, new_is_stream;
5994 status = check_name(conn, smb_fname_dst_in->base_name);
5995 if (!NT_STATUS_IS_OK(status)) {
5996 return status;
5999 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
6000 if (!NT_STATUS_IS_OK(status)) {
6001 return status;
6004 /* Make a copy of the dst smb_fname structs */
6006 status = copy_smb_filename(ctx, smb_fname_dst_in, &smb_fname_dst);
6007 if (!NT_STATUS_IS_OK(status)) {
6008 goto out;
6012 * Check for special case with case preserving and not
6013 * case sensitive. If the old last component differs from the original
6014 * last component only by case, then we should allow
6015 * the rename (user is trying to change the case of the
6016 * filename).
6018 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
6019 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6020 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
6021 char *last_slash;
6022 char *fname_dst_lcomp_base_mod = NULL;
6023 struct smb_filename *smb_fname_orig_lcomp = NULL;
6026 * Get the last component of the destination name.
6028 last_slash = strrchr_m(smb_fname_dst->base_name, '/');
6029 if (last_slash) {
6030 fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1);
6031 } else {
6032 fname_dst_lcomp_base_mod = talloc_strdup(ctx, smb_fname_dst->base_name);
6034 if (!fname_dst_lcomp_base_mod) {
6035 status = NT_STATUS_NO_MEMORY;
6036 goto out;
6040 * Create an smb_filename struct using the original last
6041 * component of the destination.
6043 status = create_synthetic_smb_fname_split(ctx,
6044 smb_fname_dst->original_lcomp, NULL,
6045 &smb_fname_orig_lcomp);
6046 if (!NT_STATUS_IS_OK(status)) {
6047 TALLOC_FREE(fname_dst_lcomp_base_mod);
6048 goto out;
6051 /* If the base names only differ by case, use original. */
6052 if(!strcsequal(fname_dst_lcomp_base_mod,
6053 smb_fname_orig_lcomp->base_name)) {
6054 char *tmp;
6056 * Replace the modified last component with the
6057 * original.
6059 if (last_slash) {
6060 *last_slash = '\0'; /* Truncate at the '/' */
6061 tmp = talloc_asprintf(smb_fname_dst,
6062 "%s/%s",
6063 smb_fname_dst->base_name,
6064 smb_fname_orig_lcomp->base_name);
6065 } else {
6066 tmp = talloc_asprintf(smb_fname_dst,
6067 "%s",
6068 smb_fname_orig_lcomp->base_name);
6070 if (tmp == NULL) {
6071 status = NT_STATUS_NO_MEMORY;
6072 TALLOC_FREE(fname_dst_lcomp_base_mod);
6073 TALLOC_FREE(smb_fname_orig_lcomp);
6074 goto out;
6076 TALLOC_FREE(smb_fname_dst->base_name);
6077 smb_fname_dst->base_name = tmp;
6080 /* If the stream_names only differ by case, use original. */
6081 if(!strcsequal(smb_fname_dst->stream_name,
6082 smb_fname_orig_lcomp->stream_name)) {
6083 char *tmp = NULL;
6084 /* Use the original stream. */
6085 tmp = talloc_strdup(smb_fname_dst,
6086 smb_fname_orig_lcomp->stream_name);
6087 if (tmp == NULL) {
6088 status = NT_STATUS_NO_MEMORY;
6089 TALLOC_FREE(fname_dst_lcomp_base_mod);
6090 TALLOC_FREE(smb_fname_orig_lcomp);
6091 goto out;
6093 TALLOC_FREE(smb_fname_dst->stream_name);
6094 smb_fname_dst->stream_name = tmp;
6096 TALLOC_FREE(fname_dst_lcomp_base_mod);
6097 TALLOC_FREE(smb_fname_orig_lcomp);
6101 * If the src and dest names are identical - including case,
6102 * don't do the rename, just return success.
6105 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6106 strcsequal(fsp->fsp_name->stream_name,
6107 smb_fname_dst->stream_name)) {
6108 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6109 "- returning success\n",
6110 smb_fname_str_dbg(smb_fname_dst)));
6111 status = NT_STATUS_OK;
6112 goto out;
6115 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6116 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6118 /* Return the correct error code if both names aren't streams. */
6119 if (!old_is_stream && new_is_stream) {
6120 status = NT_STATUS_OBJECT_NAME_INVALID;
6121 goto out;
6124 if (old_is_stream && !new_is_stream) {
6125 status = NT_STATUS_INVALID_PARAMETER;
6126 goto out;
6129 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6131 if(!replace_if_exists && dst_exists) {
6132 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6133 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6134 smb_fname_str_dbg(smb_fname_dst)));
6135 status = NT_STATUS_OBJECT_NAME_COLLISION;
6136 goto out;
6139 if (dst_exists) {
6140 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6141 &smb_fname_dst->st);
6142 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6143 fileid);
6144 /* The file can be open when renaming a stream */
6145 if (dst_fsp && !new_is_stream) {
6146 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6147 status = NT_STATUS_ACCESS_DENIED;
6148 goto out;
6152 /* Ensure we have a valid stat struct for the source. */
6153 status = vfs_stat_fsp(fsp);
6154 if (!NT_STATUS_IS_OK(status)) {
6155 goto out;
6158 status = can_rename(conn, fsp, attrs);
6160 if (!NT_STATUS_IS_OK(status)) {
6161 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6162 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6163 smb_fname_str_dbg(smb_fname_dst)));
6164 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6165 status = NT_STATUS_ACCESS_DENIED;
6166 goto out;
6169 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6170 status = NT_STATUS_ACCESS_DENIED;
6173 lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
6174 NULL);
6177 * We have the file open ourselves, so not being able to get the
6178 * corresponding share mode lock is a fatal error.
6181 SMB_ASSERT(lck != NULL);
6183 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6184 uint32 create_options = fsp->fh->private_options;
6186 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6187 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6188 smb_fname_str_dbg(smb_fname_dst)));
6190 if (!fsp->is_directory &&
6191 !lp_posix_pathnames() &&
6192 (lp_map_archive(SNUM(conn)) ||
6193 lp_store_dos_attributes(SNUM(conn)))) {
6194 /* We must set the archive bit on the newly
6195 renamed file. */
6196 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6197 uint32_t old_dosmode = dos_mode(conn,
6198 smb_fname_dst);
6199 file_set_dosmode(conn,
6200 smb_fname_dst,
6201 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6202 NULL,
6203 true);
6207 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6208 smb_fname_dst);
6210 rename_open_files(conn, lck, fsp->name_hash, smb_fname_dst);
6213 * A rename acts as a new file create w.r.t. allowing an initial delete
6214 * on close, probably because in Windows there is a new handle to the
6215 * new file. If initial delete on close was requested but not
6216 * originally set, we need to set it here. This is probably not 100% correct,
6217 * but will work for the CIFSFS client which in non-posix mode
6218 * depends on these semantics. JRA.
6221 if (create_options & FILE_DELETE_ON_CLOSE) {
6222 status = can_set_delete_on_close(fsp, 0);
6224 if (NT_STATUS_IS_OK(status)) {
6225 /* Note that here we set the *inital* delete on close flag,
6226 * not the regular one. The magic gets handled in close. */
6227 fsp->initial_delete_on_close = True;
6230 TALLOC_FREE(lck);
6231 status = NT_STATUS_OK;
6232 goto out;
6235 TALLOC_FREE(lck);
6237 if (errno == ENOTDIR || errno == EISDIR) {
6238 status = NT_STATUS_OBJECT_NAME_COLLISION;
6239 } else {
6240 status = map_nt_error_from_unix(errno);
6243 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6244 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6245 smb_fname_str_dbg(smb_fname_dst)));
6247 out:
6248 TALLOC_FREE(smb_fname_dst);
6250 return status;
6253 /****************************************************************************
6254 The guts of the rename command, split out so it may be called by the NT SMB
6255 code.
6256 ****************************************************************************/
6258 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6259 connection_struct *conn,
6260 struct smb_request *req,
6261 struct smb_filename *smb_fname_src,
6262 struct smb_filename *smb_fname_dst,
6263 uint32 attrs,
6264 bool replace_if_exists,
6265 bool src_has_wild,
6266 bool dest_has_wild,
6267 uint32_t access_mask)
6269 char *fname_src_dir = NULL;
6270 char *fname_src_mask = NULL;
6271 int count=0;
6272 NTSTATUS status = NT_STATUS_OK;
6273 struct smb_Dir *dir_hnd = NULL;
6274 const char *dname = NULL;
6275 char *talloced = NULL;
6276 long offset = 0;
6277 int create_options = 0;
6278 bool posix_pathnames = lp_posix_pathnames();
6281 * Split the old name into directory and last component
6282 * strings. Note that unix_convert may have stripped off a
6283 * leading ./ from both name and newname if the rename is
6284 * at the root of the share. We need to make sure either both
6285 * name and newname contain a / character or neither of them do
6286 * as this is checked in resolve_wildcards().
6289 /* Split up the directory from the filename/mask. */
6290 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6291 &fname_src_dir, &fname_src_mask);
6292 if (!NT_STATUS_IS_OK(status)) {
6293 status = NT_STATUS_NO_MEMORY;
6294 goto out;
6298 * We should only check the mangled cache
6299 * here if unix_convert failed. This means
6300 * that the path in 'mask' doesn't exist
6301 * on the file system and so we need to look
6302 * for a possible mangle. This patch from
6303 * Tine Smukavec <valentin.smukavec@hermes.si>.
6306 if (!VALID_STAT(smb_fname_src->st) &&
6307 mangle_is_mangled(fname_src_mask, conn->params)) {
6308 char *new_mask = NULL;
6309 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6310 conn->params);
6311 if (new_mask) {
6312 TALLOC_FREE(fname_src_mask);
6313 fname_src_mask = new_mask;
6317 if (!src_has_wild) {
6318 files_struct *fsp;
6321 * Only one file needs to be renamed. Append the mask back
6322 * onto the directory.
6324 TALLOC_FREE(smb_fname_src->base_name);
6325 if (ISDOT(fname_src_dir)) {
6326 /* Ensure we use canonical names on open. */
6327 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6328 "%s",
6329 fname_src_mask);
6330 } else {
6331 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6332 "%s/%s",
6333 fname_src_dir,
6334 fname_src_mask);
6336 if (!smb_fname_src->base_name) {
6337 status = NT_STATUS_NO_MEMORY;
6338 goto out;
6341 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6342 "case_preserve = %d, short case preserve = %d, "
6343 "directory = %s, newname = %s, "
6344 "last_component_dest = %s\n",
6345 conn->case_sensitive, conn->case_preserve,
6346 conn->short_case_preserve,
6347 smb_fname_str_dbg(smb_fname_src),
6348 smb_fname_str_dbg(smb_fname_dst),
6349 smb_fname_dst->original_lcomp));
6351 /* The dest name still may have wildcards. */
6352 if (dest_has_wild) {
6353 char *fname_dst_mod = NULL;
6354 if (!resolve_wildcards(smb_fname_dst,
6355 smb_fname_src->base_name,
6356 smb_fname_dst->base_name,
6357 &fname_dst_mod)) {
6358 DEBUG(6, ("rename_internals: resolve_wildcards "
6359 "%s %s failed\n",
6360 smb_fname_src->base_name,
6361 smb_fname_dst->base_name));
6362 status = NT_STATUS_NO_MEMORY;
6363 goto out;
6365 TALLOC_FREE(smb_fname_dst->base_name);
6366 smb_fname_dst->base_name = fname_dst_mod;
6369 ZERO_STRUCT(smb_fname_src->st);
6370 if (posix_pathnames) {
6371 SMB_VFS_LSTAT(conn, smb_fname_src);
6372 } else {
6373 SMB_VFS_STAT(conn, smb_fname_src);
6376 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6377 create_options |= FILE_DIRECTORY_FILE;
6380 status = SMB_VFS_CREATE_FILE(
6381 conn, /* conn */
6382 req, /* req */
6383 0, /* root_dir_fid */
6384 smb_fname_src, /* fname */
6385 access_mask, /* access_mask */
6386 (FILE_SHARE_READ | /* share_access */
6387 FILE_SHARE_WRITE),
6388 FILE_OPEN, /* create_disposition*/
6389 create_options, /* create_options */
6390 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6391 0, /* oplock_request */
6392 0, /* allocation_size */
6393 0, /* private_flags */
6394 NULL, /* sd */
6395 NULL, /* ea_list */
6396 &fsp, /* result */
6397 NULL); /* pinfo */
6399 if (!NT_STATUS_IS_OK(status)) {
6400 DEBUG(3, ("Could not open rename source %s: %s\n",
6401 smb_fname_str_dbg(smb_fname_src),
6402 nt_errstr(status)));
6403 goto out;
6406 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6407 attrs, replace_if_exists);
6409 close_file(req, fsp, NORMAL_CLOSE);
6411 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
6412 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
6413 smb_fname_str_dbg(smb_fname_dst)));
6415 goto out;
6419 * Wildcards - process each file that matches.
6421 if (strequal(fname_src_mask, "????????.???")) {
6422 TALLOC_FREE(fname_src_mask);
6423 fname_src_mask = talloc_strdup(ctx, "*");
6424 if (!fname_src_mask) {
6425 status = NT_STATUS_NO_MEMORY;
6426 goto out;
6430 status = check_name(conn, fname_src_dir);
6431 if (!NT_STATUS_IS_OK(status)) {
6432 goto out;
6435 dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask,
6436 attrs);
6437 if (dir_hnd == NULL) {
6438 status = map_nt_error_from_unix(errno);
6439 goto out;
6442 status = NT_STATUS_NO_SUCH_FILE;
6444 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
6445 * - gentest fix. JRA
6448 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
6449 &talloced))) {
6450 files_struct *fsp = NULL;
6451 char *destname = NULL;
6452 bool sysdir_entry = False;
6454 /* Quick check for "." and ".." */
6455 if (ISDOT(dname) || ISDOTDOT(dname)) {
6456 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
6457 sysdir_entry = True;
6458 } else {
6459 TALLOC_FREE(talloced);
6460 continue;
6464 if (!is_visible_file(conn, fname_src_dir, dname,
6465 &smb_fname_src->st, false)) {
6466 TALLOC_FREE(talloced);
6467 continue;
6470 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
6471 TALLOC_FREE(talloced);
6472 continue;
6475 if (sysdir_entry) {
6476 status = NT_STATUS_OBJECT_NAME_INVALID;
6477 break;
6480 TALLOC_FREE(smb_fname_src->base_name);
6481 if (ISDOT(fname_src_dir)) {
6482 /* Ensure we use canonical names on open. */
6483 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6484 "%s",
6485 dname);
6486 } else {
6487 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6488 "%s/%s",
6489 fname_src_dir,
6490 dname);
6492 if (!smb_fname_src->base_name) {
6493 status = NT_STATUS_NO_MEMORY;
6494 goto out;
6497 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6498 smb_fname_dst->base_name,
6499 &destname)) {
6500 DEBUG(6, ("resolve_wildcards %s %s failed\n",
6501 smb_fname_src->base_name, destname));
6502 TALLOC_FREE(talloced);
6503 continue;
6505 if (!destname) {
6506 status = NT_STATUS_NO_MEMORY;
6507 goto out;
6510 TALLOC_FREE(smb_fname_dst->base_name);
6511 smb_fname_dst->base_name = destname;
6513 ZERO_STRUCT(smb_fname_src->st);
6514 if (posix_pathnames) {
6515 SMB_VFS_LSTAT(conn, smb_fname_src);
6516 } else {
6517 SMB_VFS_STAT(conn, smb_fname_src);
6520 create_options = 0;
6522 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6523 create_options |= FILE_DIRECTORY_FILE;
6526 status = SMB_VFS_CREATE_FILE(
6527 conn, /* conn */
6528 req, /* req */
6529 0, /* root_dir_fid */
6530 smb_fname_src, /* fname */
6531 access_mask, /* access_mask */
6532 (FILE_SHARE_READ | /* share_access */
6533 FILE_SHARE_WRITE),
6534 FILE_OPEN, /* create_disposition*/
6535 create_options, /* create_options */
6536 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6537 0, /* oplock_request */
6538 0, /* allocation_size */
6539 0, /* private_flags */
6540 NULL, /* sd */
6541 NULL, /* ea_list */
6542 &fsp, /* result */
6543 NULL); /* pinfo */
6545 if (!NT_STATUS_IS_OK(status)) {
6546 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
6547 "returned %s rename %s -> %s\n",
6548 nt_errstr(status),
6549 smb_fname_str_dbg(smb_fname_src),
6550 smb_fname_str_dbg(smb_fname_dst)));
6551 break;
6554 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6555 dname);
6556 if (!smb_fname_dst->original_lcomp) {
6557 status = NT_STATUS_NO_MEMORY;
6558 goto out;
6561 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6562 attrs, replace_if_exists);
6564 close_file(req, fsp, NORMAL_CLOSE);
6566 if (!NT_STATUS_IS_OK(status)) {
6567 DEBUG(3, ("rename_internals_fsp returned %s for "
6568 "rename %s -> %s\n", nt_errstr(status),
6569 smb_fname_str_dbg(smb_fname_src),
6570 smb_fname_str_dbg(smb_fname_dst)));
6571 break;
6574 count++;
6576 DEBUG(3,("rename_internals: doing rename on %s -> "
6577 "%s\n", smb_fname_str_dbg(smb_fname_src),
6578 smb_fname_str_dbg(smb_fname_src)));
6579 TALLOC_FREE(talloced);
6581 TALLOC_FREE(dir_hnd);
6583 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
6584 status = map_nt_error_from_unix(errno);
6587 out:
6588 TALLOC_FREE(talloced);
6589 TALLOC_FREE(fname_src_dir);
6590 TALLOC_FREE(fname_src_mask);
6591 return status;
6594 /****************************************************************************
6595 Reply to a mv.
6596 ****************************************************************************/
6598 void reply_mv(struct smb_request *req)
6600 connection_struct *conn = req->conn;
6601 char *name = NULL;
6602 char *newname = NULL;
6603 const char *p;
6604 uint32 attrs;
6605 NTSTATUS status;
6606 bool src_has_wcard = False;
6607 bool dest_has_wcard = False;
6608 TALLOC_CTX *ctx = talloc_tos();
6609 struct smb_filename *smb_fname_src = NULL;
6610 struct smb_filename *smb_fname_dst = NULL;
6611 uint32_t src_ucf_flags = lp_posix_pathnames() ? UCF_UNIX_NAME_LOOKUP : UCF_COND_ALLOW_WCARD_LCOMP;
6612 uint32_t dst_ucf_flags = UCF_SAVE_LCOMP | (lp_posix_pathnames() ? 0 : UCF_COND_ALLOW_WCARD_LCOMP);
6613 bool stream_rename = false;
6615 START_PROFILE(SMBmv);
6617 if (req->wct < 1) {
6618 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6619 goto out;
6622 attrs = SVAL(req->vwv+0, 0);
6624 p = (const char *)req->buf + 1;
6625 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
6626 &status, &src_has_wcard);
6627 if (!NT_STATUS_IS_OK(status)) {
6628 reply_nterror(req, status);
6629 goto out;
6631 p++;
6632 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
6633 &status, &dest_has_wcard);
6634 if (!NT_STATUS_IS_OK(status)) {
6635 reply_nterror(req, status);
6636 goto out;
6639 if (!lp_posix_pathnames()) {
6640 /* The newname must begin with a ':' if the
6641 name contains a ':'. */
6642 if (strchr_m(name, ':')) {
6643 if (newname[0] != ':') {
6644 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6645 goto out;
6647 stream_rename = true;
6651 status = filename_convert(ctx,
6652 conn,
6653 req->flags2 & FLAGS2_DFS_PATHNAMES,
6654 name,
6655 src_ucf_flags,
6656 &src_has_wcard,
6657 &smb_fname_src);
6659 if (!NT_STATUS_IS_OK(status)) {
6660 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6661 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6662 ERRSRV, ERRbadpath);
6663 goto out;
6665 reply_nterror(req, status);
6666 goto out;
6669 status = filename_convert(ctx,
6670 conn,
6671 req->flags2 & FLAGS2_DFS_PATHNAMES,
6672 newname,
6673 dst_ucf_flags,
6674 &dest_has_wcard,
6675 &smb_fname_dst);
6677 if (!NT_STATUS_IS_OK(status)) {
6678 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6679 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6680 ERRSRV, ERRbadpath);
6681 goto out;
6683 reply_nterror(req, status);
6684 goto out;
6687 if (stream_rename) {
6688 /* smb_fname_dst->base_name must be the same as
6689 smb_fname_src->base_name. */
6690 TALLOC_FREE(smb_fname_dst->base_name);
6691 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
6692 smb_fname_src->base_name);
6693 if (!smb_fname_dst->base_name) {
6694 reply_nterror(req, NT_STATUS_NO_MEMORY);
6695 goto out;
6699 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
6700 smb_fname_str_dbg(smb_fname_dst)));
6702 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
6703 attrs, False, src_has_wcard, dest_has_wcard,
6704 DELETE_ACCESS);
6705 if (!NT_STATUS_IS_OK(status)) {
6706 if (open_was_deferred(req->mid)) {
6707 /* We have re-scheduled this call. */
6708 goto out;
6710 reply_nterror(req, status);
6711 goto out;
6714 reply_outbuf(req, 0, 0);
6715 out:
6716 TALLOC_FREE(smb_fname_src);
6717 TALLOC_FREE(smb_fname_dst);
6718 END_PROFILE(SMBmv);
6719 return;
6722 /*******************************************************************
6723 Copy a file as part of a reply_copy.
6724 ******************************************************************/
6727 * TODO: check error codes on all callers
6730 NTSTATUS copy_file(TALLOC_CTX *ctx,
6731 connection_struct *conn,
6732 struct smb_filename *smb_fname_src,
6733 struct smb_filename *smb_fname_dst,
6734 int ofun,
6735 int count,
6736 bool target_is_directory)
6738 struct smb_filename *smb_fname_dst_tmp = NULL;
6739 SMB_OFF_T ret=-1;
6740 files_struct *fsp1,*fsp2;
6741 uint32 dosattrs;
6742 uint32 new_create_disposition;
6743 NTSTATUS status;
6746 status = copy_smb_filename(ctx, smb_fname_dst, &smb_fname_dst_tmp);
6747 if (!NT_STATUS_IS_OK(status)) {
6748 return status;
6752 * If the target is a directory, extract the last component from the
6753 * src filename and append it to the dst filename
6755 if (target_is_directory) {
6756 const char *p;
6758 /* dest/target can't be a stream if it's a directory. */
6759 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
6761 p = strrchr_m(smb_fname_src->base_name,'/');
6762 if (p) {
6763 p++;
6764 } else {
6765 p = smb_fname_src->base_name;
6767 smb_fname_dst_tmp->base_name =
6768 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
6770 if (!smb_fname_dst_tmp->base_name) {
6771 status = NT_STATUS_NO_MEMORY;
6772 goto out;
6776 status = vfs_file_exist(conn, smb_fname_src);
6777 if (!NT_STATUS_IS_OK(status)) {
6778 goto out;
6781 if (!target_is_directory && count) {
6782 new_create_disposition = FILE_OPEN;
6783 } else {
6784 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
6785 0, ofun,
6786 NULL, NULL,
6787 &new_create_disposition,
6788 NULL,
6789 NULL)) {
6790 status = NT_STATUS_INVALID_PARAMETER;
6791 goto out;
6795 /* Open the src file for reading. */
6796 status = SMB_VFS_CREATE_FILE(
6797 conn, /* conn */
6798 NULL, /* req */
6799 0, /* root_dir_fid */
6800 smb_fname_src, /* fname */
6801 FILE_GENERIC_READ, /* access_mask */
6802 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6803 FILE_OPEN, /* create_disposition*/
6804 0, /* create_options */
6805 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
6806 INTERNAL_OPEN_ONLY, /* oplock_request */
6807 0, /* allocation_size */
6808 0, /* private_flags */
6809 NULL, /* sd */
6810 NULL, /* ea_list */
6811 &fsp1, /* result */
6812 NULL); /* psbuf */
6814 if (!NT_STATUS_IS_OK(status)) {
6815 goto out;
6818 dosattrs = dos_mode(conn, smb_fname_src);
6820 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
6821 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
6824 /* Open the dst file for writing. */
6825 status = SMB_VFS_CREATE_FILE(
6826 conn, /* conn */
6827 NULL, /* req */
6828 0, /* root_dir_fid */
6829 smb_fname_dst, /* fname */
6830 FILE_GENERIC_WRITE, /* access_mask */
6831 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6832 new_create_disposition, /* create_disposition*/
6833 0, /* create_options */
6834 dosattrs, /* file_attributes */
6835 INTERNAL_OPEN_ONLY, /* oplock_request */
6836 0, /* allocation_size */
6837 0, /* private_flags */
6838 NULL, /* sd */
6839 NULL, /* ea_list */
6840 &fsp2, /* result */
6841 NULL); /* psbuf */
6843 if (!NT_STATUS_IS_OK(status)) {
6844 close_file(NULL, fsp1, ERROR_CLOSE);
6845 goto out;
6848 if (ofun & OPENX_FILE_EXISTS_OPEN) {
6849 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
6850 if (ret == -1) {
6851 DEBUG(0, ("error - vfs lseek returned error %s\n",
6852 strerror(errno)));
6853 status = map_nt_error_from_unix(errno);
6854 close_file(NULL, fsp1, ERROR_CLOSE);
6855 close_file(NULL, fsp2, ERROR_CLOSE);
6856 goto out;
6860 /* Do the actual copy. */
6861 if (smb_fname_src->st.st_ex_size) {
6862 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
6863 } else {
6864 ret = 0;
6867 close_file(NULL, fsp1, NORMAL_CLOSE);
6869 /* Ensure the modtime is set correctly on the destination file. */
6870 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
6873 * As we are opening fsp1 read-only we only expect
6874 * an error on close on fsp2 if we are out of space.
6875 * Thus we don't look at the error return from the
6876 * close of fsp1.
6878 status = close_file(NULL, fsp2, NORMAL_CLOSE);
6880 if (!NT_STATUS_IS_OK(status)) {
6881 goto out;
6884 if (ret != (SMB_OFF_T)smb_fname_src->st.st_ex_size) {
6885 status = NT_STATUS_DISK_FULL;
6886 goto out;
6889 status = NT_STATUS_OK;
6891 out:
6892 TALLOC_FREE(smb_fname_dst_tmp);
6893 return status;
6896 /****************************************************************************
6897 Reply to a file copy.
6898 ****************************************************************************/
6900 void reply_copy(struct smb_request *req)
6902 connection_struct *conn = req->conn;
6903 struct smb_filename *smb_fname_src = NULL;
6904 struct smb_filename *smb_fname_dst = NULL;
6905 char *fname_src = NULL;
6906 char *fname_dst = NULL;
6907 char *fname_src_mask = NULL;
6908 char *fname_src_dir = NULL;
6909 const char *p;
6910 int count=0;
6911 int error = ERRnoaccess;
6912 int tid2;
6913 int ofun;
6914 int flags;
6915 bool target_is_directory=False;
6916 bool source_has_wild = False;
6917 bool dest_has_wild = False;
6918 NTSTATUS status;
6919 TALLOC_CTX *ctx = talloc_tos();
6921 START_PROFILE(SMBcopy);
6923 if (req->wct < 3) {
6924 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6925 goto out;
6928 tid2 = SVAL(req->vwv+0, 0);
6929 ofun = SVAL(req->vwv+1, 0);
6930 flags = SVAL(req->vwv+2, 0);
6932 p = (const char *)req->buf;
6933 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
6934 &status, &source_has_wild);
6935 if (!NT_STATUS_IS_OK(status)) {
6936 reply_nterror(req, status);
6937 goto out;
6939 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
6940 &status, &dest_has_wild);
6941 if (!NT_STATUS_IS_OK(status)) {
6942 reply_nterror(req, status);
6943 goto out;
6946 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
6948 if (tid2 != conn->cnum) {
6949 /* can't currently handle inter share copies XXXX */
6950 DEBUG(3,("Rejecting inter-share copy\n"));
6951 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
6952 goto out;
6955 status = filename_convert(ctx, conn,
6956 req->flags2 & FLAGS2_DFS_PATHNAMES,
6957 fname_src,
6958 UCF_COND_ALLOW_WCARD_LCOMP,
6959 &source_has_wild,
6960 &smb_fname_src);
6961 if (!NT_STATUS_IS_OK(status)) {
6962 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6963 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6964 ERRSRV, ERRbadpath);
6965 goto out;
6967 reply_nterror(req, status);
6968 goto out;
6971 status = filename_convert(ctx, conn,
6972 req->flags2 & FLAGS2_DFS_PATHNAMES,
6973 fname_dst,
6974 UCF_COND_ALLOW_WCARD_LCOMP,
6975 &dest_has_wild,
6976 &smb_fname_dst);
6977 if (!NT_STATUS_IS_OK(status)) {
6978 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6979 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6980 ERRSRV, ERRbadpath);
6981 goto out;
6983 reply_nterror(req, status);
6984 goto out;
6987 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
6989 if ((flags&1) && target_is_directory) {
6990 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
6991 goto out;
6994 if ((flags&2) && !target_is_directory) {
6995 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
6996 goto out;
6999 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
7000 /* wants a tree copy! XXXX */
7001 DEBUG(3,("Rejecting tree copy\n"));
7002 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7003 goto out;
7006 /* Split up the directory from the filename/mask. */
7007 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7008 &fname_src_dir, &fname_src_mask);
7009 if (!NT_STATUS_IS_OK(status)) {
7010 reply_nterror(req, NT_STATUS_NO_MEMORY);
7011 goto out;
7015 * We should only check the mangled cache
7016 * here if unix_convert failed. This means
7017 * that the path in 'mask' doesn't exist
7018 * on the file system and so we need to look
7019 * for a possible mangle. This patch from
7020 * Tine Smukavec <valentin.smukavec@hermes.si>.
7022 if (!VALID_STAT(smb_fname_src->st) &&
7023 mangle_is_mangled(fname_src_mask, conn->params)) {
7024 char *new_mask = NULL;
7025 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
7026 &new_mask, conn->params);
7028 /* Use demangled name if one was successfully found. */
7029 if (new_mask) {
7030 TALLOC_FREE(fname_src_mask);
7031 fname_src_mask = new_mask;
7035 if (!source_has_wild) {
7038 * Only one file needs to be copied. Append the mask back onto
7039 * the directory.
7041 TALLOC_FREE(smb_fname_src->base_name);
7042 if (ISDOT(fname_src_dir)) {
7043 /* Ensure we use canonical names on open. */
7044 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7045 "%s",
7046 fname_src_mask);
7047 } else {
7048 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7049 "%s/%s",
7050 fname_src_dir,
7051 fname_src_mask);
7053 if (!smb_fname_src->base_name) {
7054 reply_nterror(req, NT_STATUS_NO_MEMORY);
7055 goto out;
7058 if (dest_has_wild) {
7059 char *fname_dst_mod = NULL;
7060 if (!resolve_wildcards(smb_fname_dst,
7061 smb_fname_src->base_name,
7062 smb_fname_dst->base_name,
7063 &fname_dst_mod)) {
7064 reply_nterror(req, NT_STATUS_NO_MEMORY);
7065 goto out;
7067 TALLOC_FREE(smb_fname_dst->base_name);
7068 smb_fname_dst->base_name = fname_dst_mod;
7071 status = check_name(conn, smb_fname_src->base_name);
7072 if (!NT_STATUS_IS_OK(status)) {
7073 reply_nterror(req, status);
7074 goto out;
7077 status = check_name(conn, smb_fname_dst->base_name);
7078 if (!NT_STATUS_IS_OK(status)) {
7079 reply_nterror(req, status);
7080 goto out;
7083 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7084 ofun, count, target_is_directory);
7086 if(!NT_STATUS_IS_OK(status)) {
7087 reply_nterror(req, status);
7088 goto out;
7089 } else {
7090 count++;
7092 } else {
7093 struct smb_Dir *dir_hnd = NULL;
7094 const char *dname = NULL;
7095 char *talloced = NULL;
7096 long offset = 0;
7099 * There is a wildcard that requires us to actually read the
7100 * src dir and copy each file matching the mask to the dst.
7101 * Right now streams won't be copied, but this could
7102 * presumably be added with a nested loop for reach dir entry.
7104 SMB_ASSERT(!smb_fname_src->stream_name);
7105 SMB_ASSERT(!smb_fname_dst->stream_name);
7107 smb_fname_src->stream_name = NULL;
7108 smb_fname_dst->stream_name = NULL;
7110 if (strequal(fname_src_mask,"????????.???")) {
7111 TALLOC_FREE(fname_src_mask);
7112 fname_src_mask = talloc_strdup(ctx, "*");
7113 if (!fname_src_mask) {
7114 reply_nterror(req, NT_STATUS_NO_MEMORY);
7115 goto out;
7119 status = check_name(conn, fname_src_dir);
7120 if (!NT_STATUS_IS_OK(status)) {
7121 reply_nterror(req, status);
7122 goto out;
7125 dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0);
7126 if (dir_hnd == NULL) {
7127 status = map_nt_error_from_unix(errno);
7128 reply_nterror(req, status);
7129 goto out;
7132 error = ERRbadfile;
7134 /* Iterate over the src dir copying each entry to the dst. */
7135 while ((dname = ReadDirName(dir_hnd, &offset,
7136 &smb_fname_src->st, &talloced))) {
7137 char *destname = NULL;
7139 if (ISDOT(dname) || ISDOTDOT(dname)) {
7140 TALLOC_FREE(talloced);
7141 continue;
7144 if (!is_visible_file(conn, fname_src_dir, dname,
7145 &smb_fname_src->st, false)) {
7146 TALLOC_FREE(talloced);
7147 continue;
7150 if(!mask_match(dname, fname_src_mask,
7151 conn->case_sensitive)) {
7152 TALLOC_FREE(talloced);
7153 continue;
7156 error = ERRnoaccess;
7158 /* Get the src smb_fname struct setup. */
7159 TALLOC_FREE(smb_fname_src->base_name);
7160 if (ISDOT(fname_src_dir)) {
7161 /* Ensure we use canonical names on open. */
7162 smb_fname_src->base_name =
7163 talloc_asprintf(smb_fname_src, "%s",
7164 dname);
7165 } else {
7166 smb_fname_src->base_name =
7167 talloc_asprintf(smb_fname_src, "%s/%s",
7168 fname_src_dir, dname);
7171 if (!smb_fname_src->base_name) {
7172 TALLOC_FREE(dir_hnd);
7173 TALLOC_FREE(talloced);
7174 reply_nterror(req, NT_STATUS_NO_MEMORY);
7175 goto out;
7178 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7179 smb_fname_dst->base_name,
7180 &destname)) {
7181 TALLOC_FREE(talloced);
7182 continue;
7184 if (!destname) {
7185 TALLOC_FREE(dir_hnd);
7186 TALLOC_FREE(talloced);
7187 reply_nterror(req, NT_STATUS_NO_MEMORY);
7188 goto out;
7191 TALLOC_FREE(smb_fname_dst->base_name);
7192 smb_fname_dst->base_name = destname;
7194 status = check_name(conn, smb_fname_src->base_name);
7195 if (!NT_STATUS_IS_OK(status)) {
7196 TALLOC_FREE(dir_hnd);
7197 TALLOC_FREE(talloced);
7198 reply_nterror(req, status);
7199 goto out;
7202 status = check_name(conn, smb_fname_dst->base_name);
7203 if (!NT_STATUS_IS_OK(status)) {
7204 TALLOC_FREE(dir_hnd);
7205 TALLOC_FREE(talloced);
7206 reply_nterror(req, status);
7207 goto out;
7210 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7211 smb_fname_src->base_name,
7212 smb_fname_dst->base_name));
7214 status = copy_file(ctx, conn, smb_fname_src,
7215 smb_fname_dst, ofun, count,
7216 target_is_directory);
7217 if (NT_STATUS_IS_OK(status)) {
7218 count++;
7221 TALLOC_FREE(talloced);
7223 TALLOC_FREE(dir_hnd);
7226 if (count == 0) {
7227 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7228 goto out;
7231 reply_outbuf(req, 1, 0);
7232 SSVAL(req->outbuf,smb_vwv0,count);
7233 out:
7234 TALLOC_FREE(smb_fname_src);
7235 TALLOC_FREE(smb_fname_dst);
7236 TALLOC_FREE(fname_src);
7237 TALLOC_FREE(fname_dst);
7238 TALLOC_FREE(fname_src_mask);
7239 TALLOC_FREE(fname_src_dir);
7241 END_PROFILE(SMBcopy);
7242 return;
7245 #undef DBGC_CLASS
7246 #define DBGC_CLASS DBGC_LOCKING
7248 /****************************************************************************
7249 Get a lock pid, dealing with large count requests.
7250 ****************************************************************************/
7252 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7253 bool large_file_format)
7255 if(!large_file_format)
7256 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7257 else
7258 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7261 /****************************************************************************
7262 Get a lock count, dealing with large count requests.
7263 ****************************************************************************/
7265 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7266 bool large_file_format)
7268 uint64_t count = 0;
7270 if(!large_file_format) {
7271 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7272 } else {
7274 #if defined(HAVE_LONGLONG)
7275 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7276 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7277 #else /* HAVE_LONGLONG */
7280 * NT4.x seems to be broken in that it sends large file (64 bit)
7281 * lockingX calls even if the CAP_LARGE_FILES was *not*
7282 * negotiated. For boxes without large unsigned ints truncate the
7283 * lock count by dropping the top 32 bits.
7286 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
7287 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
7288 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
7289 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
7290 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
7293 count = (uint64_t)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
7294 #endif /* HAVE_LONGLONG */
7297 return count;
7300 #if !defined(HAVE_LONGLONG)
7301 /****************************************************************************
7302 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
7303 ****************************************************************************/
7305 static uint32 map_lock_offset(uint32 high, uint32 low)
7307 unsigned int i;
7308 uint32 mask = 0;
7309 uint32 highcopy = high;
7312 * Try and find out how many significant bits there are in high.
7315 for(i = 0; highcopy; i++)
7316 highcopy >>= 1;
7319 * We use 31 bits not 32 here as POSIX
7320 * lock offsets may not be negative.
7323 mask = (~0) << (31 - i);
7325 if(low & mask)
7326 return 0; /* Fail. */
7328 high <<= (31 - i);
7330 return (high|low);
7332 #endif /* !defined(HAVE_LONGLONG) */
7334 /****************************************************************************
7335 Get a lock offset, dealing with large offset requests.
7336 ****************************************************************************/
7338 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7339 bool large_file_format, bool *err)
7341 uint64_t offset = 0;
7343 *err = False;
7345 if(!large_file_format) {
7346 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7347 } else {
7349 #if defined(HAVE_LONGLONG)
7350 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7351 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7352 #else /* HAVE_LONGLONG */
7355 * NT4.x seems to be broken in that it sends large file (64 bit)
7356 * lockingX calls even if the CAP_LARGE_FILES was *not*
7357 * negotiated. For boxes without large unsigned ints mangle the
7358 * lock offset by mapping the top 32 bits onto the lower 32.
7361 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
7362 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7363 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
7364 uint32 new_low = 0;
7366 if((new_low = map_lock_offset(high, low)) == 0) {
7367 *err = True;
7368 return (uint64_t)-1;
7371 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
7372 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
7373 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
7374 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
7377 offset = (uint64_t)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7378 #endif /* HAVE_LONGLONG */
7381 return offset;
7384 NTSTATUS smbd_do_locking(struct smb_request *req,
7385 files_struct *fsp,
7386 uint8_t type,
7387 int32_t timeout,
7388 uint16_t num_ulocks,
7389 struct smbd_lock_element *ulocks,
7390 uint16_t num_locks,
7391 struct smbd_lock_element *locks,
7392 bool *async)
7394 connection_struct *conn = req->conn;
7395 int i;
7396 NTSTATUS status = NT_STATUS_OK;
7398 *async = false;
7400 /* Data now points at the beginning of the list
7401 of smb_unlkrng structs */
7402 for(i = 0; i < (int)num_ulocks; i++) {
7403 struct smbd_lock_element *e = &ulocks[i];
7405 DEBUG(10,("smbd_do_locking: unlock start=%.0f, len=%.0f for "
7406 "pid %u, file %s\n",
7407 (double)e->offset,
7408 (double)e->count,
7409 (unsigned int)e->smblctx,
7410 fsp_str_dbg(fsp)));
7412 if (e->brltype != UNLOCK_LOCK) {
7413 /* this can only happen with SMB2 */
7414 return NT_STATUS_INVALID_PARAMETER;
7417 status = do_unlock(req->sconn->msg_ctx,
7418 fsp,
7419 e->smblctx,
7420 e->count,
7421 e->offset,
7422 WINDOWS_LOCK);
7424 DEBUG(10, ("smbd_do_locking: unlock returned %s\n",
7425 nt_errstr(status)));
7427 if (!NT_STATUS_IS_OK(status)) {
7428 return status;
7432 /* Setup the timeout in seconds. */
7434 if (!lp_blocking_locks(SNUM(conn))) {
7435 timeout = 0;
7438 /* Data now points at the beginning of the list
7439 of smb_lkrng structs */
7441 for(i = 0; i < (int)num_locks; i++) {
7442 struct smbd_lock_element *e = &locks[i];
7444 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
7445 "%llu, file %s timeout = %d\n",
7446 (double)e->offset,
7447 (double)e->count,
7448 (unsigned long long)e->smblctx,
7449 fsp_str_dbg(fsp),
7450 (int)timeout));
7452 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7453 struct blocking_lock_record *blr = NULL;
7455 if (num_locks > 1) {
7457 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
7458 * if the lock vector contains one entry. When given mutliple cancel
7459 * requests in a single PDU we expect the server to return an
7460 * error. Windows servers seem to accept the request but only
7461 * cancel the first lock.
7462 * JRA - Do what Windows does (tm) :-).
7465 #if 0
7466 /* MS-CIFS (2.2.4.32.1) behavior. */
7467 return NT_STATUS_DOS(ERRDOS,
7468 ERRcancelviolation);
7469 #else
7470 /* Windows behavior. */
7471 if (i != 0) {
7472 DEBUG(10,("smbd_do_locking: ignoring subsequent "
7473 "cancel request\n"));
7474 continue;
7476 #endif
7479 if (lp_blocking_locks(SNUM(conn))) {
7481 /* Schedule a message to ourselves to
7482 remove the blocking lock record and
7483 return the right error. */
7485 blr = blocking_lock_cancel_smb1(fsp,
7486 e->smblctx,
7487 e->offset,
7488 e->count,
7489 WINDOWS_LOCK,
7490 type,
7491 NT_STATUS_FILE_LOCK_CONFLICT);
7492 if (blr == NULL) {
7493 return NT_STATUS_DOS(
7494 ERRDOS,
7495 ERRcancelviolation);
7498 /* Remove a matching pending lock. */
7499 status = do_lock_cancel(fsp,
7500 e->smblctx,
7501 e->count,
7502 e->offset,
7503 WINDOWS_LOCK,
7504 blr);
7505 } else {
7506 bool blocking_lock = timeout ? true : false;
7507 bool defer_lock = false;
7508 struct byte_range_lock *br_lck;
7509 uint64_t block_smblctx;
7511 br_lck = do_lock(req->sconn->msg_ctx,
7512 fsp,
7513 e->smblctx,
7514 e->count,
7515 e->offset,
7516 e->brltype,
7517 WINDOWS_LOCK,
7518 blocking_lock,
7519 &status,
7520 &block_smblctx,
7521 NULL);
7523 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
7524 /* Windows internal resolution for blocking locks seems
7525 to be about 200ms... Don't wait for less than that. JRA. */
7526 if (timeout != -1 && timeout < lp_lock_spin_time()) {
7527 timeout = lp_lock_spin_time();
7529 defer_lock = true;
7532 /* If a lock sent with timeout of zero would fail, and
7533 * this lock has been requested multiple times,
7534 * according to brl_lock_failed() we convert this
7535 * request to a blocking lock with a timeout of between
7536 * 150 - 300 milliseconds.
7538 * If lp_lock_spin_time() has been set to 0, we skip
7539 * this blocking retry and fail immediately.
7541 * Replacement for do_lock_spin(). JRA. */
7543 if (!req->sconn->using_smb2 &&
7544 br_lck && lp_blocking_locks(SNUM(conn)) &&
7545 lp_lock_spin_time() && !blocking_lock &&
7546 NT_STATUS_EQUAL((status),
7547 NT_STATUS_FILE_LOCK_CONFLICT))
7549 defer_lock = true;
7550 timeout = lp_lock_spin_time();
7553 if (br_lck && defer_lock) {
7555 * A blocking lock was requested. Package up
7556 * this smb into a queued request and push it
7557 * onto the blocking lock queue.
7559 if(push_blocking_lock_request(br_lck,
7560 req,
7561 fsp,
7562 timeout,
7564 e->smblctx,
7565 e->brltype,
7566 WINDOWS_LOCK,
7567 e->offset,
7568 e->count,
7569 block_smblctx)) {
7570 TALLOC_FREE(br_lck);
7571 *async = true;
7572 return NT_STATUS_OK;
7576 TALLOC_FREE(br_lck);
7579 if (!NT_STATUS_IS_OK(status)) {
7580 break;
7584 /* If any of the above locks failed, then we must unlock
7585 all of the previous locks (X/Open spec). */
7587 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
7589 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7590 i = -1; /* we want to skip the for loop */
7594 * Ensure we don't do a remove on the lock that just failed,
7595 * as under POSIX rules, if we have a lock already there, we
7596 * will delete it (and we shouldn't) .....
7598 for(i--; i >= 0; i--) {
7599 struct smbd_lock_element *e = &locks[i];
7601 do_unlock(req->sconn->msg_ctx,
7602 fsp,
7603 e->smblctx,
7604 e->count,
7605 e->offset,
7606 WINDOWS_LOCK);
7608 return status;
7611 DEBUG(3, ("smbd_do_locking: fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
7612 fsp->fnum, (unsigned int)type, num_locks, num_ulocks));
7614 return NT_STATUS_OK;
7617 /****************************************************************************
7618 Reply to a lockingX request.
7619 ****************************************************************************/
7621 void reply_lockingX(struct smb_request *req)
7623 connection_struct *conn = req->conn;
7624 files_struct *fsp;
7625 unsigned char locktype;
7626 unsigned char oplocklevel;
7627 uint16 num_ulocks;
7628 uint16 num_locks;
7629 int32 lock_timeout;
7630 int i;
7631 const uint8_t *data;
7632 bool large_file_format;
7633 bool err;
7634 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
7635 struct smbd_lock_element *ulocks;
7636 struct smbd_lock_element *locks;
7637 bool async = false;
7639 START_PROFILE(SMBlockingX);
7641 if (req->wct < 8) {
7642 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7643 END_PROFILE(SMBlockingX);
7644 return;
7647 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
7648 locktype = CVAL(req->vwv+3, 0);
7649 oplocklevel = CVAL(req->vwv+3, 1);
7650 num_ulocks = SVAL(req->vwv+6, 0);
7651 num_locks = SVAL(req->vwv+7, 0);
7652 lock_timeout = IVAL(req->vwv+4, 0);
7653 large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
7655 if (!check_fsp(conn, req, fsp)) {
7656 END_PROFILE(SMBlockingX);
7657 return;
7660 data = req->buf;
7662 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
7663 /* we don't support these - and CANCEL_LOCK makes w2k
7664 and XP reboot so I don't really want to be
7665 compatible! (tridge) */
7666 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
7667 END_PROFILE(SMBlockingX);
7668 return;
7671 /* Check if this is an oplock break on a file
7672 we have granted an oplock on.
7674 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
7675 /* Client can insist on breaking to none. */
7676 bool break_to_none = (oplocklevel == 0);
7677 bool result;
7679 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
7680 "for fnum = %d\n", (unsigned int)oplocklevel,
7681 fsp->fnum ));
7684 * Make sure we have granted an exclusive or batch oplock on
7685 * this file.
7688 if (fsp->oplock_type == 0) {
7690 /* The Samba4 nbench simulator doesn't understand
7691 the difference between break to level2 and break
7692 to none from level2 - it sends oplock break
7693 replies in both cases. Don't keep logging an error
7694 message here - just ignore it. JRA. */
7696 DEBUG(5,("reply_lockingX: Error : oplock break from "
7697 "client for fnum = %d (oplock=%d) and no "
7698 "oplock granted on this file (%s).\n",
7699 fsp->fnum, fsp->oplock_type,
7700 fsp_str_dbg(fsp)));
7702 /* if this is a pure oplock break request then don't
7703 * send a reply */
7704 if (num_locks == 0 && num_ulocks == 0) {
7705 END_PROFILE(SMBlockingX);
7706 return;
7707 } else {
7708 END_PROFILE(SMBlockingX);
7709 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
7710 return;
7714 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
7715 (break_to_none)) {
7716 result = remove_oplock(fsp);
7717 } else {
7718 result = downgrade_oplock(fsp);
7721 if (!result) {
7722 DEBUG(0, ("reply_lockingX: error in removing "
7723 "oplock on file %s\n", fsp_str_dbg(fsp)));
7724 /* Hmmm. Is this panic justified? */
7725 smb_panic("internal tdb error");
7728 reply_to_oplock_break_requests(fsp);
7730 /* if this is a pure oplock break request then don't send a
7731 * reply */
7732 if (num_locks == 0 && num_ulocks == 0) {
7733 /* Sanity check - ensure a pure oplock break is not a
7734 chained request. */
7735 if(CVAL(req->vwv+0, 0) != 0xff)
7736 DEBUG(0,("reply_lockingX: Error : pure oplock "
7737 "break is a chained %d request !\n",
7738 (unsigned int)CVAL(req->vwv+0, 0)));
7739 END_PROFILE(SMBlockingX);
7740 return;
7744 if (req->buflen <
7745 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
7746 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7747 END_PROFILE(SMBlockingX);
7748 return;
7751 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
7752 if (ulocks == NULL) {
7753 reply_nterror(req, NT_STATUS_NO_MEMORY);
7754 END_PROFILE(SMBlockingX);
7755 return;
7758 locks = talloc_array(req, struct smbd_lock_element, num_locks);
7759 if (locks == NULL) {
7760 reply_nterror(req, NT_STATUS_NO_MEMORY);
7761 END_PROFILE(SMBlockingX);
7762 return;
7765 /* Data now points at the beginning of the list
7766 of smb_unlkrng structs */
7767 for(i = 0; i < (int)num_ulocks; i++) {
7768 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
7769 ulocks[i].count = get_lock_count(data, i, large_file_format);
7770 ulocks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7771 ulocks[i].brltype = UNLOCK_LOCK;
7774 * There is no error code marked "stupid client bug".... :-).
7776 if(err) {
7777 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7778 END_PROFILE(SMBlockingX);
7779 return;
7783 /* Now do any requested locks */
7784 data += ((large_file_format ? 20 : 10)*num_ulocks);
7786 /* Data now points at the beginning of the list
7787 of smb_lkrng structs */
7789 for(i = 0; i < (int)num_locks; i++) {
7790 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
7791 locks[i].count = get_lock_count(data, i, large_file_format);
7792 locks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7794 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
7795 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7796 locks[i].brltype = PENDING_READ_LOCK;
7797 } else {
7798 locks[i].brltype = READ_LOCK;
7800 } else {
7801 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7802 locks[i].brltype = PENDING_WRITE_LOCK;
7803 } else {
7804 locks[i].brltype = WRITE_LOCK;
7809 * There is no error code marked "stupid client bug".... :-).
7811 if(err) {
7812 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7813 END_PROFILE(SMBlockingX);
7814 return;
7818 status = smbd_do_locking(req, fsp,
7819 locktype, lock_timeout,
7820 num_ulocks, ulocks,
7821 num_locks, locks,
7822 &async);
7823 if (!NT_STATUS_IS_OK(status)) {
7824 END_PROFILE(SMBlockingX);
7825 reply_nterror(req, status);
7826 return;
7828 if (async) {
7829 END_PROFILE(SMBlockingX);
7830 return;
7833 reply_outbuf(req, 2, 0);
7835 DEBUG(3, ("lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
7836 fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks));
7838 END_PROFILE(SMBlockingX);
7839 chain_reply(req);
7842 #undef DBGC_CLASS
7843 #define DBGC_CLASS DBGC_ALL
7845 /****************************************************************************
7846 Reply to a SMBreadbmpx (read block multiplex) request.
7847 Always reply with an error, if someone has a platform really needs this,
7848 please contact vl@samba.org
7849 ****************************************************************************/
7851 void reply_readbmpx(struct smb_request *req)
7853 START_PROFILE(SMBreadBmpx);
7854 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7855 END_PROFILE(SMBreadBmpx);
7856 return;
7859 /****************************************************************************
7860 Reply to a SMBreadbs (read block multiplex secondary) request.
7861 Always reply with an error, if someone has a platform really needs this,
7862 please contact vl@samba.org
7863 ****************************************************************************/
7865 void reply_readbs(struct smb_request *req)
7867 START_PROFILE(SMBreadBs);
7868 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7869 END_PROFILE(SMBreadBs);
7870 return;
7873 /****************************************************************************
7874 Reply to a SMBsetattrE.
7875 ****************************************************************************/
7877 void reply_setattrE(struct smb_request *req)
7879 connection_struct *conn = req->conn;
7880 struct smb_file_time ft;
7881 files_struct *fsp;
7882 NTSTATUS status;
7884 START_PROFILE(SMBsetattrE);
7885 ZERO_STRUCT(ft);
7887 if (req->wct < 7) {
7888 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7889 goto out;
7892 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
7894 if(!fsp || (fsp->conn != conn)) {
7895 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
7896 goto out;
7900 * Convert the DOS times into unix times.
7903 ft.atime = convert_time_t_to_timespec(
7904 srv_make_unix_date2(req->vwv+3));
7905 ft.mtime = convert_time_t_to_timespec(
7906 srv_make_unix_date2(req->vwv+5));
7907 ft.create_time = convert_time_t_to_timespec(
7908 srv_make_unix_date2(req->vwv+1));
7910 reply_outbuf(req, 0, 0);
7913 * Patch from Ray Frush <frush@engr.colostate.edu>
7914 * Sometimes times are sent as zero - ignore them.
7917 /* Ensure we have a valid stat struct for the source. */
7918 status = vfs_stat_fsp(fsp);
7919 if (!NT_STATUS_IS_OK(status)) {
7920 reply_nterror(req, status);
7921 goto out;
7924 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
7925 if (!NT_STATUS_IS_OK(status)) {
7926 reply_nterror(req, status);
7927 goto out;
7930 DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u "
7931 " createtime=%u\n",
7932 fsp->fnum,
7933 (unsigned int)ft.atime.tv_sec,
7934 (unsigned int)ft.mtime.tv_sec,
7935 (unsigned int)ft.create_time.tv_sec
7937 out:
7938 END_PROFILE(SMBsetattrE);
7939 return;
7943 /* Back from the dead for OS/2..... JRA. */
7945 /****************************************************************************
7946 Reply to a SMBwritebmpx (write block multiplex primary) request.
7947 Always reply with an error, if someone has a platform really needs this,
7948 please contact vl@samba.org
7949 ****************************************************************************/
7951 void reply_writebmpx(struct smb_request *req)
7953 START_PROFILE(SMBwriteBmpx);
7954 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7955 END_PROFILE(SMBwriteBmpx);
7956 return;
7959 /****************************************************************************
7960 Reply to a SMBwritebs (write block multiplex secondary) request.
7961 Always reply with an error, if someone has a platform really needs this,
7962 please contact vl@samba.org
7963 ****************************************************************************/
7965 void reply_writebs(struct smb_request *req)
7967 START_PROFILE(SMBwriteBs);
7968 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7969 END_PROFILE(SMBwriteBs);
7970 return;
7973 /****************************************************************************
7974 Reply to a SMBgetattrE.
7975 ****************************************************************************/
7977 void reply_getattrE(struct smb_request *req)
7979 connection_struct *conn = req->conn;
7980 int mode;
7981 files_struct *fsp;
7982 struct timespec create_ts;
7984 START_PROFILE(SMBgetattrE);
7986 if (req->wct < 1) {
7987 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7988 END_PROFILE(SMBgetattrE);
7989 return;
7992 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
7994 if(!fsp || (fsp->conn != conn)) {
7995 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
7996 END_PROFILE(SMBgetattrE);
7997 return;
8000 /* Do an fstat on this file */
8001 if(fsp_stat(fsp)) {
8002 reply_nterror(req, map_nt_error_from_unix(errno));
8003 END_PROFILE(SMBgetattrE);
8004 return;
8007 mode = dos_mode(conn, fsp->fsp_name);
8010 * Convert the times into dos times. Set create
8011 * date to be last modify date as UNIX doesn't save
8012 * this.
8015 reply_outbuf(req, 11, 0);
8017 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
8018 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
8019 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
8020 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
8021 /* Should we check pending modtime here ? JRA */
8022 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
8023 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
8025 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
8026 SIVAL(req->outbuf, smb_vwv6, 0);
8027 SIVAL(req->outbuf, smb_vwv8, 0);
8028 } else {
8029 uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8030 SIVAL(req->outbuf, smb_vwv6, (uint32)fsp->fsp_name->st.st_ex_size);
8031 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8033 SSVAL(req->outbuf,smb_vwv10, mode);
8035 DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
8037 END_PROFILE(SMBgetattrE);
8038 return;