s3: reply_readbraw_error needs an sconn as argument also in the non-LFS code path
[Samba/gbeck.git] / source3 / smbd / reply.c
blob9c66ddee029b1af1aaa1120b11c86fc426e632f6
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 = CAN_WRITE(conn) ?
839 SHARE_ALL_ACCESS :
840 SHARE_READ_ONLY;
843 SIVAL(req->outbuf, smb_vwv3, perm1);
844 SIVAL(req->outbuf, smb_vwv5, perm2);
845 } else {
846 reply_outbuf(req, 3, 0);
849 if ((message_push_string(&req->outbuf, server_devicetype,
850 STR_TERMINATE|STR_ASCII) == -1)
851 || (message_push_string(&req->outbuf, fstype,
852 STR_TERMINATE) == -1)) {
853 reply_nterror(req, NT_STATUS_NO_MEMORY);
854 END_PROFILE(SMBtconX);
855 return;
858 /* what does setting this bit do? It is set by NT4 and
859 may affect the ability to autorun mounted cdroms */
860 SSVAL(req->outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS|
861 (lp_csc_policy(SNUM(conn)) << 2));
863 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
864 DEBUG(2,("Serving %s as a Dfs root\n",
865 lp_servicename(SNUM(conn)) ));
866 SSVAL(req->outbuf, smb_vwv2,
867 SMB_SHARE_IN_DFS | SVAL(req->outbuf, smb_vwv2));
872 DEBUG(3,("tconX service=%s \n",
873 service));
875 /* set the incoming and outgoing tid to the just created one */
876 SSVAL(req->inbuf,smb_tid,conn->cnum);
877 SSVAL(req->outbuf,smb_tid,conn->cnum);
879 END_PROFILE(SMBtconX);
881 req->tid = conn->cnum;
882 chain_reply(req);
883 return;
886 /****************************************************************************
887 Reply to an unknown type.
888 ****************************************************************************/
890 void reply_unknown_new(struct smb_request *req, uint8 type)
892 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
893 smb_fn_name(type), type, type));
894 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
895 return;
898 /****************************************************************************
899 Reply to an ioctl.
900 conn POINTER CAN BE NULL HERE !
901 ****************************************************************************/
903 void reply_ioctl(struct smb_request *req)
905 connection_struct *conn = req->conn;
906 uint16 device;
907 uint16 function;
908 uint32 ioctl_code;
909 int replysize;
910 char *p;
912 START_PROFILE(SMBioctl);
914 if (req->wct < 3) {
915 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
916 END_PROFILE(SMBioctl);
917 return;
920 device = SVAL(req->vwv+1, 0);
921 function = SVAL(req->vwv+2, 0);
922 ioctl_code = (device << 16) + function;
924 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
926 switch (ioctl_code) {
927 case IOCTL_QUERY_JOB_INFO:
928 replysize = 32;
929 break;
930 default:
931 reply_force_doserror(req, ERRSRV, ERRnosupport);
932 END_PROFILE(SMBioctl);
933 return;
936 reply_outbuf(req, 8, replysize+1);
937 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
938 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
939 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
940 p = smb_buf(req->outbuf);
941 memset(p, '\0', replysize+1); /* valgrind-safe. */
942 p += 1; /* Allow for alignment */
944 switch (ioctl_code) {
945 case IOCTL_QUERY_JOB_INFO:
947 files_struct *fsp = file_fsp(
948 req, SVAL(req->vwv+0, 0));
949 if (!fsp) {
950 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
951 END_PROFILE(SMBioctl);
952 return;
954 /* Job number */
955 if (fsp->print_file) {
956 SSVAL(p, 0, fsp->print_file->rap_jobid);
957 } else {
958 SSVAL(p, 0, 0);
960 srvstr_push((char *)req->outbuf, req->flags2, p+2,
961 global_myname(), 15,
962 STR_TERMINATE|STR_ASCII);
963 if (conn) {
964 srvstr_push((char *)req->outbuf, req->flags2,
965 p+18, lp_servicename(SNUM(conn)),
966 13, STR_TERMINATE|STR_ASCII);
967 } else {
968 memset(p+18, 0, 13);
970 break;
974 END_PROFILE(SMBioctl);
975 return;
978 /****************************************************************************
979 Strange checkpath NTSTATUS mapping.
980 ****************************************************************************/
982 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
984 /* Strange DOS error code semantics only for checkpath... */
985 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
986 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
987 /* We need to map to ERRbadpath */
988 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
991 return status;
994 /****************************************************************************
995 Reply to a checkpath.
996 ****************************************************************************/
998 void reply_checkpath(struct smb_request *req)
1000 connection_struct *conn = req->conn;
1001 struct smb_filename *smb_fname = NULL;
1002 char *name = NULL;
1003 NTSTATUS status;
1004 TALLOC_CTX *ctx = talloc_tos();
1006 START_PROFILE(SMBcheckpath);
1008 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
1009 STR_TERMINATE, &status);
1011 if (!NT_STATUS_IS_OK(status)) {
1012 status = map_checkpath_error(req->flags2, status);
1013 reply_nterror(req, status);
1014 END_PROFILE(SMBcheckpath);
1015 return;
1018 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1020 status = filename_convert(ctx,
1021 conn,
1022 req->flags2 & FLAGS2_DFS_PATHNAMES,
1023 name,
1025 NULL,
1026 &smb_fname);
1028 if (!NT_STATUS_IS_OK(status)) {
1029 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1030 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1031 ERRSRV, ERRbadpath);
1032 END_PROFILE(SMBcheckpath);
1033 return;
1035 goto path_err;
1038 if (!VALID_STAT(smb_fname->st) &&
1039 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1040 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1041 smb_fname_str_dbg(smb_fname), strerror(errno)));
1042 status = map_nt_error_from_unix(errno);
1043 goto path_err;
1046 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1047 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1048 ERRDOS, ERRbadpath);
1049 goto out;
1052 reply_outbuf(req, 0, 0);
1054 path_err:
1055 /* We special case this - as when a Windows machine
1056 is parsing a path is steps through the components
1057 one at a time - if a component fails it expects
1058 ERRbadpath, not ERRbadfile.
1060 status = map_checkpath_error(req->flags2, status);
1061 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1063 * Windows returns different error codes if
1064 * the parent directory is valid but not the
1065 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1066 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1067 * if the path is invalid.
1069 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1070 ERRDOS, ERRbadpath);
1071 goto out;
1074 reply_nterror(req, status);
1076 out:
1077 TALLOC_FREE(smb_fname);
1078 END_PROFILE(SMBcheckpath);
1079 return;
1082 /****************************************************************************
1083 Reply to a getatr.
1084 ****************************************************************************/
1086 void reply_getatr(struct smb_request *req)
1088 connection_struct *conn = req->conn;
1089 struct smb_filename *smb_fname = NULL;
1090 char *fname = NULL;
1091 int mode=0;
1092 SMB_OFF_T size=0;
1093 time_t mtime=0;
1094 const char *p;
1095 NTSTATUS status;
1096 TALLOC_CTX *ctx = talloc_tos();
1097 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1099 START_PROFILE(SMBgetatr);
1101 p = (const char *)req->buf + 1;
1102 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1103 if (!NT_STATUS_IS_OK(status)) {
1104 reply_nterror(req, status);
1105 goto out;
1108 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1109 under WfWg - weird! */
1110 if (*fname == '\0') {
1111 mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1112 if (!CAN_WRITE(conn)) {
1113 mode |= FILE_ATTRIBUTE_READONLY;
1115 size = 0;
1116 mtime = 0;
1117 } else {
1118 status = filename_convert(ctx,
1119 conn,
1120 req->flags2 & FLAGS2_DFS_PATHNAMES,
1121 fname,
1123 NULL,
1124 &smb_fname);
1125 if (!NT_STATUS_IS_OK(status)) {
1126 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1127 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1128 ERRSRV, ERRbadpath);
1129 goto out;
1131 reply_nterror(req, status);
1132 goto out;
1134 if (!VALID_STAT(smb_fname->st) &&
1135 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1136 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1137 smb_fname_str_dbg(smb_fname),
1138 strerror(errno)));
1139 reply_nterror(req, map_nt_error_from_unix(errno));
1140 goto out;
1143 mode = dos_mode(conn, smb_fname);
1144 size = smb_fname->st.st_ex_size;
1146 if (ask_sharemode) {
1147 struct timespec write_time_ts;
1148 struct file_id fileid;
1150 ZERO_STRUCT(write_time_ts);
1151 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1152 get_file_infos(fileid, 0, NULL, &write_time_ts);
1153 if (!null_timespec(write_time_ts)) {
1154 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1158 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1159 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1160 size = 0;
1164 reply_outbuf(req, 10, 0);
1166 SSVAL(req->outbuf,smb_vwv0,mode);
1167 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1168 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1169 } else {
1170 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1172 SIVAL(req->outbuf,smb_vwv3,(uint32)size);
1174 if (get_Protocol() >= PROTOCOL_NT1) {
1175 SSVAL(req->outbuf, smb_flg2,
1176 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1179 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1180 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1182 out:
1183 TALLOC_FREE(smb_fname);
1184 TALLOC_FREE(fname);
1185 END_PROFILE(SMBgetatr);
1186 return;
1189 /****************************************************************************
1190 Reply to a setatr.
1191 ****************************************************************************/
1193 void reply_setatr(struct smb_request *req)
1195 struct smb_file_time ft;
1196 connection_struct *conn = req->conn;
1197 struct smb_filename *smb_fname = NULL;
1198 char *fname = NULL;
1199 int mode;
1200 time_t mtime;
1201 const char *p;
1202 NTSTATUS status;
1203 TALLOC_CTX *ctx = talloc_tos();
1205 START_PROFILE(SMBsetatr);
1207 ZERO_STRUCT(ft);
1209 if (req->wct < 2) {
1210 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1211 goto out;
1214 p = (const char *)req->buf + 1;
1215 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1216 if (!NT_STATUS_IS_OK(status)) {
1217 reply_nterror(req, status);
1218 goto out;
1221 status = filename_convert(ctx,
1222 conn,
1223 req->flags2 & FLAGS2_DFS_PATHNAMES,
1224 fname,
1226 NULL,
1227 &smb_fname);
1228 if (!NT_STATUS_IS_OK(status)) {
1229 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1230 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1231 ERRSRV, ERRbadpath);
1232 goto out;
1234 reply_nterror(req, status);
1235 goto out;
1238 if (smb_fname->base_name[0] == '.' &&
1239 smb_fname->base_name[1] == '\0') {
1241 * Not sure here is the right place to catch this
1242 * condition. Might be moved to somewhere else later -- vl
1244 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1245 goto out;
1248 mode = SVAL(req->vwv+0, 0);
1249 mtime = srv_make_unix_date3(req->vwv+1);
1251 ft.mtime = convert_time_t_to_timespec(mtime);
1252 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1253 if (!NT_STATUS_IS_OK(status)) {
1254 reply_nterror(req, status);
1255 goto out;
1258 if (mode != FILE_ATTRIBUTE_NORMAL) {
1259 if (VALID_STAT_OF_DIR(smb_fname->st))
1260 mode |= FILE_ATTRIBUTE_DIRECTORY;
1261 else
1262 mode &= ~FILE_ATTRIBUTE_DIRECTORY;
1264 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1265 false) != 0) {
1266 reply_nterror(req, map_nt_error_from_unix(errno));
1267 goto out;
1271 reply_outbuf(req, 0, 0);
1273 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1274 mode));
1275 out:
1276 TALLOC_FREE(smb_fname);
1277 END_PROFILE(SMBsetatr);
1278 return;
1281 /****************************************************************************
1282 Reply to a dskattr.
1283 ****************************************************************************/
1285 void reply_dskattr(struct smb_request *req)
1287 connection_struct *conn = req->conn;
1288 uint64_t dfree,dsize,bsize;
1289 START_PROFILE(SMBdskattr);
1291 if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (uint64_t)-1) {
1292 reply_nterror(req, map_nt_error_from_unix(errno));
1293 END_PROFILE(SMBdskattr);
1294 return;
1297 reply_outbuf(req, 5, 0);
1299 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1300 double total_space, free_space;
1301 /* we need to scale this to a number that DOS6 can handle. We
1302 use floating point so we can handle large drives on systems
1303 that don't have 64 bit integers
1305 we end up displaying a maximum of 2G to DOS systems
1307 total_space = dsize * (double)bsize;
1308 free_space = dfree * (double)bsize;
1310 dsize = (uint64_t)((total_space+63*512) / (64*512));
1311 dfree = (uint64_t)((free_space+63*512) / (64*512));
1313 if (dsize > 0xFFFF) dsize = 0xFFFF;
1314 if (dfree > 0xFFFF) dfree = 0xFFFF;
1316 SSVAL(req->outbuf,smb_vwv0,dsize);
1317 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1318 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1319 SSVAL(req->outbuf,smb_vwv3,dfree);
1320 } else {
1321 SSVAL(req->outbuf,smb_vwv0,dsize);
1322 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1323 SSVAL(req->outbuf,smb_vwv2,512);
1324 SSVAL(req->outbuf,smb_vwv3,dfree);
1327 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1329 END_PROFILE(SMBdskattr);
1330 return;
1334 * Utility function to split the filename from the directory.
1336 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1337 char **fname_dir_out,
1338 char **fname_mask_out)
1340 const char *p = NULL;
1341 char *fname_dir = NULL;
1342 char *fname_mask = NULL;
1344 p = strrchr_m(fname_in, '/');
1345 if (!p) {
1346 fname_dir = talloc_strdup(ctx, ".");
1347 fname_mask = talloc_strdup(ctx, fname_in);
1348 } else {
1349 fname_dir = talloc_strndup(ctx, fname_in,
1350 PTR_DIFF(p, fname_in));
1351 fname_mask = talloc_strdup(ctx, p+1);
1354 if (!fname_dir || !fname_mask) {
1355 TALLOC_FREE(fname_dir);
1356 TALLOC_FREE(fname_mask);
1357 return NT_STATUS_NO_MEMORY;
1360 *fname_dir_out = fname_dir;
1361 *fname_mask_out = fname_mask;
1362 return NT_STATUS_OK;
1365 /****************************************************************************
1366 Reply to a search.
1367 Can be called from SMBsearch, SMBffirst or SMBfunique.
1368 ****************************************************************************/
1370 void reply_search(struct smb_request *req)
1372 connection_struct *conn = req->conn;
1373 char *path = NULL;
1374 const char *mask = NULL;
1375 char *directory = NULL;
1376 struct smb_filename *smb_fname = NULL;
1377 char *fname = NULL;
1378 SMB_OFF_T size;
1379 uint32 mode;
1380 struct timespec date;
1381 uint32 dirtype;
1382 unsigned int numentries = 0;
1383 unsigned int maxentries = 0;
1384 bool finished = False;
1385 const char *p;
1386 int status_len;
1387 char status[21];
1388 int dptr_num= -1;
1389 bool check_descend = False;
1390 bool expect_close = False;
1391 NTSTATUS nt_status;
1392 bool mask_contains_wcard = False;
1393 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1394 TALLOC_CTX *ctx = talloc_tos();
1395 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1396 struct dptr_struct *dirptr = NULL;
1397 struct smbd_server_connection *sconn = req->sconn;
1399 START_PROFILE(SMBsearch);
1401 if (req->wct < 2) {
1402 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1403 goto out;
1406 if (lp_posix_pathnames()) {
1407 reply_unknown_new(req, req->cmd);
1408 goto out;
1411 /* If we were called as SMBffirst then we must expect close. */
1412 if(req->cmd == SMBffirst) {
1413 expect_close = True;
1416 reply_outbuf(req, 1, 3);
1417 maxentries = SVAL(req->vwv+0, 0);
1418 dirtype = SVAL(req->vwv+1, 0);
1419 p = (const char *)req->buf + 1;
1420 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1421 &nt_status, &mask_contains_wcard);
1422 if (!NT_STATUS_IS_OK(nt_status)) {
1423 reply_nterror(req, nt_status);
1424 goto out;
1427 p++;
1428 status_len = SVAL(p, 0);
1429 p += 2;
1431 /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1433 if (status_len == 0) {
1434 nt_status = filename_convert(ctx, conn,
1435 req->flags2 & FLAGS2_DFS_PATHNAMES,
1436 path,
1437 UCF_ALWAYS_ALLOW_WCARD_LCOMP,
1438 &mask_contains_wcard,
1439 &smb_fname);
1440 if (!NT_STATUS_IS_OK(nt_status)) {
1441 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1442 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1443 ERRSRV, ERRbadpath);
1444 goto out;
1446 reply_nterror(req, nt_status);
1447 goto out;
1450 directory = smb_fname->base_name;
1452 p = strrchr_m(directory,'/');
1453 if ((p != NULL) && (*directory != '/')) {
1454 mask = p + 1;
1455 directory = talloc_strndup(ctx, directory,
1456 PTR_DIFF(p, directory));
1457 } else {
1458 mask = directory;
1459 directory = talloc_strdup(ctx,".");
1462 if (!directory) {
1463 reply_nterror(req, NT_STATUS_NO_MEMORY);
1464 goto out;
1467 memset((char *)status,'\0',21);
1468 SCVAL(status,0,(dirtype & 0x1F));
1470 nt_status = dptr_create(conn,
1471 NULL, /* fsp */
1472 directory,
1473 True,
1474 expect_close,
1475 req->smbpid,
1476 mask,
1477 mask_contains_wcard,
1478 dirtype,
1479 &dirptr);
1480 if (!NT_STATUS_IS_OK(nt_status)) {
1481 reply_nterror(req, nt_status);
1482 goto out;
1484 dptr_num = dptr_dnum(dirptr);
1485 } else {
1486 int status_dirtype;
1487 const char *dirpath;
1489 memcpy(status,p,21);
1490 status_dirtype = CVAL(status,0) & 0x1F;
1491 if (status_dirtype != (dirtype & 0x1F)) {
1492 dirtype = status_dirtype;
1495 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1496 if (!dirptr) {
1497 goto SearchEmpty;
1499 dirpath = dptr_path(sconn, dptr_num);
1500 directory = talloc_strdup(ctx, dirpath);
1501 if (!directory) {
1502 reply_nterror(req, NT_STATUS_NO_MEMORY);
1503 goto out;
1506 mask = dptr_wcard(sconn, dptr_num);
1507 if (!mask) {
1508 goto SearchEmpty;
1511 * For a 'continue' search we have no string. So
1512 * check from the initial saved string.
1514 mask_contains_wcard = ms_has_wild(mask);
1515 dirtype = dptr_attr(sconn, dptr_num);
1518 DEBUG(4,("dptr_num is %d\n",dptr_num));
1520 /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
1521 dptr_init_search_op(dirptr);
1523 if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1524 char buf[DIR_STRUCT_SIZE];
1525 memcpy(buf,status,21);
1526 if (!make_dir_struct(ctx,buf,"???????????",volume_label(SNUM(conn)),
1527 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1528 reply_nterror(req, NT_STATUS_NO_MEMORY);
1529 goto out;
1531 dptr_fill(sconn, buf+12,dptr_num);
1532 if (dptr_zero(buf+12) && (status_len==0)) {
1533 numentries = 1;
1534 } else {
1535 numentries = 0;
1537 if (message_push_blob(&req->outbuf,
1538 data_blob_const(buf, sizeof(buf)))
1539 == -1) {
1540 reply_nterror(req, NT_STATUS_NO_MEMORY);
1541 goto out;
1543 } else {
1544 unsigned int i;
1545 maxentries = MIN(
1546 maxentries,
1547 ((BUFFER_SIZE -
1548 ((uint8 *)smb_buf(req->outbuf) + 3 - req->outbuf))
1549 /DIR_STRUCT_SIZE));
1551 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1552 directory,lp_dontdescend(SNUM(conn))));
1553 if (in_list(directory, lp_dontdescend(SNUM(conn)),True)) {
1554 check_descend = True;
1557 for (i=numentries;(i<maxentries) && !finished;i++) {
1558 finished = !get_dir_entry(ctx,
1559 dirptr,
1560 mask,
1561 dirtype,
1562 &fname,
1563 &size,
1564 &mode,
1565 &date,
1566 check_descend,
1567 ask_sharemode);
1568 if (!finished) {
1569 char buf[DIR_STRUCT_SIZE];
1570 memcpy(buf,status,21);
1571 if (!make_dir_struct(ctx,
1572 buf,
1573 mask,
1574 fname,
1575 size,
1576 mode,
1577 convert_timespec_to_time_t(date),
1578 !allow_long_path_components)) {
1579 reply_nterror(req, NT_STATUS_NO_MEMORY);
1580 goto out;
1582 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1583 break;
1585 if (message_push_blob(&req->outbuf,
1586 data_blob_const(buf, sizeof(buf)))
1587 == -1) {
1588 reply_nterror(req, NT_STATUS_NO_MEMORY);
1589 goto out;
1591 numentries++;
1596 SearchEmpty:
1598 /* If we were called as SMBffirst with smb_search_id == NULL
1599 and no entries were found then return error and close dirptr
1600 (X/Open spec) */
1602 if (numentries == 0) {
1603 dptr_close(sconn, &dptr_num);
1604 } else if(expect_close && status_len == 0) {
1605 /* Close the dptr - we know it's gone */
1606 dptr_close(sconn, &dptr_num);
1609 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1610 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1611 dptr_close(sconn, &dptr_num);
1614 if ((numentries == 0) && !mask_contains_wcard) {
1615 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1616 goto out;
1619 SSVAL(req->outbuf,smb_vwv0,numentries);
1620 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1621 SCVAL(smb_buf(req->outbuf),0,5);
1622 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1624 /* The replies here are never long name. */
1625 SSVAL(req->outbuf, smb_flg2,
1626 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1627 if (!allow_long_path_components) {
1628 SSVAL(req->outbuf, smb_flg2,
1629 SVAL(req->outbuf, smb_flg2)
1630 & (~FLAGS2_LONG_PATH_COMPONENTS));
1633 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
1634 SSVAL(req->outbuf, smb_flg2,
1635 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
1637 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
1638 smb_fn_name(req->cmd),
1639 mask,
1640 directory,
1641 dirtype,
1642 numentries,
1643 maxentries ));
1644 out:
1645 TALLOC_FREE(directory);
1646 TALLOC_FREE(smb_fname);
1647 END_PROFILE(SMBsearch);
1648 return;
1651 /****************************************************************************
1652 Reply to a fclose (stop directory search).
1653 ****************************************************************************/
1655 void reply_fclose(struct smb_request *req)
1657 int status_len;
1658 char status[21];
1659 int dptr_num= -2;
1660 const char *p;
1661 char *path = NULL;
1662 NTSTATUS err;
1663 bool path_contains_wcard = False;
1664 TALLOC_CTX *ctx = talloc_tos();
1665 struct smbd_server_connection *sconn = req->sconn;
1667 START_PROFILE(SMBfclose);
1669 if (lp_posix_pathnames()) {
1670 reply_unknown_new(req, req->cmd);
1671 END_PROFILE(SMBfclose);
1672 return;
1675 p = (const char *)req->buf + 1;
1676 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1677 &err, &path_contains_wcard);
1678 if (!NT_STATUS_IS_OK(err)) {
1679 reply_nterror(req, err);
1680 END_PROFILE(SMBfclose);
1681 return;
1683 p++;
1684 status_len = SVAL(p,0);
1685 p += 2;
1687 if (status_len == 0) {
1688 reply_force_doserror(req, ERRSRV, ERRsrverror);
1689 END_PROFILE(SMBfclose);
1690 return;
1693 memcpy(status,p,21);
1695 if(dptr_fetch(sconn, status+12,&dptr_num)) {
1696 /* Close the dptr - we know it's gone */
1697 dptr_close(sconn, &dptr_num);
1700 reply_outbuf(req, 1, 0);
1701 SSVAL(req->outbuf,smb_vwv0,0);
1703 DEBUG(3,("search close\n"));
1705 END_PROFILE(SMBfclose);
1706 return;
1709 /****************************************************************************
1710 Reply to an open.
1711 ****************************************************************************/
1713 void reply_open(struct smb_request *req)
1715 connection_struct *conn = req->conn;
1716 struct smb_filename *smb_fname = NULL;
1717 char *fname = NULL;
1718 uint32 fattr=0;
1719 SMB_OFF_T size = 0;
1720 time_t mtime=0;
1721 int info;
1722 files_struct *fsp;
1723 int oplock_request;
1724 int deny_mode;
1725 uint32 dos_attr;
1726 uint32 access_mask;
1727 uint32 share_mode;
1728 uint32 create_disposition;
1729 uint32 create_options = 0;
1730 uint32_t private_flags = 0;
1731 NTSTATUS status;
1732 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1733 TALLOC_CTX *ctx = talloc_tos();
1735 START_PROFILE(SMBopen);
1737 if (req->wct < 2) {
1738 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1739 goto out;
1742 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1743 deny_mode = SVAL(req->vwv+0, 0);
1744 dos_attr = SVAL(req->vwv+1, 0);
1746 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
1747 STR_TERMINATE, &status);
1748 if (!NT_STATUS_IS_OK(status)) {
1749 reply_nterror(req, status);
1750 goto out;
1753 status = filename_convert(ctx,
1754 conn,
1755 req->flags2 & FLAGS2_DFS_PATHNAMES,
1756 fname,
1758 NULL,
1759 &smb_fname);
1760 if (!NT_STATUS_IS_OK(status)) {
1761 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1762 reply_botherror(req,
1763 NT_STATUS_PATH_NOT_COVERED,
1764 ERRSRV, ERRbadpath);
1765 goto out;
1767 reply_nterror(req, status);
1768 goto out;
1771 if (!map_open_params_to_ntcreate(smb_fname, deny_mode,
1772 OPENX_FILE_EXISTS_OPEN, &access_mask,
1773 &share_mode, &create_disposition,
1774 &create_options, &private_flags)) {
1775 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1776 goto out;
1779 status = SMB_VFS_CREATE_FILE(
1780 conn, /* conn */
1781 req, /* req */
1782 0, /* root_dir_fid */
1783 smb_fname, /* fname */
1784 access_mask, /* access_mask */
1785 share_mode, /* share_access */
1786 create_disposition, /* create_disposition*/
1787 create_options, /* create_options */
1788 dos_attr, /* file_attributes */
1789 oplock_request, /* oplock_request */
1790 0, /* allocation_size */
1791 private_flags,
1792 NULL, /* sd */
1793 NULL, /* ea_list */
1794 &fsp, /* result */
1795 &info); /* pinfo */
1797 if (!NT_STATUS_IS_OK(status)) {
1798 if (open_was_deferred(req->mid)) {
1799 /* We have re-scheduled this call. */
1800 goto out;
1802 reply_openerror(req, status);
1803 goto out;
1806 size = smb_fname->st.st_ex_size;
1807 fattr = dos_mode(conn, smb_fname);
1809 /* Deal with other possible opens having a modified
1810 write time. JRA. */
1811 if (ask_sharemode) {
1812 struct timespec write_time_ts;
1814 ZERO_STRUCT(write_time_ts);
1815 get_file_infos(fsp->file_id, 0, NULL, &write_time_ts);
1816 if (!null_timespec(write_time_ts)) {
1817 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1821 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1823 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
1824 DEBUG(3,("attempt to open a directory %s\n",
1825 fsp_str_dbg(fsp)));
1826 close_file(req, fsp, ERROR_CLOSE);
1827 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
1828 ERRDOS, ERRnoaccess);
1829 goto out;
1832 reply_outbuf(req, 7, 0);
1833 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
1834 SSVAL(req->outbuf,smb_vwv1,fattr);
1835 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1836 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
1837 } else {
1838 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
1840 SIVAL(req->outbuf,smb_vwv4,(uint32)size);
1841 SSVAL(req->outbuf,smb_vwv6,deny_mode);
1843 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1844 SCVAL(req->outbuf,smb_flg,
1845 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1848 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1849 SCVAL(req->outbuf,smb_flg,
1850 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1852 out:
1853 TALLOC_FREE(smb_fname);
1854 END_PROFILE(SMBopen);
1855 return;
1858 /****************************************************************************
1859 Reply to an open and X.
1860 ****************************************************************************/
1862 void reply_open_and_X(struct smb_request *req)
1864 connection_struct *conn = req->conn;
1865 struct smb_filename *smb_fname = NULL;
1866 char *fname = NULL;
1867 uint16 open_flags;
1868 int deny_mode;
1869 uint32 smb_attr;
1870 /* Breakout the oplock request bits so we can set the
1871 reply bits separately. */
1872 int ex_oplock_request;
1873 int core_oplock_request;
1874 int oplock_request;
1875 #if 0
1876 int smb_sattr = SVAL(req->vwv+4, 0);
1877 uint32 smb_time = make_unix_date3(req->vwv+6);
1878 #endif
1879 int smb_ofun;
1880 uint32 fattr=0;
1881 int mtime=0;
1882 int smb_action = 0;
1883 files_struct *fsp;
1884 NTSTATUS status;
1885 uint64_t allocation_size;
1886 ssize_t retval = -1;
1887 uint32 access_mask;
1888 uint32 share_mode;
1889 uint32 create_disposition;
1890 uint32 create_options = 0;
1891 uint32_t private_flags = 0;
1892 TALLOC_CTX *ctx = talloc_tos();
1894 START_PROFILE(SMBopenX);
1896 if (req->wct < 15) {
1897 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1898 goto out;
1901 open_flags = SVAL(req->vwv+2, 0);
1902 deny_mode = SVAL(req->vwv+3, 0);
1903 smb_attr = SVAL(req->vwv+5, 0);
1904 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
1905 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1906 oplock_request = ex_oplock_request | core_oplock_request;
1907 smb_ofun = SVAL(req->vwv+8, 0);
1908 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
1910 /* If it's an IPC, pass off the pipe handler. */
1911 if (IS_IPC(conn)) {
1912 if (lp_nt_pipe_support()) {
1913 reply_open_pipe_and_X(conn, req);
1914 } else {
1915 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
1917 goto out;
1920 /* XXXX we need to handle passed times, sattr and flags */
1921 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
1922 STR_TERMINATE, &status);
1923 if (!NT_STATUS_IS_OK(status)) {
1924 reply_nterror(req, status);
1925 goto out;
1928 status = filename_convert(ctx,
1929 conn,
1930 req->flags2 & FLAGS2_DFS_PATHNAMES,
1931 fname,
1933 NULL,
1934 &smb_fname);
1935 if (!NT_STATUS_IS_OK(status)) {
1936 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1937 reply_botherror(req,
1938 NT_STATUS_PATH_NOT_COVERED,
1939 ERRSRV, ERRbadpath);
1940 goto out;
1942 reply_nterror(req, status);
1943 goto out;
1946 if (!map_open_params_to_ntcreate(smb_fname, deny_mode, smb_ofun,
1947 &access_mask, &share_mode,
1948 &create_disposition,
1949 &create_options,
1950 &private_flags)) {
1951 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1952 goto out;
1955 status = SMB_VFS_CREATE_FILE(
1956 conn, /* conn */
1957 req, /* req */
1958 0, /* root_dir_fid */
1959 smb_fname, /* fname */
1960 access_mask, /* access_mask */
1961 share_mode, /* share_access */
1962 create_disposition, /* create_disposition*/
1963 create_options, /* create_options */
1964 smb_attr, /* file_attributes */
1965 oplock_request, /* oplock_request */
1966 0, /* allocation_size */
1967 private_flags,
1968 NULL, /* sd */
1969 NULL, /* ea_list */
1970 &fsp, /* result */
1971 &smb_action); /* pinfo */
1973 if (!NT_STATUS_IS_OK(status)) {
1974 if (open_was_deferred(req->mid)) {
1975 /* We have re-scheduled this call. */
1976 goto out;
1978 reply_openerror(req, status);
1979 goto out;
1982 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
1983 if the file is truncated or created. */
1984 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
1985 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
1986 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
1987 close_file(req, fsp, ERROR_CLOSE);
1988 reply_nterror(req, NT_STATUS_DISK_FULL);
1989 goto out;
1991 retval = vfs_set_filelen(fsp, (SMB_OFF_T)allocation_size);
1992 if (retval < 0) {
1993 close_file(req, fsp, ERROR_CLOSE);
1994 reply_nterror(req, NT_STATUS_DISK_FULL);
1995 goto out;
1997 status = vfs_stat_fsp(fsp);
1998 if (!NT_STATUS_IS_OK(status)) {
1999 close_file(req, fsp, ERROR_CLOSE);
2000 reply_nterror(req, status);
2001 goto out;
2005 fattr = dos_mode(conn, fsp->fsp_name);
2006 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2007 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2008 close_file(req, fsp, ERROR_CLOSE);
2009 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2010 goto out;
2013 /* If the caller set the extended oplock request bit
2014 and we granted one (by whatever means) - set the
2015 correct bit for extended oplock reply.
2018 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2019 smb_action |= EXTENDED_OPLOCK_GRANTED;
2022 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2023 smb_action |= EXTENDED_OPLOCK_GRANTED;
2026 /* If the caller set the core oplock request bit
2027 and we granted one (by whatever means) - set the
2028 correct bit for core oplock reply.
2031 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2032 reply_outbuf(req, 19, 0);
2033 } else {
2034 reply_outbuf(req, 15, 0);
2037 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2038 SCVAL(req->outbuf, smb_flg,
2039 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2042 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2043 SCVAL(req->outbuf, smb_flg,
2044 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2047 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2048 SSVAL(req->outbuf,smb_vwv3,fattr);
2049 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2050 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2051 } else {
2052 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2054 SIVAL(req->outbuf,smb_vwv6,(uint32)fsp->fsp_name->st.st_ex_size);
2055 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2056 SSVAL(req->outbuf,smb_vwv11,smb_action);
2058 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2059 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2062 chain_reply(req);
2063 out:
2064 TALLOC_FREE(smb_fname);
2065 END_PROFILE(SMBopenX);
2066 return;
2069 /****************************************************************************
2070 Reply to a SMBulogoffX.
2071 ****************************************************************************/
2073 void reply_ulogoffX(struct smb_request *req)
2075 struct smbd_server_connection *sconn = req->sconn;
2076 user_struct *vuser;
2078 START_PROFILE(SMBulogoffX);
2080 vuser = get_valid_user_struct(sconn, req->vuid);
2082 if(vuser == NULL) {
2083 DEBUG(3,("ulogoff, vuser id %d does not map to user.\n",
2084 req->vuid));
2087 /* in user level security we are supposed to close any files
2088 open by this user */
2089 if ((vuser != NULL) && (lp_security() != SEC_SHARE)) {
2090 file_close_user(sconn, req->vuid);
2093 invalidate_vuid(sconn, req->vuid);
2095 reply_outbuf(req, 2, 0);
2097 DEBUG( 3, ( "ulogoffX vuid=%d\n", req->vuid ) );
2099 END_PROFILE(SMBulogoffX);
2100 req->vuid = UID_FIELD_INVALID;
2101 chain_reply(req);
2104 /****************************************************************************
2105 Reply to a mknew or a create.
2106 ****************************************************************************/
2108 void reply_mknew(struct smb_request *req)
2110 connection_struct *conn = req->conn;
2111 struct smb_filename *smb_fname = NULL;
2112 char *fname = NULL;
2113 uint32 fattr = 0;
2114 struct smb_file_time ft;
2115 files_struct *fsp;
2116 int oplock_request = 0;
2117 NTSTATUS status;
2118 uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2119 uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2120 uint32 create_disposition;
2121 uint32 create_options = 0;
2122 TALLOC_CTX *ctx = talloc_tos();
2124 START_PROFILE(SMBcreate);
2125 ZERO_STRUCT(ft);
2127 if (req->wct < 3) {
2128 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2129 goto out;
2132 fattr = SVAL(req->vwv+0, 0);
2133 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2135 /* mtime. */
2136 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2138 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2139 STR_TERMINATE, &status);
2140 if (!NT_STATUS_IS_OK(status)) {
2141 reply_nterror(req, status);
2142 goto out;
2145 status = filename_convert(ctx,
2146 conn,
2147 req->flags2 & FLAGS2_DFS_PATHNAMES,
2148 fname,
2150 NULL,
2151 &smb_fname);
2152 if (!NT_STATUS_IS_OK(status)) {
2153 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2154 reply_botherror(req,
2155 NT_STATUS_PATH_NOT_COVERED,
2156 ERRSRV, ERRbadpath);
2157 goto out;
2159 reply_nterror(req, status);
2160 goto out;
2163 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2164 DEBUG(0,("Attempt to create file (%s) with volid set - "
2165 "please report this\n",
2166 smb_fname_str_dbg(smb_fname)));
2169 if(req->cmd == SMBmknew) {
2170 /* We should fail if file exists. */
2171 create_disposition = FILE_CREATE;
2172 } else {
2173 /* Create if file doesn't exist, truncate if it does. */
2174 create_disposition = FILE_OVERWRITE_IF;
2177 status = SMB_VFS_CREATE_FILE(
2178 conn, /* conn */
2179 req, /* req */
2180 0, /* root_dir_fid */
2181 smb_fname, /* fname */
2182 access_mask, /* access_mask */
2183 share_mode, /* share_access */
2184 create_disposition, /* create_disposition*/
2185 create_options, /* create_options */
2186 fattr, /* file_attributes */
2187 oplock_request, /* oplock_request */
2188 0, /* allocation_size */
2189 0, /* private_flags */
2190 NULL, /* sd */
2191 NULL, /* ea_list */
2192 &fsp, /* result */
2193 NULL); /* pinfo */
2195 if (!NT_STATUS_IS_OK(status)) {
2196 if (open_was_deferred(req->mid)) {
2197 /* We have re-scheduled this call. */
2198 goto out;
2200 reply_openerror(req, status);
2201 goto out;
2204 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2205 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2206 if (!NT_STATUS_IS_OK(status)) {
2207 END_PROFILE(SMBcreate);
2208 goto out;
2211 reply_outbuf(req, 1, 0);
2212 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2214 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2215 SCVAL(req->outbuf,smb_flg,
2216 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2219 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2220 SCVAL(req->outbuf,smb_flg,
2221 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2224 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2225 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2226 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2227 (unsigned int)fattr));
2229 out:
2230 TALLOC_FREE(smb_fname);
2231 END_PROFILE(SMBcreate);
2232 return;
2235 /****************************************************************************
2236 Reply to a create temporary file.
2237 ****************************************************************************/
2239 void reply_ctemp(struct smb_request *req)
2241 connection_struct *conn = req->conn;
2242 struct smb_filename *smb_fname = NULL;
2243 char *fname = NULL;
2244 uint32 fattr;
2245 files_struct *fsp;
2246 int oplock_request;
2247 int tmpfd;
2248 char *s;
2249 NTSTATUS status;
2250 TALLOC_CTX *ctx = talloc_tos();
2252 START_PROFILE(SMBctemp);
2254 if (req->wct < 3) {
2255 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2256 goto out;
2259 fattr = SVAL(req->vwv+0, 0);
2260 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2262 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
2263 STR_TERMINATE, &status);
2264 if (!NT_STATUS_IS_OK(status)) {
2265 reply_nterror(req, status);
2266 goto out;
2268 if (*fname) {
2269 fname = talloc_asprintf(ctx,
2270 "%s/TMXXXXXX",
2271 fname);
2272 } else {
2273 fname = talloc_strdup(ctx, "TMXXXXXX");
2276 if (!fname) {
2277 reply_nterror(req, NT_STATUS_NO_MEMORY);
2278 goto out;
2281 status = filename_convert(ctx, conn,
2282 req->flags2 & FLAGS2_DFS_PATHNAMES,
2283 fname,
2285 NULL,
2286 &smb_fname);
2287 if (!NT_STATUS_IS_OK(status)) {
2288 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2289 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2290 ERRSRV, ERRbadpath);
2291 goto out;
2293 reply_nterror(req, status);
2294 goto out;
2297 tmpfd = mkstemp(smb_fname->base_name);
2298 if (tmpfd == -1) {
2299 reply_nterror(req, map_nt_error_from_unix(errno));
2300 goto out;
2303 SMB_VFS_STAT(conn, smb_fname);
2305 /* We should fail if file does not exist. */
2306 status = SMB_VFS_CREATE_FILE(
2307 conn, /* conn */
2308 req, /* req */
2309 0, /* root_dir_fid */
2310 smb_fname, /* fname */
2311 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2312 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2313 FILE_OPEN, /* create_disposition*/
2314 0, /* create_options */
2315 fattr, /* file_attributes */
2316 oplock_request, /* oplock_request */
2317 0, /* allocation_size */
2318 0, /* private_flags */
2319 NULL, /* sd */
2320 NULL, /* ea_list */
2321 &fsp, /* result */
2322 NULL); /* pinfo */
2324 /* close fd from mkstemp() */
2325 close(tmpfd);
2327 if (!NT_STATUS_IS_OK(status)) {
2328 if (open_was_deferred(req->mid)) {
2329 /* We have re-scheduled this call. */
2330 goto out;
2332 reply_openerror(req, status);
2333 goto out;
2336 reply_outbuf(req, 1, 0);
2337 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2339 /* the returned filename is relative to the directory */
2340 s = strrchr_m(fsp->fsp_name->base_name, '/');
2341 if (!s) {
2342 s = fsp->fsp_name->base_name;
2343 } else {
2344 s++;
2347 #if 0
2348 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2349 thing in the byte section. JRA */
2350 SSVALS(p, 0, -1); /* what is this? not in spec */
2351 #endif
2352 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2353 == -1) {
2354 reply_nterror(req, NT_STATUS_NO_MEMORY);
2355 goto out;
2358 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2359 SCVAL(req->outbuf, smb_flg,
2360 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2363 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2364 SCVAL(req->outbuf, smb_flg,
2365 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2368 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2369 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2370 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2371 out:
2372 TALLOC_FREE(smb_fname);
2373 END_PROFILE(SMBctemp);
2374 return;
2377 /*******************************************************************
2378 Check if a user is allowed to rename a file.
2379 ********************************************************************/
2381 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2382 uint16 dirtype)
2384 uint32 fmode;
2386 if (!CAN_WRITE(conn)) {
2387 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2390 fmode = dos_mode(conn, fsp->fsp_name);
2391 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2392 return NT_STATUS_NO_SUCH_FILE;
2395 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2396 if (fsp->posix_open) {
2397 return NT_STATUS_OK;
2400 /* If no pathnames are open below this
2401 directory, allow the rename. */
2403 if (file_find_subpath(fsp)) {
2404 return NT_STATUS_ACCESS_DENIED;
2406 return NT_STATUS_OK;
2409 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2410 return NT_STATUS_OK;
2413 return NT_STATUS_ACCESS_DENIED;
2416 /*******************************************************************
2417 * unlink a file with all relevant access checks
2418 *******************************************************************/
2420 static NTSTATUS do_unlink(connection_struct *conn,
2421 struct smb_request *req,
2422 struct smb_filename *smb_fname,
2423 uint32 dirtype)
2425 uint32 fattr;
2426 files_struct *fsp;
2427 uint32 dirtype_orig = dirtype;
2428 NTSTATUS status;
2429 int ret;
2430 bool posix_paths = lp_posix_pathnames();
2432 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2433 smb_fname_str_dbg(smb_fname),
2434 dirtype));
2436 if (!CAN_WRITE(conn)) {
2437 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2440 if (posix_paths) {
2441 ret = SMB_VFS_LSTAT(conn, smb_fname);
2442 } else {
2443 ret = SMB_VFS_STAT(conn, smb_fname);
2445 if (ret != 0) {
2446 return map_nt_error_from_unix(errno);
2449 fattr = dos_mode(conn, smb_fname);
2451 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2452 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
2455 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
2456 if (!dirtype) {
2457 return NT_STATUS_NO_SUCH_FILE;
2460 if (!dir_check_ftype(conn, fattr, dirtype)) {
2461 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2462 return NT_STATUS_FILE_IS_A_DIRECTORY;
2464 return NT_STATUS_NO_SUCH_FILE;
2467 if (dirtype_orig & 0x8000) {
2468 /* These will never be set for POSIX. */
2469 return NT_STATUS_NO_SUCH_FILE;
2472 #if 0
2473 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2474 return NT_STATUS_FILE_IS_A_DIRECTORY;
2477 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2478 return NT_STATUS_NO_SUCH_FILE;
2481 if (dirtype & 0xFF00) {
2482 /* These will never be set for POSIX. */
2483 return NT_STATUS_NO_SUCH_FILE;
2486 dirtype &= 0xFF;
2487 if (!dirtype) {
2488 return NT_STATUS_NO_SUCH_FILE;
2491 /* Can't delete a directory. */
2492 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2493 return NT_STATUS_FILE_IS_A_DIRECTORY;
2495 #endif
2497 #if 0 /* JRATEST */
2498 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
2499 return NT_STATUS_OBJECT_NAME_INVALID;
2500 #endif /* JRATEST */
2502 /* On open checks the open itself will check the share mode, so
2503 don't do it here as we'll get it wrong. */
2505 status = SMB_VFS_CREATE_FILE
2506 (conn, /* conn */
2507 req, /* req */
2508 0, /* root_dir_fid */
2509 smb_fname, /* fname */
2510 DELETE_ACCESS, /* access_mask */
2511 FILE_SHARE_NONE, /* share_access */
2512 FILE_OPEN, /* create_disposition*/
2513 FILE_NON_DIRECTORY_FILE, /* create_options */
2514 /* file_attributes */
2515 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2516 FILE_ATTRIBUTE_NORMAL,
2517 0, /* oplock_request */
2518 0, /* allocation_size */
2519 0, /* private_flags */
2520 NULL, /* sd */
2521 NULL, /* ea_list */
2522 &fsp, /* result */
2523 NULL); /* pinfo */
2525 if (!NT_STATUS_IS_OK(status)) {
2526 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2527 nt_errstr(status)));
2528 return status;
2531 status = can_set_delete_on_close(fsp, fattr);
2532 if (!NT_STATUS_IS_OK(status)) {
2533 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2534 "(%s)\n",
2535 smb_fname_str_dbg(smb_fname),
2536 nt_errstr(status)));
2537 close_file(req, fsp, NORMAL_CLOSE);
2538 return status;
2541 /* The set is across all open files on this dev/inode pair. */
2542 if (!set_delete_on_close(fsp, True, &conn->session_info->utok)) {
2543 close_file(req, fsp, NORMAL_CLOSE);
2544 return NT_STATUS_ACCESS_DENIED;
2547 return close_file(req, fsp, NORMAL_CLOSE);
2550 /****************************************************************************
2551 The guts of the unlink command, split out so it may be called by the NT SMB
2552 code.
2553 ****************************************************************************/
2555 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2556 uint32 dirtype, struct smb_filename *smb_fname,
2557 bool has_wild)
2559 char *fname_dir = NULL;
2560 char *fname_mask = NULL;
2561 int count=0;
2562 NTSTATUS status = NT_STATUS_OK;
2563 TALLOC_CTX *ctx = talloc_tos();
2565 /* Split up the directory from the filename/mask. */
2566 status = split_fname_dir_mask(ctx, smb_fname->base_name,
2567 &fname_dir, &fname_mask);
2568 if (!NT_STATUS_IS_OK(status)) {
2569 goto out;
2573 * We should only check the mangled cache
2574 * here if unix_convert failed. This means
2575 * that the path in 'mask' doesn't exist
2576 * on the file system and so we need to look
2577 * for a possible mangle. This patch from
2578 * Tine Smukavec <valentin.smukavec@hermes.si>.
2581 if (!VALID_STAT(smb_fname->st) &&
2582 mangle_is_mangled(fname_mask, conn->params)) {
2583 char *new_mask = NULL;
2584 mangle_lookup_name_from_8_3(ctx, fname_mask,
2585 &new_mask, conn->params);
2586 if (new_mask) {
2587 TALLOC_FREE(fname_mask);
2588 fname_mask = new_mask;
2592 if (!has_wild) {
2595 * Only one file needs to be unlinked. Append the mask back
2596 * onto the directory.
2598 TALLOC_FREE(smb_fname->base_name);
2599 if (ISDOT(fname_dir)) {
2600 /* Ensure we use canonical names on open. */
2601 smb_fname->base_name = talloc_asprintf(smb_fname,
2602 "%s",
2603 fname_mask);
2604 } else {
2605 smb_fname->base_name = talloc_asprintf(smb_fname,
2606 "%s/%s",
2607 fname_dir,
2608 fname_mask);
2610 if (!smb_fname->base_name) {
2611 status = NT_STATUS_NO_MEMORY;
2612 goto out;
2614 if (dirtype == 0) {
2615 dirtype = FILE_ATTRIBUTE_NORMAL;
2618 status = check_name(conn, smb_fname->base_name);
2619 if (!NT_STATUS_IS_OK(status)) {
2620 goto out;
2623 status = do_unlink(conn, req, smb_fname, dirtype);
2624 if (!NT_STATUS_IS_OK(status)) {
2625 goto out;
2628 count++;
2629 } else {
2630 struct smb_Dir *dir_hnd = NULL;
2631 long offset = 0;
2632 const char *dname = NULL;
2633 char *talloced = NULL;
2635 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
2636 status = NT_STATUS_OBJECT_NAME_INVALID;
2637 goto out;
2640 if (strequal(fname_mask,"????????.???")) {
2641 TALLOC_FREE(fname_mask);
2642 fname_mask = talloc_strdup(ctx, "*");
2643 if (!fname_mask) {
2644 status = NT_STATUS_NO_MEMORY;
2645 goto out;
2649 status = check_name(conn, fname_dir);
2650 if (!NT_STATUS_IS_OK(status)) {
2651 goto out;
2654 dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask,
2655 dirtype);
2656 if (dir_hnd == NULL) {
2657 status = map_nt_error_from_unix(errno);
2658 goto out;
2661 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2662 the pattern matches against the long name, otherwise the short name
2663 We don't implement this yet XXXX
2666 status = NT_STATUS_NO_SUCH_FILE;
2668 while ((dname = ReadDirName(dir_hnd, &offset,
2669 &smb_fname->st, &talloced))) {
2670 TALLOC_CTX *frame = talloc_stackframe();
2672 if (!is_visible_file(conn, fname_dir, dname,
2673 &smb_fname->st, true)) {
2674 TALLOC_FREE(frame);
2675 TALLOC_FREE(talloced);
2676 continue;
2679 /* Quick check for "." and ".." */
2680 if (ISDOT(dname) || ISDOTDOT(dname)) {
2681 TALLOC_FREE(frame);
2682 TALLOC_FREE(talloced);
2683 continue;
2686 if(!mask_match(dname, fname_mask,
2687 conn->case_sensitive)) {
2688 TALLOC_FREE(frame);
2689 TALLOC_FREE(talloced);
2690 continue;
2693 TALLOC_FREE(smb_fname->base_name);
2694 if (ISDOT(fname_dir)) {
2695 /* Ensure we use canonical names on open. */
2696 smb_fname->base_name =
2697 talloc_asprintf(smb_fname, "%s",
2698 dname);
2699 } else {
2700 smb_fname->base_name =
2701 talloc_asprintf(smb_fname, "%s/%s",
2702 fname_dir, dname);
2705 if (!smb_fname->base_name) {
2706 TALLOC_FREE(dir_hnd);
2707 status = NT_STATUS_NO_MEMORY;
2708 TALLOC_FREE(frame);
2709 TALLOC_FREE(talloced);
2710 goto out;
2713 status = check_name(conn, smb_fname->base_name);
2714 if (!NT_STATUS_IS_OK(status)) {
2715 TALLOC_FREE(dir_hnd);
2716 TALLOC_FREE(frame);
2717 TALLOC_FREE(talloced);
2718 goto out;
2721 status = do_unlink(conn, req, smb_fname, dirtype);
2722 if (!NT_STATUS_IS_OK(status)) {
2723 TALLOC_FREE(frame);
2724 TALLOC_FREE(talloced);
2725 continue;
2728 count++;
2729 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
2730 smb_fname->base_name));
2732 TALLOC_FREE(frame);
2733 TALLOC_FREE(talloced);
2735 TALLOC_FREE(dir_hnd);
2738 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
2739 status = map_nt_error_from_unix(errno);
2742 out:
2743 TALLOC_FREE(fname_dir);
2744 TALLOC_FREE(fname_mask);
2745 return status;
2748 /****************************************************************************
2749 Reply to a unlink
2750 ****************************************************************************/
2752 void reply_unlink(struct smb_request *req)
2754 connection_struct *conn = req->conn;
2755 char *name = NULL;
2756 struct smb_filename *smb_fname = NULL;
2757 uint32 dirtype;
2758 NTSTATUS status;
2759 bool path_contains_wcard = False;
2760 TALLOC_CTX *ctx = talloc_tos();
2762 START_PROFILE(SMBunlink);
2764 if (req->wct < 1) {
2765 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2766 goto out;
2769 dirtype = SVAL(req->vwv+0, 0);
2771 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
2772 STR_TERMINATE, &status,
2773 &path_contains_wcard);
2774 if (!NT_STATUS_IS_OK(status)) {
2775 reply_nterror(req, status);
2776 goto out;
2779 status = filename_convert(ctx, conn,
2780 req->flags2 & FLAGS2_DFS_PATHNAMES,
2781 name,
2782 UCF_COND_ALLOW_WCARD_LCOMP,
2783 &path_contains_wcard,
2784 &smb_fname);
2785 if (!NT_STATUS_IS_OK(status)) {
2786 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2787 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2788 ERRSRV, ERRbadpath);
2789 goto out;
2791 reply_nterror(req, status);
2792 goto out;
2795 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
2797 status = unlink_internals(conn, req, dirtype, smb_fname,
2798 path_contains_wcard);
2799 if (!NT_STATUS_IS_OK(status)) {
2800 if (open_was_deferred(req->mid)) {
2801 /* We have re-scheduled this call. */
2802 goto out;
2804 reply_nterror(req, status);
2805 goto out;
2808 reply_outbuf(req, 0, 0);
2809 out:
2810 TALLOC_FREE(smb_fname);
2811 END_PROFILE(SMBunlink);
2812 return;
2815 /****************************************************************************
2816 Fail for readbraw.
2817 ****************************************************************************/
2819 static void fail_readraw(void)
2821 const char *errstr = talloc_asprintf(talloc_tos(),
2822 "FAIL ! reply_readbraw: socket write fail (%s)",
2823 strerror(errno));
2824 if (!errstr) {
2825 errstr = "";
2827 exit_server_cleanly(errstr);
2830 /****************************************************************************
2831 Fake (read/write) sendfile. Returns -1 on read or write fail.
2832 ****************************************************************************/
2834 ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos, size_t nread)
2836 size_t bufsize;
2837 size_t tosend = nread;
2838 char *buf;
2840 if (nread == 0) {
2841 return 0;
2844 bufsize = MIN(nread, 65536);
2846 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
2847 return -1;
2850 while (tosend > 0) {
2851 ssize_t ret;
2852 size_t cur_read;
2854 if (tosend > bufsize) {
2855 cur_read = bufsize;
2856 } else {
2857 cur_read = tosend;
2859 ret = read_file(fsp,buf,startpos,cur_read);
2860 if (ret == -1) {
2861 SAFE_FREE(buf);
2862 return -1;
2865 /* If we had a short read, fill with zeros. */
2866 if (ret < cur_read) {
2867 memset(buf + ret, '\0', cur_read - ret);
2870 if (write_data(fsp->conn->sconn->sock, buf, cur_read)
2871 != cur_read) {
2872 char addr[INET6_ADDRSTRLEN];
2874 * Try and give an error message saying what
2875 * client failed.
2877 DEBUG(0, ("write_data failed for client %s. "
2878 "Error %s\n",
2879 get_peer_addr(fsp->conn->sconn->sock, addr,
2880 sizeof(addr)),
2881 strerror(errno)));
2882 SAFE_FREE(buf);
2883 return -1;
2885 tosend -= cur_read;
2886 startpos += cur_read;
2889 SAFE_FREE(buf);
2890 return (ssize_t)nread;
2893 /****************************************************************************
2894 Deal with the case of sendfile reading less bytes from the file than
2895 requested. Fill with zeros (all we can do).
2896 ****************************************************************************/
2898 void sendfile_short_send(files_struct *fsp,
2899 ssize_t nread,
2900 size_t headersize,
2901 size_t smb_maxcnt)
2903 #define SHORT_SEND_BUFSIZE 1024
2904 if (nread < headersize) {
2905 DEBUG(0,("sendfile_short_send: sendfile failed to send "
2906 "header for file %s (%s). Terminating\n",
2907 fsp_str_dbg(fsp), strerror(errno)));
2908 exit_server_cleanly("sendfile_short_send failed");
2911 nread -= headersize;
2913 if (nread < smb_maxcnt) {
2914 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
2915 if (!buf) {
2916 exit_server_cleanly("sendfile_short_send: "
2917 "malloc failed");
2920 DEBUG(0,("sendfile_short_send: filling truncated file %s "
2921 "with zeros !\n", fsp_str_dbg(fsp)));
2923 while (nread < smb_maxcnt) {
2925 * We asked for the real file size and told sendfile
2926 * to not go beyond the end of the file. But it can
2927 * happen that in between our fstat call and the
2928 * sendfile call the file was truncated. This is very
2929 * bad because we have already announced the larger
2930 * number of bytes to the client.
2932 * The best we can do now is to send 0-bytes, just as
2933 * a read from a hole in a sparse file would do.
2935 * This should happen rarely enough that I don't care
2936 * about efficiency here :-)
2938 size_t to_write;
2940 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
2941 if (write_data(fsp->conn->sconn->sock, buf, to_write)
2942 != to_write) {
2943 char addr[INET6_ADDRSTRLEN];
2945 * Try and give an error message saying what
2946 * client failed.
2948 DEBUG(0, ("write_data failed for client %s. "
2949 "Error %s\n",
2950 get_peer_addr(
2951 fsp->conn->sconn->sock, addr,
2952 sizeof(addr)),
2953 strerror(errno)));
2954 exit_server_cleanly("sendfile_short_send: "
2955 "write_data failed");
2957 nread += to_write;
2959 SAFE_FREE(buf);
2963 /****************************************************************************
2964 Return a readbraw error (4 bytes of zero).
2965 ****************************************************************************/
2967 static void reply_readbraw_error(struct smbd_server_connection *sconn)
2969 char header[4];
2971 SIVAL(header,0,0);
2973 smbd_lock_socket(sconn);
2974 if (write_data(sconn->sock,header,4) != 4) {
2975 char addr[INET6_ADDRSTRLEN];
2977 * Try and give an error message saying what
2978 * client failed.
2980 DEBUG(0, ("write_data failed for client %s. "
2981 "Error %s\n",
2982 get_peer_addr(sconn->sock, addr, sizeof(addr)),
2983 strerror(errno)));
2985 fail_readraw();
2987 smbd_unlock_socket(sconn);
2990 /****************************************************************************
2991 Use sendfile in readbraw.
2992 ****************************************************************************/
2994 static void send_file_readbraw(connection_struct *conn,
2995 struct smb_request *req,
2996 files_struct *fsp,
2997 SMB_OFF_T startpos,
2998 size_t nread,
2999 ssize_t mincount)
3001 struct smbd_server_connection *sconn = req->sconn;
3002 char *outbuf = NULL;
3003 ssize_t ret=0;
3006 * We can only use sendfile on a non-chained packet
3007 * but we can use on a non-oplocked file. tridge proved this
3008 * on a train in Germany :-). JRA.
3009 * reply_readbraw has already checked the length.
3012 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3013 (fsp->wcp == NULL) &&
3014 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3015 ssize_t sendfile_read = -1;
3016 char header[4];
3017 DATA_BLOB header_blob;
3019 _smb_setlen(header,nread);
3020 header_blob = data_blob_const(header, 4);
3022 sendfile_read = SMB_VFS_SENDFILE(sconn->sock, fsp,
3023 &header_blob, startpos,
3024 nread);
3025 if (sendfile_read == -1) {
3026 /* Returning ENOSYS means no data at all was sent.
3027 * Do this as a normal read. */
3028 if (errno == ENOSYS) {
3029 goto normal_readbraw;
3033 * Special hack for broken Linux with no working sendfile. If we
3034 * return EINTR we sent the header but not the rest of the data.
3035 * Fake this up by doing read/write calls.
3037 if (errno == EINTR) {
3038 /* Ensure we don't do this again. */
3039 set_use_sendfile(SNUM(conn), False);
3040 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3042 if (fake_sendfile(fsp, startpos, nread) == -1) {
3043 DEBUG(0,("send_file_readbraw: "
3044 "fake_sendfile failed for "
3045 "file %s (%s).\n",
3046 fsp_str_dbg(fsp),
3047 strerror(errno)));
3048 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3050 return;
3053 DEBUG(0,("send_file_readbraw: sendfile failed for "
3054 "file %s (%s). Terminating\n",
3055 fsp_str_dbg(fsp), strerror(errno)));
3056 exit_server_cleanly("send_file_readbraw sendfile failed");
3057 } else if (sendfile_read == 0) {
3059 * Some sendfile implementations return 0 to indicate
3060 * that there was a short read, but nothing was
3061 * actually written to the socket. In this case,
3062 * fallback to the normal read path so the header gets
3063 * the correct byte count.
3065 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3066 "bytes falling back to the normal read: "
3067 "%s\n", fsp_str_dbg(fsp)));
3068 goto normal_readbraw;
3071 /* Deal with possible short send. */
3072 if (sendfile_read != 4+nread) {
3073 sendfile_short_send(fsp, sendfile_read, 4, nread);
3075 return;
3078 normal_readbraw:
3080 outbuf = TALLOC_ARRAY(NULL, char, nread+4);
3081 if (!outbuf) {
3082 DEBUG(0,("send_file_readbraw: TALLOC_ARRAY failed for size %u.\n",
3083 (unsigned)(nread+4)));
3084 reply_readbraw_error(sconn);
3085 return;
3088 if (nread > 0) {
3089 ret = read_file(fsp,outbuf+4,startpos,nread);
3090 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3091 if (ret < mincount)
3092 ret = 0;
3093 #else
3094 if (ret < nread)
3095 ret = 0;
3096 #endif
3099 _smb_setlen(outbuf,ret);
3100 if (write_data(sconn->sock, outbuf, 4+ret) != 4+ret) {
3101 char addr[INET6_ADDRSTRLEN];
3103 * Try and give an error message saying what
3104 * client failed.
3106 DEBUG(0, ("write_data failed for client %s. "
3107 "Error %s\n",
3108 get_peer_addr(fsp->conn->sconn->sock, addr,
3109 sizeof(addr)),
3110 strerror(errno)));
3112 fail_readraw();
3115 TALLOC_FREE(outbuf);
3118 /****************************************************************************
3119 Reply to a readbraw (core+ protocol).
3120 ****************************************************************************/
3122 void reply_readbraw(struct smb_request *req)
3124 connection_struct *conn = req->conn;
3125 struct smbd_server_connection *sconn = req->sconn;
3126 ssize_t maxcount,mincount;
3127 size_t nread = 0;
3128 SMB_OFF_T startpos;
3129 files_struct *fsp;
3130 struct lock_struct lock;
3131 SMB_OFF_T size = 0;
3133 START_PROFILE(SMBreadbraw);
3135 if (srv_is_signing_active(sconn) ||
3136 is_encrypted_packet(req->inbuf)) {
3137 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3138 "raw reads/writes are disallowed.");
3141 if (req->wct < 8) {
3142 reply_readbraw_error(sconn);
3143 END_PROFILE(SMBreadbraw);
3144 return;
3147 if (sconn->smb1.echo_handler.trusted_fde) {
3148 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3149 "'async smb echo handler = yes'\n"));
3150 reply_readbraw_error(sconn);
3151 END_PROFILE(SMBreadbraw);
3152 return;
3156 * Special check if an oplock break has been issued
3157 * and the readraw request croses on the wire, we must
3158 * return a zero length response here.
3161 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3164 * We have to do a check_fsp by hand here, as
3165 * we must always return 4 zero bytes on error,
3166 * not a NTSTATUS.
3169 if (!fsp || !conn || conn != fsp->conn ||
3170 req->vuid != fsp->vuid ||
3171 fsp->is_directory || fsp->fh->fd == -1) {
3173 * fsp could be NULL here so use the value from the packet. JRA.
3175 DEBUG(3,("reply_readbraw: fnum %d not valid "
3176 "- cache prime?\n",
3177 (int)SVAL(req->vwv+0, 0)));
3178 reply_readbraw_error(sconn);
3179 END_PROFILE(SMBreadbraw);
3180 return;
3183 /* Do a "by hand" version of CHECK_READ. */
3184 if (!(fsp->can_read ||
3185 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3186 (fsp->access_mask & FILE_EXECUTE)))) {
3187 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3188 (int)SVAL(req->vwv+0, 0)));
3189 reply_readbraw_error(sconn);
3190 END_PROFILE(SMBreadbraw);
3191 return;
3194 flush_write_cache(fsp, READRAW_FLUSH);
3196 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3197 if(req->wct == 10) {
3199 * This is a large offset (64 bit) read.
3201 #ifdef LARGE_SMB_OFF_T
3203 startpos |= (((SMB_OFF_T)IVAL(req->vwv+8, 0)) << 32);
3205 #else /* !LARGE_SMB_OFF_T */
3208 * Ensure we haven't been sent a >32 bit offset.
3211 if(IVAL(req->vwv+8, 0) != 0) {
3212 DEBUG(0,("reply_readbraw: large offset "
3213 "(%x << 32) used and we don't support "
3214 "64 bit offsets.\n",
3215 (unsigned int)IVAL(req->vwv+8, 0) ));
3216 reply_readbraw_error(sconn);
3217 END_PROFILE(SMBreadbraw);
3218 return;
3221 #endif /* LARGE_SMB_OFF_T */
3223 if(startpos < 0) {
3224 DEBUG(0,("reply_readbraw: negative 64 bit "
3225 "readraw offset (%.0f) !\n",
3226 (double)startpos ));
3227 reply_readbraw_error(sconn);
3228 END_PROFILE(SMBreadbraw);
3229 return;
3233 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3234 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3236 /* ensure we don't overrun the packet size */
3237 maxcount = MIN(65535,maxcount);
3239 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3240 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3241 &lock);
3243 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3244 reply_readbraw_error(sconn);
3245 END_PROFILE(SMBreadbraw);
3246 return;
3249 if (fsp_stat(fsp) == 0) {
3250 size = fsp->fsp_name->st.st_ex_size;
3253 if (startpos >= size) {
3254 nread = 0;
3255 } else {
3256 nread = MIN(maxcount,(size - startpos));
3259 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3260 if (nread < mincount)
3261 nread = 0;
3262 #endif
3264 DEBUG( 3, ( "reply_readbraw: fnum=%d start=%.0f max=%lu "
3265 "min=%lu nread=%lu\n",
3266 fsp->fnum, (double)startpos,
3267 (unsigned long)maxcount,
3268 (unsigned long)mincount,
3269 (unsigned long)nread ) );
3271 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3273 DEBUG(5,("reply_readbraw finished\n"));
3275 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3277 END_PROFILE(SMBreadbraw);
3278 return;
3281 #undef DBGC_CLASS
3282 #define DBGC_CLASS DBGC_LOCKING
3284 /****************************************************************************
3285 Reply to a lockread (core+ protocol).
3286 ****************************************************************************/
3288 void reply_lockread(struct smb_request *req)
3290 connection_struct *conn = req->conn;
3291 ssize_t nread = -1;
3292 char *data;
3293 SMB_OFF_T startpos;
3294 size_t numtoread;
3295 NTSTATUS status;
3296 files_struct *fsp;
3297 struct byte_range_lock *br_lck = NULL;
3298 char *p = NULL;
3299 struct smbd_server_connection *sconn = req->sconn;
3301 START_PROFILE(SMBlockread);
3303 if (req->wct < 5) {
3304 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3305 END_PROFILE(SMBlockread);
3306 return;
3309 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3311 if (!check_fsp(conn, req, fsp)) {
3312 END_PROFILE(SMBlockread);
3313 return;
3316 if (!CHECK_READ(fsp,req)) {
3317 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3318 END_PROFILE(SMBlockread);
3319 return;
3322 numtoread = SVAL(req->vwv+1, 0);
3323 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3325 numtoread = MIN(BUFFER_SIZE - (smb_size + 3*2 + 3), numtoread);
3327 reply_outbuf(req, 5, numtoread + 3);
3329 data = smb_buf(req->outbuf) + 3;
3332 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3333 * protocol request that predates the read/write lock concept.
3334 * Thus instead of asking for a read lock here we need to ask
3335 * for a write lock. JRA.
3336 * Note that the requested lock size is unaffected by max_recv.
3339 br_lck = do_lock(req->sconn->msg_ctx,
3340 fsp,
3341 (uint64_t)req->smbpid,
3342 (uint64_t)numtoread,
3343 (uint64_t)startpos,
3344 WRITE_LOCK,
3345 WINDOWS_LOCK,
3346 False, /* Non-blocking lock. */
3347 &status,
3348 NULL,
3349 NULL);
3350 TALLOC_FREE(br_lck);
3352 if (NT_STATUS_V(status)) {
3353 reply_nterror(req, status);
3354 END_PROFILE(SMBlockread);
3355 return;
3359 * However the requested READ size IS affected by max_recv. Insanity.... JRA.
3362 if (numtoread > sconn->smb1.negprot.max_recv) {
3363 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \
3364 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3365 (unsigned int)numtoread,
3366 (unsigned int)sconn->smb1.negprot.max_recv));
3367 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3369 nread = read_file(fsp,data,startpos,numtoread);
3371 if (nread < 0) {
3372 reply_nterror(req, map_nt_error_from_unix(errno));
3373 END_PROFILE(SMBlockread);
3374 return;
3377 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3379 SSVAL(req->outbuf,smb_vwv0,nread);
3380 SSVAL(req->outbuf,smb_vwv5,nread+3);
3381 p = smb_buf(req->outbuf);
3382 SCVAL(p,0,0); /* pad byte. */
3383 SSVAL(p,1,nread);
3385 DEBUG(3,("lockread fnum=%d num=%d nread=%d\n",
3386 fsp->fnum, (int)numtoread, (int)nread));
3388 END_PROFILE(SMBlockread);
3389 return;
3392 #undef DBGC_CLASS
3393 #define DBGC_CLASS DBGC_ALL
3395 /****************************************************************************
3396 Reply to a read.
3397 ****************************************************************************/
3399 void reply_read(struct smb_request *req)
3401 connection_struct *conn = req->conn;
3402 size_t numtoread;
3403 ssize_t nread = 0;
3404 char *data;
3405 SMB_OFF_T startpos;
3406 int outsize = 0;
3407 files_struct *fsp;
3408 struct lock_struct lock;
3409 struct smbd_server_connection *sconn = req->sconn;
3411 START_PROFILE(SMBread);
3413 if (req->wct < 3) {
3414 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3415 END_PROFILE(SMBread);
3416 return;
3419 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3421 if (!check_fsp(conn, req, fsp)) {
3422 END_PROFILE(SMBread);
3423 return;
3426 if (!CHECK_READ(fsp,req)) {
3427 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3428 END_PROFILE(SMBread);
3429 return;
3432 numtoread = SVAL(req->vwv+1, 0);
3433 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3435 numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
3438 * The requested read size cannot be greater than max_recv. JRA.
3440 if (numtoread > sconn->smb1.negprot.max_recv) {
3441 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \
3442 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3443 (unsigned int)numtoread,
3444 (unsigned int)sconn->smb1.negprot.max_recv));
3445 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3448 reply_outbuf(req, 5, numtoread+3);
3450 data = smb_buf(req->outbuf) + 3;
3452 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3453 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3454 &lock);
3456 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3457 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3458 END_PROFILE(SMBread);
3459 return;
3462 if (numtoread > 0)
3463 nread = read_file(fsp,data,startpos,numtoread);
3465 if (nread < 0) {
3466 reply_nterror(req, map_nt_error_from_unix(errno));
3467 goto strict_unlock;
3470 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3472 SSVAL(req->outbuf,smb_vwv0,nread);
3473 SSVAL(req->outbuf,smb_vwv5,nread+3);
3474 SCVAL(smb_buf(req->outbuf),0,1);
3475 SSVAL(smb_buf(req->outbuf),1,nread);
3477 DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
3478 fsp->fnum, (int)numtoread, (int)nread ) );
3480 strict_unlock:
3481 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3483 END_PROFILE(SMBread);
3484 return;
3487 /****************************************************************************
3488 Setup readX header.
3489 ****************************************************************************/
3491 static int setup_readX_header(struct smb_request *req, char *outbuf,
3492 size_t smb_maxcnt)
3494 int outsize;
3495 char *data;
3497 outsize = srv_set_message(outbuf,12,smb_maxcnt,False);
3498 data = smb_buf(outbuf);
3500 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3502 SCVAL(outbuf,smb_vwv0,0xFF);
3503 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3504 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3505 SSVAL(outbuf,smb_vwv6,
3506 req_wct_ofs(req)
3507 + 1 /* the wct field */
3508 + 12 * sizeof(uint16_t) /* vwv */
3509 + 2); /* the buflen field */
3510 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3511 SSVAL(outbuf,smb_vwv11,smb_maxcnt);
3512 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3513 _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
3514 return outsize;
3517 /****************************************************************************
3518 Reply to a read and X - possibly using sendfile.
3519 ****************************************************************************/
3521 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3522 files_struct *fsp, SMB_OFF_T startpos,
3523 size_t smb_maxcnt)
3525 ssize_t nread = -1;
3526 struct lock_struct lock;
3527 int saved_errno = 0;
3529 if(fsp_stat(fsp) == -1) {
3530 reply_nterror(req, map_nt_error_from_unix(errno));
3531 return;
3534 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3535 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3536 &lock);
3538 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3539 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3540 return;
3543 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3544 (startpos > fsp->fsp_name->st.st_ex_size)
3545 || (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3547 * We already know that we would do a short read, so don't
3548 * try the sendfile() path.
3550 goto nosendfile_read;
3554 * We can only use sendfile on a non-chained packet
3555 * but we can use on a non-oplocked file. tridge proved this
3556 * on a train in Germany :-). JRA.
3559 if (!req_is_in_chain(req) &&
3560 !is_encrypted_packet(req->inbuf) && (fsp->base_fsp == NULL) &&
3561 (fsp->wcp == NULL) &&
3562 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3563 uint8 headerbuf[smb_size + 12 * 2];
3564 DATA_BLOB header;
3567 * Set up the packet header before send. We
3568 * assume here the sendfile will work (get the
3569 * correct amount of data).
3572 header = data_blob_const(headerbuf, sizeof(headerbuf));
3574 construct_reply_common_req(req, (char *)headerbuf);
3575 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3577 nread = SMB_VFS_SENDFILE(req->sconn->sock, fsp, &header,
3578 startpos, smb_maxcnt);
3579 if (nread == -1) {
3580 /* Returning ENOSYS means no data at all was sent.
3581 Do this as a normal read. */
3582 if (errno == ENOSYS) {
3583 goto normal_read;
3587 * Special hack for broken Linux with no working sendfile. If we
3588 * return EINTR we sent the header but not the rest of the data.
3589 * Fake this up by doing read/write calls.
3592 if (errno == EINTR) {
3593 /* Ensure we don't do this again. */
3594 set_use_sendfile(SNUM(conn), False);
3595 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3596 nread = fake_sendfile(fsp, startpos,
3597 smb_maxcnt);
3598 if (nread == -1) {
3599 DEBUG(0,("send_file_readX: "
3600 "fake_sendfile failed for "
3601 "file %s (%s).\n",
3602 fsp_str_dbg(fsp),
3603 strerror(errno)));
3604 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3606 DEBUG( 3, ( "send_file_readX: fake_sendfile fnum=%d max=%d nread=%d\n",
3607 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3608 /* No outbuf here means successful sendfile. */
3609 goto strict_unlock;
3612 DEBUG(0,("send_file_readX: sendfile failed for file "
3613 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3614 strerror(errno)));
3615 exit_server_cleanly("send_file_readX sendfile failed");
3616 } else if (nread == 0) {
3618 * Some sendfile implementations return 0 to indicate
3619 * that there was a short read, but nothing was
3620 * actually written to the socket. In this case,
3621 * fallback to the normal read path so the header gets
3622 * the correct byte count.
3624 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
3625 "falling back to the normal read: %s\n",
3626 fsp_str_dbg(fsp)));
3627 goto normal_read;
3630 DEBUG( 3, ( "send_file_readX: sendfile fnum=%d max=%d nread=%d\n",
3631 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3633 /* Deal with possible short send. */
3634 if (nread != smb_maxcnt + sizeof(headerbuf)) {
3635 sendfile_short_send(fsp, nread, sizeof(headerbuf), smb_maxcnt);
3637 /* No outbuf here means successful sendfile. */
3638 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
3639 SMB_PERFCOUNT_END(&req->pcd);
3640 goto strict_unlock;
3643 normal_read:
3645 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3646 uint8 headerbuf[smb_size + 2*12];
3648 construct_reply_common_req(req, (char *)headerbuf);
3649 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3651 /* Send out the header. */
3652 if (write_data(req->sconn->sock, (char *)headerbuf,
3653 sizeof(headerbuf)) != sizeof(headerbuf)) {
3655 char addr[INET6_ADDRSTRLEN];
3657 * Try and give an error message saying what
3658 * client failed.
3660 DEBUG(0, ("write_data failed for client %s. "
3661 "Error %s\n",
3662 get_peer_addr(req->sconn->sock, addr,
3663 sizeof(addr)),
3664 strerror(errno)));
3666 DEBUG(0,("send_file_readX: write_data failed for file "
3667 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3668 strerror(errno)));
3669 exit_server_cleanly("send_file_readX sendfile failed");
3671 nread = fake_sendfile(fsp, startpos, smb_maxcnt);
3672 if (nread == -1) {
3673 DEBUG(0,("send_file_readX: fake_sendfile failed for "
3674 "file %s (%s).\n", fsp_str_dbg(fsp),
3675 strerror(errno)));
3676 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3678 goto strict_unlock;
3681 nosendfile_read:
3683 reply_outbuf(req, 12, smb_maxcnt);
3685 nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt);
3686 saved_errno = errno;
3688 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3690 if (nread < 0) {
3691 reply_nterror(req, map_nt_error_from_unix(saved_errno));
3692 return;
3695 setup_readX_header(req, (char *)req->outbuf, nread);
3697 DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
3698 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3700 chain_reply(req);
3701 return;
3703 strict_unlock:
3704 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3705 TALLOC_FREE(req->outbuf);
3706 return;
3709 /****************************************************************************
3710 Reply to a read and X.
3711 ****************************************************************************/
3713 void reply_read_and_X(struct smb_request *req)
3715 connection_struct *conn = req->conn;
3716 files_struct *fsp;
3717 SMB_OFF_T startpos;
3718 size_t smb_maxcnt;
3719 bool big_readX = False;
3720 #if 0
3721 size_t smb_mincnt = SVAL(req->vwv+6, 0);
3722 #endif
3724 START_PROFILE(SMBreadX);
3726 if ((req->wct != 10) && (req->wct != 12)) {
3727 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3728 return;
3731 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
3732 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3733 smb_maxcnt = SVAL(req->vwv+5, 0);
3735 /* If it's an IPC, pass off the pipe handler. */
3736 if (IS_IPC(conn)) {
3737 reply_pipe_read_and_X(req);
3738 END_PROFILE(SMBreadX);
3739 return;
3742 if (!check_fsp(conn, req, fsp)) {
3743 END_PROFILE(SMBreadX);
3744 return;
3747 if (!CHECK_READ(fsp,req)) {
3748 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3749 END_PROFILE(SMBreadX);
3750 return;
3753 if (global_client_caps & CAP_LARGE_READX) {
3754 size_t upper_size = SVAL(req->vwv+7, 0);
3755 smb_maxcnt |= (upper_size<<16);
3756 if (upper_size > 1) {
3757 /* Can't do this on a chained packet. */
3758 if ((CVAL(req->vwv+0, 0) != 0xFF)) {
3759 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3760 END_PROFILE(SMBreadX);
3761 return;
3763 /* We currently don't do this on signed or sealed data. */
3764 if (srv_is_signing_active(req->sconn) ||
3765 is_encrypted_packet(req->inbuf)) {
3766 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3767 END_PROFILE(SMBreadX);
3768 return;
3770 /* Is there room in the reply for this data ? */
3771 if (smb_maxcnt > (0xFFFFFF - (smb_size -4 + 12*2))) {
3772 reply_nterror(req,
3773 NT_STATUS_INVALID_PARAMETER);
3774 END_PROFILE(SMBreadX);
3775 return;
3777 big_readX = True;
3781 if (req->wct == 12) {
3782 #ifdef LARGE_SMB_OFF_T
3784 * This is a large offset (64 bit) read.
3786 startpos |= (((SMB_OFF_T)IVAL(req->vwv+10, 0)) << 32);
3788 #else /* !LARGE_SMB_OFF_T */
3791 * Ensure we haven't been sent a >32 bit offset.
3794 if(IVAL(req->vwv+10, 0) != 0) {
3795 DEBUG(0,("reply_read_and_X - large offset (%x << 32) "
3796 "used and we don't support 64 bit offsets.\n",
3797 (unsigned int)IVAL(req->vwv+10, 0) ));
3798 END_PROFILE(SMBreadX);
3799 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3800 return;
3803 #endif /* LARGE_SMB_OFF_T */
3807 if (!big_readX) {
3808 NTSTATUS status = schedule_aio_read_and_X(conn,
3809 req,
3810 fsp,
3811 startpos,
3812 smb_maxcnt);
3813 if (NT_STATUS_IS_OK(status)) {
3814 /* Read scheduled - we're done. */
3815 goto out;
3817 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
3818 /* Real error - report to client. */
3819 END_PROFILE(SMBreadX);
3820 reply_nterror(req, status);
3821 return;
3823 /* NT_STATUS_RETRY - fall back to sync read. */
3826 smbd_lock_socket(req->sconn);
3827 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
3828 smbd_unlock_socket(req->sconn);
3830 out:
3831 END_PROFILE(SMBreadX);
3832 return;
3835 /****************************************************************************
3836 Error replies to writebraw must have smb_wct == 1. Fix this up.
3837 ****************************************************************************/
3839 void error_to_writebrawerr(struct smb_request *req)
3841 uint8 *old_outbuf = req->outbuf;
3843 reply_outbuf(req, 1, 0);
3845 memcpy(req->outbuf, old_outbuf, smb_size);
3846 TALLOC_FREE(old_outbuf);
3849 /****************************************************************************
3850 Read 4 bytes of a smb packet and return the smb length of the packet.
3851 Store the result in the buffer. This version of the function will
3852 never return a session keepalive (length of zero).
3853 Timeout is in milliseconds.
3854 ****************************************************************************/
3856 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
3857 size_t *len)
3859 uint8_t msgtype = SMBkeepalive;
3861 while (msgtype == SMBkeepalive) {
3862 NTSTATUS status;
3864 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
3865 len);
3866 if (!NT_STATUS_IS_OK(status)) {
3867 char addr[INET6_ADDRSTRLEN];
3868 /* Try and give an error message
3869 * saying what client failed. */
3870 DEBUG(0, ("read_fd_with_timeout failed for "
3871 "client %s read error = %s.\n",
3872 get_peer_addr(fd,addr,sizeof(addr)),
3873 nt_errstr(status)));
3874 return status;
3877 msgtype = CVAL(inbuf, 0);
3880 DEBUG(10,("read_smb_length: got smb length of %lu\n",
3881 (unsigned long)len));
3883 return NT_STATUS_OK;
3886 /****************************************************************************
3887 Reply to a writebraw (core+ or LANMAN1.0 protocol).
3888 ****************************************************************************/
3890 void reply_writebraw(struct smb_request *req)
3892 connection_struct *conn = req->conn;
3893 char *buf = NULL;
3894 ssize_t nwritten=0;
3895 ssize_t total_written=0;
3896 size_t numtowrite=0;
3897 size_t tcount;
3898 SMB_OFF_T startpos;
3899 char *data=NULL;
3900 bool write_through;
3901 files_struct *fsp;
3902 struct lock_struct lock;
3903 NTSTATUS status;
3905 START_PROFILE(SMBwritebraw);
3908 * If we ever reply with an error, it must have the SMB command
3909 * type of SMBwritec, not SMBwriteBraw, as this tells the client
3910 * we're finished.
3912 SCVAL(req->inbuf,smb_com,SMBwritec);
3914 if (srv_is_signing_active(req->sconn)) {
3915 END_PROFILE(SMBwritebraw);
3916 exit_server_cleanly("reply_writebraw: SMB signing is active - "
3917 "raw reads/writes are disallowed.");
3920 if (req->wct < 12) {
3921 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3922 error_to_writebrawerr(req);
3923 END_PROFILE(SMBwritebraw);
3924 return;
3927 if (req->sconn->smb1.echo_handler.trusted_fde) {
3928 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
3929 "'async smb echo handler = yes'\n"));
3930 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3931 error_to_writebrawerr(req);
3932 END_PROFILE(SMBwritebraw);
3933 return;
3936 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3937 if (!check_fsp(conn, req, fsp)) {
3938 error_to_writebrawerr(req);
3939 END_PROFILE(SMBwritebraw);
3940 return;
3943 if (!CHECK_WRITE(fsp)) {
3944 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3945 error_to_writebrawerr(req);
3946 END_PROFILE(SMBwritebraw);
3947 return;
3950 tcount = IVAL(req->vwv+1, 0);
3951 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3952 write_through = BITSETW(req->vwv+7,0);
3954 /* We have to deal with slightly different formats depending
3955 on whether we are using the core+ or lanman1.0 protocol */
3957 if(get_Protocol() <= PROTOCOL_COREPLUS) {
3958 numtowrite = SVAL(smb_buf(req->inbuf),-2);
3959 data = smb_buf(req->inbuf);
3960 } else {
3961 numtowrite = SVAL(req->vwv+10, 0);
3962 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
3965 /* Ensure we don't write bytes past the end of this packet. */
3966 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
3967 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3968 error_to_writebrawerr(req);
3969 END_PROFILE(SMBwritebraw);
3970 return;
3973 if (!fsp->print_file) {
3974 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3975 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
3976 &lock);
3978 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3979 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3980 error_to_writebrawerr(req);
3981 END_PROFILE(SMBwritebraw);
3982 return;
3986 if (numtowrite>0) {
3987 nwritten = write_file(req,fsp,data,startpos,numtowrite);
3990 DEBUG(3,("reply_writebraw: initial write fnum=%d start=%.0f num=%d "
3991 "wrote=%d sync=%d\n",
3992 fsp->fnum, (double)startpos, (int)numtowrite,
3993 (int)nwritten, (int)write_through));
3995 if (nwritten < (ssize_t)numtowrite) {
3996 reply_nterror(req, NT_STATUS_DISK_FULL);
3997 error_to_writebrawerr(req);
3998 goto strict_unlock;
4001 total_written = nwritten;
4003 /* Allocate a buffer of 64k + length. */
4004 buf = TALLOC_ARRAY(NULL, char, 65540);
4005 if (!buf) {
4006 reply_nterror(req, NT_STATUS_NO_MEMORY);
4007 error_to_writebrawerr(req);
4008 goto strict_unlock;
4011 /* Return a SMBwritebraw message to the redirector to tell
4012 * it to send more bytes */
4014 memcpy(buf, req->inbuf, smb_size);
4015 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4016 SCVAL(buf,smb_com,SMBwritebraw);
4017 SSVALS(buf,smb_vwv0,0xFFFF);
4018 show_msg(buf);
4019 if (!srv_send_smb(req->sconn,
4020 buf,
4021 false, 0, /* no signing */
4022 IS_CONN_ENCRYPTED(conn),
4023 &req->pcd)) {
4024 exit_server_cleanly("reply_writebraw: srv_send_smb "
4025 "failed.");
4028 /* Now read the raw data into the buffer and write it */
4029 status = read_smb_length(req->sconn->sock, buf, SMB_SECONDARY_WAIT,
4030 &numtowrite);
4031 if (!NT_STATUS_IS_OK(status)) {
4032 exit_server_cleanly("secondary writebraw failed");
4035 /* Set up outbuf to return the correct size */
4036 reply_outbuf(req, 1, 0);
4038 if (numtowrite != 0) {
4040 if (numtowrite > 0xFFFF) {
4041 DEBUG(0,("reply_writebraw: Oversize secondary write "
4042 "raw requested (%u). Terminating\n",
4043 (unsigned int)numtowrite ));
4044 exit_server_cleanly("secondary writebraw failed");
4047 if (tcount > nwritten+numtowrite) {
4048 DEBUG(3,("reply_writebraw: Client overestimated the "
4049 "write %d %d %d\n",
4050 (int)tcount,(int)nwritten,(int)numtowrite));
4053 status = read_data(req->sconn->sock, buf+4, numtowrite);
4055 if (!NT_STATUS_IS_OK(status)) {
4056 char addr[INET6_ADDRSTRLEN];
4057 /* Try and give an error message
4058 * saying what client failed. */
4059 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4060 "raw read failed (%s) for client %s. "
4061 "Terminating\n", nt_errstr(status),
4062 get_peer_addr(req->sconn->sock, addr,
4063 sizeof(addr))));
4064 exit_server_cleanly("secondary writebraw failed");
4067 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4068 if (nwritten == -1) {
4069 TALLOC_FREE(buf);
4070 reply_nterror(req, map_nt_error_from_unix(errno));
4071 error_to_writebrawerr(req);
4072 goto strict_unlock;
4075 if (nwritten < (ssize_t)numtowrite) {
4076 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4077 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4080 if (nwritten > 0) {
4081 total_written += nwritten;
4085 TALLOC_FREE(buf);
4086 SSVAL(req->outbuf,smb_vwv0,total_written);
4088 status = sync_file(conn, fsp, write_through);
4089 if (!NT_STATUS_IS_OK(status)) {
4090 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4091 fsp_str_dbg(fsp), nt_errstr(status)));
4092 reply_nterror(req, status);
4093 error_to_writebrawerr(req);
4094 goto strict_unlock;
4097 DEBUG(3,("reply_writebraw: secondart write fnum=%d start=%.0f num=%d "
4098 "wrote=%d\n",
4099 fsp->fnum, (double)startpos, (int)numtowrite,
4100 (int)total_written));
4102 if (!fsp->print_file) {
4103 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4106 /* We won't return a status if write through is not selected - this
4107 * follows what WfWg does */
4108 END_PROFILE(SMBwritebraw);
4110 if (!write_through && total_written==tcount) {
4112 #if RABBIT_PELLET_FIX
4114 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4115 * sending a SMBkeepalive. Thanks to DaveCB at Sun for this.
4116 * JRA.
4118 if (!send_keepalive(req->sconn->sock)) {
4119 exit_server_cleanly("reply_writebraw: send of "
4120 "keepalive failed");
4122 #endif
4123 TALLOC_FREE(req->outbuf);
4125 return;
4127 strict_unlock:
4128 if (!fsp->print_file) {
4129 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4132 END_PROFILE(SMBwritebraw);
4133 return;
4136 #undef DBGC_CLASS
4137 #define DBGC_CLASS DBGC_LOCKING
4139 /****************************************************************************
4140 Reply to a writeunlock (core+).
4141 ****************************************************************************/
4143 void reply_writeunlock(struct smb_request *req)
4145 connection_struct *conn = req->conn;
4146 ssize_t nwritten = -1;
4147 size_t numtowrite;
4148 SMB_OFF_T startpos;
4149 const char *data;
4150 NTSTATUS status = NT_STATUS_OK;
4151 files_struct *fsp;
4152 struct lock_struct lock;
4153 int saved_errno = 0;
4155 START_PROFILE(SMBwriteunlock);
4157 if (req->wct < 5) {
4158 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4159 END_PROFILE(SMBwriteunlock);
4160 return;
4163 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4165 if (!check_fsp(conn, req, fsp)) {
4166 END_PROFILE(SMBwriteunlock);
4167 return;
4170 if (!CHECK_WRITE(fsp)) {
4171 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4172 END_PROFILE(SMBwriteunlock);
4173 return;
4176 numtowrite = SVAL(req->vwv+1, 0);
4177 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4178 data = (const char *)req->buf + 3;
4180 if (!fsp->print_file && numtowrite > 0) {
4181 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4182 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4183 &lock);
4185 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4186 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4187 END_PROFILE(SMBwriteunlock);
4188 return;
4192 /* The special X/Open SMB protocol handling of
4193 zero length writes is *NOT* done for
4194 this call */
4195 if(numtowrite == 0) {
4196 nwritten = 0;
4197 } else {
4198 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4199 saved_errno = errno;
4202 status = sync_file(conn, fsp, False /* write through */);
4203 if (!NT_STATUS_IS_OK(status)) {
4204 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4205 fsp_str_dbg(fsp), nt_errstr(status)));
4206 reply_nterror(req, status);
4207 goto strict_unlock;
4210 if(nwritten < 0) {
4211 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4212 goto strict_unlock;
4215 if((nwritten < numtowrite) && (numtowrite != 0)) {
4216 reply_nterror(req, NT_STATUS_DISK_FULL);
4217 goto strict_unlock;
4220 if (numtowrite && !fsp->print_file) {
4221 status = do_unlock(req->sconn->msg_ctx,
4222 fsp,
4223 (uint64_t)req->smbpid,
4224 (uint64_t)numtowrite,
4225 (uint64_t)startpos,
4226 WINDOWS_LOCK);
4228 if (NT_STATUS_V(status)) {
4229 reply_nterror(req, status);
4230 goto strict_unlock;
4234 reply_outbuf(req, 1, 0);
4236 SSVAL(req->outbuf,smb_vwv0,nwritten);
4238 DEBUG(3,("writeunlock fnum=%d num=%d wrote=%d\n",
4239 fsp->fnum, (int)numtowrite, (int)nwritten));
4241 strict_unlock:
4242 if (numtowrite && !fsp->print_file) {
4243 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4246 END_PROFILE(SMBwriteunlock);
4247 return;
4250 #undef DBGC_CLASS
4251 #define DBGC_CLASS DBGC_ALL
4253 /****************************************************************************
4254 Reply to a write.
4255 ****************************************************************************/
4257 void reply_write(struct smb_request *req)
4259 connection_struct *conn = req->conn;
4260 size_t numtowrite;
4261 ssize_t nwritten = -1;
4262 SMB_OFF_T startpos;
4263 const char *data;
4264 files_struct *fsp;
4265 struct lock_struct lock;
4266 NTSTATUS status;
4267 int saved_errno = 0;
4269 START_PROFILE(SMBwrite);
4271 if (req->wct < 5) {
4272 END_PROFILE(SMBwrite);
4273 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4274 return;
4277 /* If it's an IPC, pass off the pipe handler. */
4278 if (IS_IPC(conn)) {
4279 reply_pipe_write(req);
4280 END_PROFILE(SMBwrite);
4281 return;
4284 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4286 if (!check_fsp(conn, req, fsp)) {
4287 END_PROFILE(SMBwrite);
4288 return;
4291 if (!CHECK_WRITE(fsp)) {
4292 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4293 END_PROFILE(SMBwrite);
4294 return;
4297 numtowrite = SVAL(req->vwv+1, 0);
4298 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4299 data = (const char *)req->buf + 3;
4301 if (!fsp->print_file) {
4302 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4303 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4304 &lock);
4306 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4307 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4308 END_PROFILE(SMBwrite);
4309 return;
4314 * X/Open SMB protocol says that if smb_vwv1 is
4315 * zero then the file size should be extended or
4316 * truncated to the size given in smb_vwv[2-3].
4319 if(numtowrite == 0) {
4321 * This is actually an allocate call, and set EOF. JRA.
4323 nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos);
4324 if (nwritten < 0) {
4325 reply_nterror(req, NT_STATUS_DISK_FULL);
4326 goto strict_unlock;
4328 nwritten = vfs_set_filelen(fsp, (SMB_OFF_T)startpos);
4329 if (nwritten < 0) {
4330 reply_nterror(req, NT_STATUS_DISK_FULL);
4331 goto strict_unlock;
4333 trigger_write_time_update_immediate(fsp);
4334 } else {
4335 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4338 status = sync_file(conn, fsp, False);
4339 if (!NT_STATUS_IS_OK(status)) {
4340 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4341 fsp_str_dbg(fsp), nt_errstr(status)));
4342 reply_nterror(req, status);
4343 goto strict_unlock;
4346 if(nwritten < 0) {
4347 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4348 goto strict_unlock;
4351 if((nwritten == 0) && (numtowrite != 0)) {
4352 reply_nterror(req, NT_STATUS_DISK_FULL);
4353 goto strict_unlock;
4356 reply_outbuf(req, 1, 0);
4358 SSVAL(req->outbuf,smb_vwv0,nwritten);
4360 if (nwritten < (ssize_t)numtowrite) {
4361 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4362 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4365 DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten));
4367 strict_unlock:
4368 if (!fsp->print_file) {
4369 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4372 END_PROFILE(SMBwrite);
4373 return;
4376 /****************************************************************************
4377 Ensure a buffer is a valid writeX for recvfile purposes.
4378 ****************************************************************************/
4380 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4381 (2*14) + /* word count (including bcc) */ \
4382 1 /* pad byte */)
4384 bool is_valid_writeX_buffer(struct smbd_server_connection *sconn,
4385 const uint8_t *inbuf)
4387 size_t numtowrite;
4388 connection_struct *conn = NULL;
4389 unsigned int doff = 0;
4390 size_t len = smb_len_large(inbuf);
4392 if (is_encrypted_packet(inbuf)) {
4393 /* Can't do this on encrypted
4394 * connections. */
4395 return false;
4398 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4399 return false;
4402 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4403 CVAL(inbuf,smb_wct) != 14) {
4404 DEBUG(10,("is_valid_writeX_buffer: chained or "
4405 "invalid word length.\n"));
4406 return false;
4409 conn = conn_find(sconn, SVAL(inbuf, smb_tid));
4410 if (conn == NULL) {
4411 DEBUG(10,("is_valid_writeX_buffer: bad tid\n"));
4412 return false;
4414 if (IS_IPC(conn)) {
4415 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4416 return false;
4418 if (IS_PRINT(conn)) {
4419 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4420 return false;
4422 doff = SVAL(inbuf,smb_vwv11);
4424 numtowrite = SVAL(inbuf,smb_vwv10);
4426 if (len > doff && len - doff > 0xFFFF) {
4427 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4430 if (numtowrite == 0) {
4431 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4432 return false;
4435 /* Ensure the sizes match up. */
4436 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4437 /* no pad byte...old smbclient :-( */
4438 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4439 (unsigned int)doff,
4440 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4441 return false;
4444 if (len - doff != numtowrite) {
4445 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4446 "len = %u, doff = %u, numtowrite = %u\n",
4447 (unsigned int)len,
4448 (unsigned int)doff,
4449 (unsigned int)numtowrite ));
4450 return false;
4453 DEBUG(10,("is_valid_writeX_buffer: true "
4454 "len = %u, doff = %u, numtowrite = %u\n",
4455 (unsigned int)len,
4456 (unsigned int)doff,
4457 (unsigned int)numtowrite ));
4459 return true;
4462 /****************************************************************************
4463 Reply to a write and X.
4464 ****************************************************************************/
4466 void reply_write_and_X(struct smb_request *req)
4468 connection_struct *conn = req->conn;
4469 files_struct *fsp;
4470 struct lock_struct lock;
4471 SMB_OFF_T startpos;
4472 size_t numtowrite;
4473 bool write_through;
4474 ssize_t nwritten;
4475 unsigned int smb_doff;
4476 unsigned int smblen;
4477 char *data;
4478 NTSTATUS status;
4479 int saved_errno = 0;
4481 START_PROFILE(SMBwriteX);
4483 if ((req->wct != 12) && (req->wct != 14)) {
4484 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4485 END_PROFILE(SMBwriteX);
4486 return;
4489 numtowrite = SVAL(req->vwv+10, 0);
4490 smb_doff = SVAL(req->vwv+11, 0);
4491 smblen = smb_len(req->inbuf);
4493 if (req->unread_bytes > 0xFFFF ||
4494 (smblen > smb_doff &&
4495 smblen - smb_doff > 0xFFFF)) {
4496 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
4499 if (req->unread_bytes) {
4500 /* Can't do a recvfile write on IPC$ */
4501 if (IS_IPC(conn)) {
4502 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4503 END_PROFILE(SMBwriteX);
4504 return;
4506 if (numtowrite != req->unread_bytes) {
4507 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4508 END_PROFILE(SMBwriteX);
4509 return;
4511 } else {
4512 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4513 smb_doff + numtowrite > smblen) {
4514 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4515 END_PROFILE(SMBwriteX);
4516 return;
4520 /* If it's an IPC, pass off the pipe handler. */
4521 if (IS_IPC(conn)) {
4522 if (req->unread_bytes) {
4523 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4524 END_PROFILE(SMBwriteX);
4525 return;
4527 reply_pipe_write_and_X(req);
4528 END_PROFILE(SMBwriteX);
4529 return;
4532 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4533 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4534 write_through = BITSETW(req->vwv+7,0);
4536 if (!check_fsp(conn, req, fsp)) {
4537 END_PROFILE(SMBwriteX);
4538 return;
4541 if (!CHECK_WRITE(fsp)) {
4542 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4543 END_PROFILE(SMBwriteX);
4544 return;
4547 data = smb_base(req->inbuf) + smb_doff;
4549 if(req->wct == 14) {
4550 #ifdef LARGE_SMB_OFF_T
4552 * This is a large offset (64 bit) write.
4554 startpos |= (((SMB_OFF_T)IVAL(req->vwv+12, 0)) << 32);
4556 #else /* !LARGE_SMB_OFF_T */
4559 * Ensure we haven't been sent a >32 bit offset.
4562 if(IVAL(req->vwv+12, 0) != 0) {
4563 DEBUG(0,("reply_write_and_X - large offset (%x << 32) "
4564 "used and we don't support 64 bit offsets.\n",
4565 (unsigned int)IVAL(req->vwv+12, 0) ));
4566 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4567 END_PROFILE(SMBwriteX);
4568 return;
4571 #endif /* LARGE_SMB_OFF_T */
4574 /* X/Open SMB protocol says that, unlike SMBwrite
4575 if the length is zero then NO truncation is
4576 done, just a write of zero. To truncate a file,
4577 use SMBwrite. */
4579 if(numtowrite == 0) {
4580 nwritten = 0;
4581 } else {
4582 if (req->unread_bytes == 0) {
4583 status = schedule_aio_write_and_X(conn,
4584 req,
4585 fsp,
4586 data,
4587 startpos,
4588 numtowrite);
4590 if (NT_STATUS_IS_OK(status)) {
4591 /* write scheduled - we're done. */
4592 goto out;
4594 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4595 /* Real error - report to client. */
4596 reply_nterror(req, status);
4597 goto out;
4599 /* NT_STATUS_RETRY - fall through to sync write. */
4602 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4603 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4604 &lock);
4606 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4607 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4608 goto out;
4611 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4612 saved_errno = errno;
4614 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4617 if(nwritten < 0) {
4618 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4619 goto out;
4622 if((nwritten == 0) && (numtowrite != 0)) {
4623 reply_nterror(req, NT_STATUS_DISK_FULL);
4624 goto out;
4627 reply_outbuf(req, 6, 0);
4628 SSVAL(req->outbuf,smb_vwv2,nwritten);
4629 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4631 if (nwritten < (ssize_t)numtowrite) {
4632 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4633 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4636 DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
4637 fsp->fnum, (int)numtowrite, (int)nwritten));
4639 status = sync_file(conn, fsp, write_through);
4640 if (!NT_STATUS_IS_OK(status)) {
4641 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4642 fsp_str_dbg(fsp), nt_errstr(status)));
4643 reply_nterror(req, status);
4644 goto out;
4647 END_PROFILE(SMBwriteX);
4648 chain_reply(req);
4649 return;
4651 out:
4652 END_PROFILE(SMBwriteX);
4653 return;
4656 /****************************************************************************
4657 Reply to a lseek.
4658 ****************************************************************************/
4660 void reply_lseek(struct smb_request *req)
4662 connection_struct *conn = req->conn;
4663 SMB_OFF_T startpos;
4664 SMB_OFF_T res= -1;
4665 int mode,umode;
4666 files_struct *fsp;
4668 START_PROFILE(SMBlseek);
4670 if (req->wct < 4) {
4671 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4672 END_PROFILE(SMBlseek);
4673 return;
4676 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4678 if (!check_fsp(conn, req, fsp)) {
4679 return;
4682 flush_write_cache(fsp, SEEK_FLUSH);
4684 mode = SVAL(req->vwv+1, 0) & 3;
4685 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4686 startpos = (SMB_OFF_T)IVALS(req->vwv+2, 0);
4688 switch (mode) {
4689 case 0:
4690 umode = SEEK_SET;
4691 res = startpos;
4692 break;
4693 case 1:
4694 umode = SEEK_CUR;
4695 res = fsp->fh->pos + startpos;
4696 break;
4697 case 2:
4698 umode = SEEK_END;
4699 break;
4700 default:
4701 umode = SEEK_SET;
4702 res = startpos;
4703 break;
4706 if (umode == SEEK_END) {
4707 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
4708 if(errno == EINVAL) {
4709 SMB_OFF_T current_pos = startpos;
4711 if(fsp_stat(fsp) == -1) {
4712 reply_nterror(req,
4713 map_nt_error_from_unix(errno));
4714 END_PROFILE(SMBlseek);
4715 return;
4718 current_pos += fsp->fsp_name->st.st_ex_size;
4719 if(current_pos < 0)
4720 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
4724 if(res == -1) {
4725 reply_nterror(req, map_nt_error_from_unix(errno));
4726 END_PROFILE(SMBlseek);
4727 return;
4731 fsp->fh->pos = res;
4733 reply_outbuf(req, 2, 0);
4734 SIVAL(req->outbuf,smb_vwv0,res);
4736 DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
4737 fsp->fnum, (double)startpos, (double)res, mode));
4739 END_PROFILE(SMBlseek);
4740 return;
4743 /****************************************************************************
4744 Reply to a flush.
4745 ****************************************************************************/
4747 void reply_flush(struct smb_request *req)
4749 connection_struct *conn = req->conn;
4750 uint16 fnum;
4751 files_struct *fsp;
4753 START_PROFILE(SMBflush);
4755 if (req->wct < 1) {
4756 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4757 return;
4760 fnum = SVAL(req->vwv+0, 0);
4761 fsp = file_fsp(req, fnum);
4763 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
4764 return;
4767 if (!fsp) {
4768 file_sync_all(conn);
4769 } else {
4770 NTSTATUS status = sync_file(conn, fsp, True);
4771 if (!NT_STATUS_IS_OK(status)) {
4772 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
4773 fsp_str_dbg(fsp), nt_errstr(status)));
4774 reply_nterror(req, status);
4775 END_PROFILE(SMBflush);
4776 return;
4780 reply_outbuf(req, 0, 0);
4782 DEBUG(3,("flush\n"));
4783 END_PROFILE(SMBflush);
4784 return;
4787 /****************************************************************************
4788 Reply to a exit.
4789 conn POINTER CAN BE NULL HERE !
4790 ****************************************************************************/
4792 void reply_exit(struct smb_request *req)
4794 START_PROFILE(SMBexit);
4796 file_close_pid(req->sconn, req->smbpid, req->vuid);
4798 reply_outbuf(req, 0, 0);
4800 DEBUG(3,("exit\n"));
4802 END_PROFILE(SMBexit);
4803 return;
4806 /****************************************************************************
4807 Reply to a close - has to deal with closing a directory opened by NT SMB's.
4808 ****************************************************************************/
4810 void reply_close(struct smb_request *req)
4812 connection_struct *conn = req->conn;
4813 NTSTATUS status = NT_STATUS_OK;
4814 files_struct *fsp = NULL;
4815 START_PROFILE(SMBclose);
4817 if (req->wct < 3) {
4818 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4819 END_PROFILE(SMBclose);
4820 return;
4823 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4826 * We can only use check_fsp if we know it's not a directory.
4829 if (!check_fsp_open(conn, req, fsp)) {
4830 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
4831 END_PROFILE(SMBclose);
4832 return;
4835 if(fsp->is_directory) {
4837 * Special case - close NT SMB directory handle.
4839 DEBUG(3,("close directory fnum=%d\n", fsp->fnum));
4840 status = close_file(req, fsp, NORMAL_CLOSE);
4841 } else {
4842 time_t t;
4844 * Close ordinary file.
4847 DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
4848 fsp->fh->fd, fsp->fnum,
4849 conn->num_files_open));
4852 * Take care of any time sent in the close.
4855 t = srv_make_unix_date3(req->vwv+1);
4856 set_close_write_time(fsp, convert_time_t_to_timespec(t));
4859 * close_file() returns the unix errno if an error
4860 * was detected on close - normally this is due to
4861 * a disk full error. If not then it was probably an I/O error.
4864 status = close_file(req, fsp, NORMAL_CLOSE);
4867 if (!NT_STATUS_IS_OK(status)) {
4868 reply_nterror(req, status);
4869 END_PROFILE(SMBclose);
4870 return;
4873 reply_outbuf(req, 0, 0);
4874 END_PROFILE(SMBclose);
4875 return;
4878 /****************************************************************************
4879 Reply to a writeclose (Core+ protocol).
4880 ****************************************************************************/
4882 void reply_writeclose(struct smb_request *req)
4884 connection_struct *conn = req->conn;
4885 size_t numtowrite;
4886 ssize_t nwritten = -1;
4887 NTSTATUS close_status = NT_STATUS_OK;
4888 SMB_OFF_T startpos;
4889 const char *data;
4890 struct timespec mtime;
4891 files_struct *fsp;
4892 struct lock_struct lock;
4894 START_PROFILE(SMBwriteclose);
4896 if (req->wct < 6) {
4897 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4898 END_PROFILE(SMBwriteclose);
4899 return;
4902 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4904 if (!check_fsp(conn, req, fsp)) {
4905 END_PROFILE(SMBwriteclose);
4906 return;
4908 if (!CHECK_WRITE(fsp)) {
4909 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4910 END_PROFILE(SMBwriteclose);
4911 return;
4914 numtowrite = SVAL(req->vwv+1, 0);
4915 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4916 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
4917 data = (const char *)req->buf + 1;
4919 if (!fsp->print_file) {
4920 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4921 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4922 &lock);
4924 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4925 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4926 END_PROFILE(SMBwriteclose);
4927 return;
4931 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4933 set_close_write_time(fsp, mtime);
4936 * More insanity. W2K only closes the file if writelen > 0.
4937 * JRA.
4940 if (numtowrite) {
4941 DEBUG(3,("reply_writeclose: zero length write doesn't close "
4942 "file %s\n", fsp_str_dbg(fsp)));
4943 close_status = close_file(req, fsp, NORMAL_CLOSE);
4946 DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
4947 fsp->fnum, (int)numtowrite, (int)nwritten,
4948 conn->num_files_open));
4950 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
4951 reply_nterror(req, NT_STATUS_DISK_FULL);
4952 goto strict_unlock;
4955 if(!NT_STATUS_IS_OK(close_status)) {
4956 reply_nterror(req, close_status);
4957 goto strict_unlock;
4960 reply_outbuf(req, 1, 0);
4962 SSVAL(req->outbuf,smb_vwv0,nwritten);
4964 strict_unlock:
4965 if (numtowrite && !fsp->print_file) {
4966 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4969 END_PROFILE(SMBwriteclose);
4970 return;
4973 #undef DBGC_CLASS
4974 #define DBGC_CLASS DBGC_LOCKING
4976 /****************************************************************************
4977 Reply to a lock.
4978 ****************************************************************************/
4980 void reply_lock(struct smb_request *req)
4982 connection_struct *conn = req->conn;
4983 uint64_t count,offset;
4984 NTSTATUS status;
4985 files_struct *fsp;
4986 struct byte_range_lock *br_lck = NULL;
4988 START_PROFILE(SMBlock);
4990 if (req->wct < 5) {
4991 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4992 END_PROFILE(SMBlock);
4993 return;
4996 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4998 if (!check_fsp(conn, req, fsp)) {
4999 END_PROFILE(SMBlock);
5000 return;
5003 count = (uint64_t)IVAL(req->vwv+1, 0);
5004 offset = (uint64_t)IVAL(req->vwv+3, 0);
5006 DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
5007 fsp->fh->fd, fsp->fnum, (double)offset, (double)count));
5009 br_lck = do_lock(req->sconn->msg_ctx,
5010 fsp,
5011 (uint64_t)req->smbpid,
5012 count,
5013 offset,
5014 WRITE_LOCK,
5015 WINDOWS_LOCK,
5016 False, /* Non-blocking lock. */
5017 &status,
5018 NULL,
5019 NULL);
5021 TALLOC_FREE(br_lck);
5023 if (NT_STATUS_V(status)) {
5024 reply_nterror(req, status);
5025 END_PROFILE(SMBlock);
5026 return;
5029 reply_outbuf(req, 0, 0);
5031 END_PROFILE(SMBlock);
5032 return;
5035 /****************************************************************************
5036 Reply to a unlock.
5037 ****************************************************************************/
5039 void reply_unlock(struct smb_request *req)
5041 connection_struct *conn = req->conn;
5042 uint64_t count,offset;
5043 NTSTATUS status;
5044 files_struct *fsp;
5046 START_PROFILE(SMBunlock);
5048 if (req->wct < 5) {
5049 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5050 END_PROFILE(SMBunlock);
5051 return;
5054 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5056 if (!check_fsp(conn, req, fsp)) {
5057 END_PROFILE(SMBunlock);
5058 return;
5061 count = (uint64_t)IVAL(req->vwv+1, 0);
5062 offset = (uint64_t)IVAL(req->vwv+3, 0);
5064 status = do_unlock(req->sconn->msg_ctx,
5065 fsp,
5066 (uint64_t)req->smbpid,
5067 count,
5068 offset,
5069 WINDOWS_LOCK);
5071 if (NT_STATUS_V(status)) {
5072 reply_nterror(req, status);
5073 END_PROFILE(SMBunlock);
5074 return;
5077 DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
5078 fsp->fh->fd, fsp->fnum, (double)offset, (double)count ) );
5080 reply_outbuf(req, 0, 0);
5082 END_PROFILE(SMBunlock);
5083 return;
5086 #undef DBGC_CLASS
5087 #define DBGC_CLASS DBGC_ALL
5089 /****************************************************************************
5090 Reply to a tdis.
5091 conn POINTER CAN BE NULL HERE !
5092 ****************************************************************************/
5094 void reply_tdis(struct smb_request *req)
5096 connection_struct *conn = req->conn;
5097 START_PROFILE(SMBtdis);
5099 if (!conn) {
5100 DEBUG(4,("Invalid connection in tdis\n"));
5101 reply_nterror(req, NT_STATUS_NETWORK_NAME_DELETED);
5102 END_PROFILE(SMBtdis);
5103 return;
5106 conn->used = False;
5108 close_cnum(conn,req->vuid);
5109 req->conn = NULL;
5111 reply_outbuf(req, 0, 0);
5112 END_PROFILE(SMBtdis);
5113 return;
5116 /****************************************************************************
5117 Reply to a echo.
5118 conn POINTER CAN BE NULL HERE !
5119 ****************************************************************************/
5121 void reply_echo(struct smb_request *req)
5123 connection_struct *conn = req->conn;
5124 struct smb_perfcount_data local_pcd;
5125 struct smb_perfcount_data *cur_pcd;
5126 int smb_reverb;
5127 int seq_num;
5129 START_PROFILE(SMBecho);
5131 smb_init_perfcount_data(&local_pcd);
5133 if (req->wct < 1) {
5134 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5135 END_PROFILE(SMBecho);
5136 return;
5139 smb_reverb = SVAL(req->vwv+0, 0);
5141 reply_outbuf(req, 1, req->buflen);
5143 /* copy any incoming data back out */
5144 if (req->buflen > 0) {
5145 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5148 if (smb_reverb > 100) {
5149 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5150 smb_reverb = 100;
5153 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5155 /* this makes sure we catch the request pcd */
5156 if (seq_num == smb_reverb) {
5157 cur_pcd = &req->pcd;
5158 } else {
5159 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5160 cur_pcd = &local_pcd;
5163 SSVAL(req->outbuf,smb_vwv0,seq_num);
5165 show_msg((char *)req->outbuf);
5166 if (!srv_send_smb(req->sconn,
5167 (char *)req->outbuf,
5168 true, req->seqnum+1,
5169 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5170 cur_pcd))
5171 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5174 DEBUG(3,("echo %d times\n", smb_reverb));
5176 TALLOC_FREE(req->outbuf);
5178 END_PROFILE(SMBecho);
5179 return;
5182 /****************************************************************************
5183 Reply to a printopen.
5184 ****************************************************************************/
5186 void reply_printopen(struct smb_request *req)
5188 connection_struct *conn = req->conn;
5189 files_struct *fsp;
5190 NTSTATUS status;
5192 START_PROFILE(SMBsplopen);
5194 if (req->wct < 2) {
5195 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5196 END_PROFILE(SMBsplopen);
5197 return;
5200 if (!CAN_PRINT(conn)) {
5201 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5202 END_PROFILE(SMBsplopen);
5203 return;
5206 status = file_new(req, conn, &fsp);
5207 if(!NT_STATUS_IS_OK(status)) {
5208 reply_nterror(req, status);
5209 END_PROFILE(SMBsplopen);
5210 return;
5213 /* Open for exclusive use, write only. */
5214 status = print_spool_open(fsp, NULL, req->vuid);
5216 if (!NT_STATUS_IS_OK(status)) {
5217 file_free(req, fsp);
5218 reply_nterror(req, status);
5219 END_PROFILE(SMBsplopen);
5220 return;
5223 reply_outbuf(req, 1, 0);
5224 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5226 DEBUG(3,("openprint fd=%d fnum=%d\n",
5227 fsp->fh->fd, fsp->fnum));
5229 END_PROFILE(SMBsplopen);
5230 return;
5233 /****************************************************************************
5234 Reply to a printclose.
5235 ****************************************************************************/
5237 void reply_printclose(struct smb_request *req)
5239 connection_struct *conn = req->conn;
5240 files_struct *fsp;
5241 NTSTATUS status;
5243 START_PROFILE(SMBsplclose);
5245 if (req->wct < 1) {
5246 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5247 END_PROFILE(SMBsplclose);
5248 return;
5251 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5253 if (!check_fsp(conn, req, fsp)) {
5254 END_PROFILE(SMBsplclose);
5255 return;
5258 if (!CAN_PRINT(conn)) {
5259 reply_force_doserror(req, ERRSRV, ERRerror);
5260 END_PROFILE(SMBsplclose);
5261 return;
5264 DEBUG(3,("printclose fd=%d fnum=%d\n",
5265 fsp->fh->fd,fsp->fnum));
5267 status = close_file(req, fsp, NORMAL_CLOSE);
5269 if(!NT_STATUS_IS_OK(status)) {
5270 reply_nterror(req, status);
5271 END_PROFILE(SMBsplclose);
5272 return;
5275 reply_outbuf(req, 0, 0);
5277 END_PROFILE(SMBsplclose);
5278 return;
5281 /****************************************************************************
5282 Reply to a printqueue.
5283 ****************************************************************************/
5285 void reply_printqueue(struct smb_request *req)
5287 connection_struct *conn = req->conn;
5288 int max_count;
5289 int start_index;
5291 START_PROFILE(SMBsplretq);
5293 if (req->wct < 2) {
5294 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5295 END_PROFILE(SMBsplretq);
5296 return;
5299 max_count = SVAL(req->vwv+0, 0);
5300 start_index = SVAL(req->vwv+1, 0);
5302 /* we used to allow the client to get the cnum wrong, but that
5303 is really quite gross and only worked when there was only
5304 one printer - I think we should now only accept it if they
5305 get it right (tridge) */
5306 if (!CAN_PRINT(conn)) {
5307 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5308 END_PROFILE(SMBsplretq);
5309 return;
5312 reply_outbuf(req, 2, 3);
5313 SSVAL(req->outbuf,smb_vwv0,0);
5314 SSVAL(req->outbuf,smb_vwv1,0);
5315 SCVAL(smb_buf(req->outbuf),0,1);
5316 SSVAL(smb_buf(req->outbuf),1,0);
5318 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5319 start_index, max_count));
5322 TALLOC_CTX *mem_ctx = talloc_tos();
5323 NTSTATUS status;
5324 WERROR werr;
5325 const char *sharename = lp_servicename(SNUM(conn));
5326 struct rpc_pipe_client *cli = NULL;
5327 struct dcerpc_binding_handle *b = NULL;
5328 struct policy_handle handle;
5329 struct spoolss_DevmodeContainer devmode_ctr;
5330 union spoolss_JobInfo *info;
5331 uint32_t count;
5332 uint32_t num_to_get;
5333 uint32_t first;
5334 uint32_t i;
5336 ZERO_STRUCT(handle);
5338 status = rpc_pipe_open_interface(conn,
5339 &ndr_table_spoolss.syntax_id,
5340 conn->session_info,
5341 &conn->sconn->client_id,
5342 conn->sconn->msg_ctx,
5343 &cli);
5344 if (!NT_STATUS_IS_OK(status)) {
5345 DEBUG(0, ("reply_printqueue: "
5346 "could not connect to spoolss: %s\n",
5347 nt_errstr(status)));
5348 reply_nterror(req, status);
5349 goto out;
5351 b = cli->binding_handle;
5353 ZERO_STRUCT(devmode_ctr);
5355 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5356 sharename,
5357 NULL, devmode_ctr,
5358 SEC_FLAG_MAXIMUM_ALLOWED,
5359 &handle,
5360 &werr);
5361 if (!NT_STATUS_IS_OK(status)) {
5362 reply_nterror(req, status);
5363 goto out;
5365 if (!W_ERROR_IS_OK(werr)) {
5366 reply_nterror(req, werror_to_ntstatus(werr));
5367 goto out;
5370 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5371 &handle,
5372 0, /* firstjob */
5373 0xff, /* numjobs */
5374 2, /* level */
5375 0, /* offered */
5376 &count,
5377 &info);
5378 if (!W_ERROR_IS_OK(werr)) {
5379 reply_nterror(req, werror_to_ntstatus(werr));
5380 goto out;
5383 if (max_count > 0) {
5384 first = start_index;
5385 } else {
5386 first = start_index + max_count + 1;
5389 if (first >= count) {
5390 num_to_get = first;
5391 } else {
5392 num_to_get = first + MIN(ABS(max_count), count - first);
5395 for (i = first; i < num_to_get; i++) {
5396 char blob[28];
5397 char *p = blob;
5398 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
5399 int qstatus;
5400 uint16_t qrapjobid = pjobid_to_rap(sharename,
5401 info[i].info2.job_id);
5403 if (info[i].info2.status == JOB_STATUS_PRINTING) {
5404 qstatus = 2;
5405 } else {
5406 qstatus = 3;
5409 srv_put_dos_date2(p, 0, qtime);
5410 SCVAL(p, 4, qstatus);
5411 SSVAL(p, 5, qrapjobid);
5412 SIVAL(p, 7, info[i].info2.size);
5413 SCVAL(p, 11, 0);
5414 srvstr_push(blob, req->flags2, p+12,
5415 info[i].info2.notify_name, 16, STR_ASCII);
5417 if (message_push_blob(
5418 &req->outbuf,
5419 data_blob_const(
5420 blob, sizeof(blob))) == -1) {
5421 reply_nterror(req, NT_STATUS_NO_MEMORY);
5422 goto out;
5426 if (count > 0) {
5427 SSVAL(req->outbuf,smb_vwv0,count);
5428 SSVAL(req->outbuf,smb_vwv1,
5429 (max_count>0?first+count:first-1));
5430 SCVAL(smb_buf(req->outbuf),0,1);
5431 SSVAL(smb_buf(req->outbuf),1,28*count);
5435 DEBUG(3, ("%u entries returned in queue\n",
5436 (unsigned)count));
5438 out:
5439 if (b && is_valid_policy_hnd(&handle)) {
5440 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5445 END_PROFILE(SMBsplretq);
5446 return;
5449 /****************************************************************************
5450 Reply to a printwrite.
5451 ****************************************************************************/
5453 void reply_printwrite(struct smb_request *req)
5455 connection_struct *conn = req->conn;
5456 int numtowrite;
5457 const char *data;
5458 files_struct *fsp;
5460 START_PROFILE(SMBsplwr);
5462 if (req->wct < 1) {
5463 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5464 END_PROFILE(SMBsplwr);
5465 return;
5468 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5470 if (!check_fsp(conn, req, fsp)) {
5471 END_PROFILE(SMBsplwr);
5472 return;
5475 if (!fsp->print_file) {
5476 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5477 END_PROFILE(SMBsplwr);
5478 return;
5481 if (!CHECK_WRITE(fsp)) {
5482 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5483 END_PROFILE(SMBsplwr);
5484 return;
5487 numtowrite = SVAL(req->buf, 1);
5489 if (req->buflen < numtowrite + 3) {
5490 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5491 END_PROFILE(SMBsplwr);
5492 return;
5495 data = (const char *)req->buf + 3;
5497 if (write_file(req,fsp,data,(SMB_OFF_T)-1,numtowrite) != numtowrite) {
5498 reply_nterror(req, map_nt_error_from_unix(errno));
5499 END_PROFILE(SMBsplwr);
5500 return;
5503 DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
5505 END_PROFILE(SMBsplwr);
5506 return;
5509 /****************************************************************************
5510 Reply to a mkdir.
5511 ****************************************************************************/
5513 void reply_mkdir(struct smb_request *req)
5515 connection_struct *conn = req->conn;
5516 struct smb_filename *smb_dname = NULL;
5517 char *directory = NULL;
5518 NTSTATUS status;
5519 TALLOC_CTX *ctx = talloc_tos();
5521 START_PROFILE(SMBmkdir);
5523 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5524 STR_TERMINATE, &status);
5525 if (!NT_STATUS_IS_OK(status)) {
5526 reply_nterror(req, status);
5527 goto out;
5530 status = filename_convert(ctx, conn,
5531 req->flags2 & FLAGS2_DFS_PATHNAMES,
5532 directory,
5534 NULL,
5535 &smb_dname);
5536 if (!NT_STATUS_IS_OK(status)) {
5537 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5538 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5539 ERRSRV, ERRbadpath);
5540 goto out;
5542 reply_nterror(req, status);
5543 goto out;
5546 status = create_directory(conn, req, smb_dname);
5548 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
5550 if (!NT_STATUS_IS_OK(status)) {
5552 if (!use_nt_status()
5553 && NT_STATUS_EQUAL(status,
5554 NT_STATUS_OBJECT_NAME_COLLISION)) {
5556 * Yes, in the DOS error code case we get a
5557 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
5558 * samba4 torture test.
5560 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
5563 reply_nterror(req, status);
5564 goto out;
5567 reply_outbuf(req, 0, 0);
5569 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
5570 out:
5571 TALLOC_FREE(smb_dname);
5572 END_PROFILE(SMBmkdir);
5573 return;
5576 /****************************************************************************
5577 Reply to a rmdir.
5578 ****************************************************************************/
5580 void reply_rmdir(struct smb_request *req)
5582 connection_struct *conn = req->conn;
5583 struct smb_filename *smb_dname = NULL;
5584 char *directory = NULL;
5585 NTSTATUS status;
5586 TALLOC_CTX *ctx = talloc_tos();
5587 files_struct *fsp = NULL;
5588 int info = 0;
5589 struct smbd_server_connection *sconn = req->sconn;
5591 START_PROFILE(SMBrmdir);
5593 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5594 STR_TERMINATE, &status);
5595 if (!NT_STATUS_IS_OK(status)) {
5596 reply_nterror(req, status);
5597 goto out;
5600 status = filename_convert(ctx, conn,
5601 req->flags2 & FLAGS2_DFS_PATHNAMES,
5602 directory,
5604 NULL,
5605 &smb_dname);
5606 if (!NT_STATUS_IS_OK(status)) {
5607 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5608 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5609 ERRSRV, ERRbadpath);
5610 goto out;
5612 reply_nterror(req, status);
5613 goto out;
5616 if (is_ntfs_stream_smb_fname(smb_dname)) {
5617 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
5618 goto out;
5621 status = SMB_VFS_CREATE_FILE(
5622 conn, /* conn */
5623 req, /* req */
5624 0, /* root_dir_fid */
5625 smb_dname, /* fname */
5626 DELETE_ACCESS, /* access_mask */
5627 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5628 FILE_SHARE_DELETE),
5629 FILE_OPEN, /* create_disposition*/
5630 FILE_DIRECTORY_FILE, /* create_options */
5631 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
5632 0, /* oplock_request */
5633 0, /* allocation_size */
5634 0, /* private_flags */
5635 NULL, /* sd */
5636 NULL, /* ea_list */
5637 &fsp, /* result */
5638 &info); /* pinfo */
5640 if (!NT_STATUS_IS_OK(status)) {
5641 if (open_was_deferred(req->mid)) {
5642 /* We have re-scheduled this call. */
5643 goto out;
5645 reply_nterror(req, status);
5646 goto out;
5649 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
5650 if (!NT_STATUS_IS_OK(status)) {
5651 close_file(req, fsp, ERROR_CLOSE);
5652 reply_nterror(req, status);
5653 goto out;
5656 if (!set_delete_on_close(fsp, true, &conn->session_info->utok)) {
5657 close_file(req, fsp, ERROR_CLOSE);
5658 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5659 goto out;
5662 status = close_file(req, fsp, NORMAL_CLOSE);
5663 if (!NT_STATUS_IS_OK(status)) {
5664 reply_nterror(req, status);
5665 } else {
5666 reply_outbuf(req, 0, 0);
5669 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
5671 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
5672 out:
5673 TALLOC_FREE(smb_dname);
5674 END_PROFILE(SMBrmdir);
5675 return;
5678 /*******************************************************************
5679 Resolve wildcards in a filename rename.
5680 ********************************************************************/
5682 static bool resolve_wildcards(TALLOC_CTX *ctx,
5683 const char *name1,
5684 const char *name2,
5685 char **pp_newname)
5687 char *name2_copy = NULL;
5688 char *root1 = NULL;
5689 char *root2 = NULL;
5690 char *ext1 = NULL;
5691 char *ext2 = NULL;
5692 char *p,*p2, *pname1, *pname2;
5694 name2_copy = talloc_strdup(ctx, name2);
5695 if (!name2_copy) {
5696 return False;
5699 pname1 = strrchr_m(name1,'/');
5700 pname2 = strrchr_m(name2_copy,'/');
5702 if (!pname1 || !pname2) {
5703 return False;
5706 /* Truncate the copy of name2 at the last '/' */
5707 *pname2 = '\0';
5709 /* Now go past the '/' */
5710 pname1++;
5711 pname2++;
5713 root1 = talloc_strdup(ctx, pname1);
5714 root2 = talloc_strdup(ctx, pname2);
5716 if (!root1 || !root2) {
5717 return False;
5720 p = strrchr_m(root1,'.');
5721 if (p) {
5722 *p = 0;
5723 ext1 = talloc_strdup(ctx, p+1);
5724 } else {
5725 ext1 = talloc_strdup(ctx, "");
5727 p = strrchr_m(root2,'.');
5728 if (p) {
5729 *p = 0;
5730 ext2 = talloc_strdup(ctx, p+1);
5731 } else {
5732 ext2 = talloc_strdup(ctx, "");
5735 if (!ext1 || !ext2) {
5736 return False;
5739 p = root1;
5740 p2 = root2;
5741 while (*p2) {
5742 if (*p2 == '?') {
5743 /* Hmmm. Should this be mb-aware ? */
5744 *p2 = *p;
5745 p2++;
5746 } else if (*p2 == '*') {
5747 *p2 = '\0';
5748 root2 = talloc_asprintf(ctx, "%s%s",
5749 root2,
5751 if (!root2) {
5752 return False;
5754 break;
5755 } else {
5756 p2++;
5758 if (*p) {
5759 p++;
5763 p = ext1;
5764 p2 = ext2;
5765 while (*p2) {
5766 if (*p2 == '?') {
5767 /* Hmmm. Should this be mb-aware ? */
5768 *p2 = *p;
5769 p2++;
5770 } else if (*p2 == '*') {
5771 *p2 = '\0';
5772 ext2 = talloc_asprintf(ctx, "%s%s",
5773 ext2,
5775 if (!ext2) {
5776 return False;
5778 break;
5779 } else {
5780 p2++;
5782 if (*p) {
5783 p++;
5787 if (*ext2) {
5788 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
5789 name2_copy,
5790 root2,
5791 ext2);
5792 } else {
5793 *pp_newname = talloc_asprintf(ctx, "%s/%s",
5794 name2_copy,
5795 root2);
5798 if (!*pp_newname) {
5799 return False;
5802 return True;
5805 /****************************************************************************
5806 Ensure open files have their names updated. Updated to notify other smbd's
5807 asynchronously.
5808 ****************************************************************************/
5810 static void rename_open_files(connection_struct *conn,
5811 struct share_mode_lock *lck,
5812 uint32_t orig_name_hash,
5813 const struct smb_filename *smb_fname_dst)
5815 files_struct *fsp;
5816 bool did_rename = False;
5817 NTSTATUS status;
5818 uint32_t new_name_hash;
5820 for(fsp = file_find_di_first(conn->sconn, lck->id); fsp;
5821 fsp = file_find_di_next(fsp)) {
5822 /* fsp_name is a relative path under the fsp. To change this for other
5823 sharepaths we need to manipulate relative paths. */
5824 /* TODO - create the absolute path and manipulate the newname
5825 relative to the sharepath. */
5826 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
5827 continue;
5829 if (fsp->name_hash != orig_name_hash) {
5830 continue;
5832 DEBUG(10, ("rename_open_files: renaming file fnum %d "
5833 "(file_id %s) from %s -> %s\n", fsp->fnum,
5834 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
5835 smb_fname_str_dbg(smb_fname_dst)));
5837 status = fsp_set_smb_fname(fsp, smb_fname_dst);
5838 if (NT_STATUS_IS_OK(status)) {
5839 did_rename = True;
5840 new_name_hash = fsp->name_hash;
5844 if (!did_rename) {
5845 DEBUG(10, ("rename_open_files: no open files on file_id %s "
5846 "for %s\n", file_id_string_tos(&lck->id),
5847 smb_fname_str_dbg(smb_fname_dst)));
5850 /* Send messages to all smbd's (not ourself) that the name has changed. */
5851 rename_share_filename(conn->sconn->msg_ctx, lck, conn->connectpath,
5852 orig_name_hash, new_name_hash,
5853 smb_fname_dst);
5857 /****************************************************************************
5858 We need to check if the source path is a parent directory of the destination
5859 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
5860 refuse the rename with a sharing violation. Under UNIX the above call can
5861 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
5862 probably need to check that the client is a Windows one before disallowing
5863 this as a UNIX client (one with UNIX extensions) can know the source is a
5864 symlink and make this decision intelligently. Found by an excellent bug
5865 report from <AndyLiebman@aol.com>.
5866 ****************************************************************************/
5868 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
5869 const struct smb_filename *smb_fname_dst)
5871 const char *psrc = smb_fname_src->base_name;
5872 const char *pdst = smb_fname_dst->base_name;
5873 size_t slen;
5875 if (psrc[0] == '.' && psrc[1] == '/') {
5876 psrc += 2;
5878 if (pdst[0] == '.' && pdst[1] == '/') {
5879 pdst += 2;
5881 if ((slen = strlen(psrc)) > strlen(pdst)) {
5882 return False;
5884 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
5888 * Do the notify calls from a rename
5891 static void notify_rename(connection_struct *conn, bool is_dir,
5892 const struct smb_filename *smb_fname_src,
5893 const struct smb_filename *smb_fname_dst)
5895 char *parent_dir_src = NULL;
5896 char *parent_dir_dst = NULL;
5897 uint32 mask;
5899 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
5900 : FILE_NOTIFY_CHANGE_FILE_NAME;
5902 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
5903 &parent_dir_src, NULL) ||
5904 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
5905 &parent_dir_dst, NULL)) {
5906 goto out;
5909 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
5910 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
5911 smb_fname_src->base_name);
5912 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
5913 smb_fname_dst->base_name);
5915 else {
5916 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
5917 smb_fname_src->base_name);
5918 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
5919 smb_fname_dst->base_name);
5922 /* this is a strange one. w2k3 gives an additional event for
5923 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
5924 files, but not directories */
5925 if (!is_dir) {
5926 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
5927 FILE_NOTIFY_CHANGE_ATTRIBUTES
5928 |FILE_NOTIFY_CHANGE_CREATION,
5929 smb_fname_dst->base_name);
5931 out:
5932 TALLOC_FREE(parent_dir_src);
5933 TALLOC_FREE(parent_dir_dst);
5936 /****************************************************************************
5937 Rename an open file - given an fsp.
5938 ****************************************************************************/
5940 NTSTATUS rename_internals_fsp(connection_struct *conn,
5941 files_struct *fsp,
5942 const struct smb_filename *smb_fname_dst_in,
5943 uint32 attrs,
5944 bool replace_if_exists)
5946 TALLOC_CTX *ctx = talloc_tos();
5947 struct smb_filename *smb_fname_dst = NULL;
5948 NTSTATUS status = NT_STATUS_OK;
5949 struct share_mode_lock *lck = NULL;
5950 bool dst_exists, old_is_stream, new_is_stream;
5952 status = check_name(conn, smb_fname_dst_in->base_name);
5953 if (!NT_STATUS_IS_OK(status)) {
5954 return status;
5957 /* Make a copy of the dst smb_fname structs */
5959 status = copy_smb_filename(ctx, smb_fname_dst_in, &smb_fname_dst);
5960 if (!NT_STATUS_IS_OK(status)) {
5961 goto out;
5965 * Check for special case with case preserving and not
5966 * case sensitive. If the old last component differs from the original
5967 * last component only by case, then we should allow
5968 * the rename (user is trying to change the case of the
5969 * filename).
5971 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
5972 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
5973 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
5974 char *last_slash;
5975 char *fname_dst_lcomp_base_mod = NULL;
5976 struct smb_filename *smb_fname_orig_lcomp = NULL;
5979 * Get the last component of the destination name.
5981 last_slash = strrchr_m(smb_fname_dst->base_name, '/');
5982 if (last_slash) {
5983 fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1);
5984 } else {
5985 fname_dst_lcomp_base_mod = talloc_strdup(ctx, smb_fname_dst->base_name);
5987 if (!fname_dst_lcomp_base_mod) {
5988 status = NT_STATUS_NO_MEMORY;
5989 goto out;
5993 * Create an smb_filename struct using the original last
5994 * component of the destination.
5996 status = create_synthetic_smb_fname_split(ctx,
5997 smb_fname_dst->original_lcomp, NULL,
5998 &smb_fname_orig_lcomp);
5999 if (!NT_STATUS_IS_OK(status)) {
6000 TALLOC_FREE(fname_dst_lcomp_base_mod);
6001 goto out;
6004 /* If the base names only differ by case, use original. */
6005 if(!strcsequal(fname_dst_lcomp_base_mod,
6006 smb_fname_orig_lcomp->base_name)) {
6007 char *tmp;
6009 * Replace the modified last component with the
6010 * original.
6012 if (last_slash) {
6013 *last_slash = '\0'; /* Truncate at the '/' */
6014 tmp = talloc_asprintf(smb_fname_dst,
6015 "%s/%s",
6016 smb_fname_dst->base_name,
6017 smb_fname_orig_lcomp->base_name);
6018 } else {
6019 tmp = talloc_asprintf(smb_fname_dst,
6020 "%s",
6021 smb_fname_orig_lcomp->base_name);
6023 if (tmp == NULL) {
6024 status = NT_STATUS_NO_MEMORY;
6025 TALLOC_FREE(fname_dst_lcomp_base_mod);
6026 TALLOC_FREE(smb_fname_orig_lcomp);
6027 goto out;
6029 TALLOC_FREE(smb_fname_dst->base_name);
6030 smb_fname_dst->base_name = tmp;
6033 /* If the stream_names only differ by case, use original. */
6034 if(!strcsequal(smb_fname_dst->stream_name,
6035 smb_fname_orig_lcomp->stream_name)) {
6036 char *tmp = NULL;
6037 /* Use the original stream. */
6038 tmp = talloc_strdup(smb_fname_dst,
6039 smb_fname_orig_lcomp->stream_name);
6040 if (tmp == NULL) {
6041 status = NT_STATUS_NO_MEMORY;
6042 TALLOC_FREE(fname_dst_lcomp_base_mod);
6043 TALLOC_FREE(smb_fname_orig_lcomp);
6044 goto out;
6046 TALLOC_FREE(smb_fname_dst->stream_name);
6047 smb_fname_dst->stream_name = tmp;
6049 TALLOC_FREE(fname_dst_lcomp_base_mod);
6050 TALLOC_FREE(smb_fname_orig_lcomp);
6054 * If the src and dest names are identical - including case,
6055 * don't do the rename, just return success.
6058 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6059 strcsequal(fsp->fsp_name->stream_name,
6060 smb_fname_dst->stream_name)) {
6061 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6062 "- returning success\n",
6063 smb_fname_str_dbg(smb_fname_dst)));
6064 status = NT_STATUS_OK;
6065 goto out;
6068 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6069 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6071 /* Return the correct error code if both names aren't streams. */
6072 if (!old_is_stream && new_is_stream) {
6073 status = NT_STATUS_OBJECT_NAME_INVALID;
6074 goto out;
6077 if (old_is_stream && !new_is_stream) {
6078 status = NT_STATUS_INVALID_PARAMETER;
6079 goto out;
6082 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6084 if(!replace_if_exists && dst_exists) {
6085 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6086 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6087 smb_fname_str_dbg(smb_fname_dst)));
6088 status = NT_STATUS_OBJECT_NAME_COLLISION;
6089 goto out;
6092 if (dst_exists) {
6093 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6094 &smb_fname_dst->st);
6095 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6096 fileid);
6097 /* The file can be open when renaming a stream */
6098 if (dst_fsp && !new_is_stream) {
6099 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6100 status = NT_STATUS_ACCESS_DENIED;
6101 goto out;
6105 /* Ensure we have a valid stat struct for the source. */
6106 status = vfs_stat_fsp(fsp);
6107 if (!NT_STATUS_IS_OK(status)) {
6108 goto out;
6111 status = can_rename(conn, fsp, attrs);
6113 if (!NT_STATUS_IS_OK(status)) {
6114 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6115 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6116 smb_fname_str_dbg(smb_fname_dst)));
6117 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6118 status = NT_STATUS_ACCESS_DENIED;
6119 goto out;
6122 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6123 status = NT_STATUS_ACCESS_DENIED;
6126 lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
6127 NULL);
6130 * We have the file open ourselves, so not being able to get the
6131 * corresponding share mode lock is a fatal error.
6134 SMB_ASSERT(lck != NULL);
6136 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6137 uint32 create_options = fsp->fh->private_options;
6139 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6140 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6141 smb_fname_str_dbg(smb_fname_dst)));
6143 if (!lp_posix_pathnames() &&
6144 (lp_map_archive(SNUM(conn)) ||
6145 lp_store_dos_attributes(SNUM(conn)))) {
6146 /* We must set the archive bit on the newly
6147 renamed file. */
6148 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6149 uint32_t old_dosmode = dos_mode(conn,
6150 smb_fname_dst);
6151 file_set_dosmode(conn,
6152 smb_fname_dst,
6153 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6154 NULL,
6155 true);
6159 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6160 smb_fname_dst);
6162 rename_open_files(conn, lck, fsp->name_hash, smb_fname_dst);
6165 * A rename acts as a new file create w.r.t. allowing an initial delete
6166 * on close, probably because in Windows there is a new handle to the
6167 * new file. If initial delete on close was requested but not
6168 * originally set, we need to set it here. This is probably not 100% correct,
6169 * but will work for the CIFSFS client which in non-posix mode
6170 * depends on these semantics. JRA.
6173 if (create_options & FILE_DELETE_ON_CLOSE) {
6174 status = can_set_delete_on_close(fsp, 0);
6176 if (NT_STATUS_IS_OK(status)) {
6177 /* Note that here we set the *inital* delete on close flag,
6178 * not the regular one. The magic gets handled in close. */
6179 fsp->initial_delete_on_close = True;
6182 TALLOC_FREE(lck);
6183 status = NT_STATUS_OK;
6184 goto out;
6187 TALLOC_FREE(lck);
6189 if (errno == ENOTDIR || errno == EISDIR) {
6190 status = NT_STATUS_OBJECT_NAME_COLLISION;
6191 } else {
6192 status = map_nt_error_from_unix(errno);
6195 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6196 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6197 smb_fname_str_dbg(smb_fname_dst)));
6199 out:
6200 TALLOC_FREE(smb_fname_dst);
6202 return status;
6205 /****************************************************************************
6206 The guts of the rename command, split out so it may be called by the NT SMB
6207 code.
6208 ****************************************************************************/
6210 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6211 connection_struct *conn,
6212 struct smb_request *req,
6213 struct smb_filename *smb_fname_src,
6214 struct smb_filename *smb_fname_dst,
6215 uint32 attrs,
6216 bool replace_if_exists,
6217 bool src_has_wild,
6218 bool dest_has_wild,
6219 uint32_t access_mask)
6221 char *fname_src_dir = NULL;
6222 char *fname_src_mask = NULL;
6223 int count=0;
6224 NTSTATUS status = NT_STATUS_OK;
6225 struct smb_Dir *dir_hnd = NULL;
6226 const char *dname = NULL;
6227 char *talloced = NULL;
6228 long offset = 0;
6229 int create_options = 0;
6230 bool posix_pathnames = lp_posix_pathnames();
6233 * Split the old name into directory and last component
6234 * strings. Note that unix_convert may have stripped off a
6235 * leading ./ from both name and newname if the rename is
6236 * at the root of the share. We need to make sure either both
6237 * name and newname contain a / character or neither of them do
6238 * as this is checked in resolve_wildcards().
6241 /* Split up the directory from the filename/mask. */
6242 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6243 &fname_src_dir, &fname_src_mask);
6244 if (!NT_STATUS_IS_OK(status)) {
6245 status = NT_STATUS_NO_MEMORY;
6246 goto out;
6250 * We should only check the mangled cache
6251 * here if unix_convert failed. This means
6252 * that the path in 'mask' doesn't exist
6253 * on the file system and so we need to look
6254 * for a possible mangle. This patch from
6255 * Tine Smukavec <valentin.smukavec@hermes.si>.
6258 if (!VALID_STAT(smb_fname_src->st) &&
6259 mangle_is_mangled(fname_src_mask, conn->params)) {
6260 char *new_mask = NULL;
6261 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6262 conn->params);
6263 if (new_mask) {
6264 TALLOC_FREE(fname_src_mask);
6265 fname_src_mask = new_mask;
6269 if (!src_has_wild) {
6270 files_struct *fsp;
6273 * Only one file needs to be renamed. Append the mask back
6274 * onto the directory.
6276 TALLOC_FREE(smb_fname_src->base_name);
6277 if (ISDOT(fname_src_dir)) {
6278 /* Ensure we use canonical names on open. */
6279 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6280 "%s",
6281 fname_src_mask);
6282 } else {
6283 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6284 "%s/%s",
6285 fname_src_dir,
6286 fname_src_mask);
6288 if (!smb_fname_src->base_name) {
6289 status = NT_STATUS_NO_MEMORY;
6290 goto out;
6293 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6294 "case_preserve = %d, short case preserve = %d, "
6295 "directory = %s, newname = %s, "
6296 "last_component_dest = %s\n",
6297 conn->case_sensitive, conn->case_preserve,
6298 conn->short_case_preserve,
6299 smb_fname_str_dbg(smb_fname_src),
6300 smb_fname_str_dbg(smb_fname_dst),
6301 smb_fname_dst->original_lcomp));
6303 /* The dest name still may have wildcards. */
6304 if (dest_has_wild) {
6305 char *fname_dst_mod = NULL;
6306 if (!resolve_wildcards(smb_fname_dst,
6307 smb_fname_src->base_name,
6308 smb_fname_dst->base_name,
6309 &fname_dst_mod)) {
6310 DEBUG(6, ("rename_internals: resolve_wildcards "
6311 "%s %s failed\n",
6312 smb_fname_src->base_name,
6313 smb_fname_dst->base_name));
6314 status = NT_STATUS_NO_MEMORY;
6315 goto out;
6317 TALLOC_FREE(smb_fname_dst->base_name);
6318 smb_fname_dst->base_name = fname_dst_mod;
6321 ZERO_STRUCT(smb_fname_src->st);
6322 if (posix_pathnames) {
6323 SMB_VFS_LSTAT(conn, smb_fname_src);
6324 } else {
6325 SMB_VFS_STAT(conn, smb_fname_src);
6328 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6329 create_options |= FILE_DIRECTORY_FILE;
6332 status = SMB_VFS_CREATE_FILE(
6333 conn, /* conn */
6334 req, /* req */
6335 0, /* root_dir_fid */
6336 smb_fname_src, /* fname */
6337 access_mask, /* access_mask */
6338 (FILE_SHARE_READ | /* share_access */
6339 FILE_SHARE_WRITE),
6340 FILE_OPEN, /* create_disposition*/
6341 create_options, /* create_options */
6342 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6343 0, /* oplock_request */
6344 0, /* allocation_size */
6345 0, /* private_flags */
6346 NULL, /* sd */
6347 NULL, /* ea_list */
6348 &fsp, /* result */
6349 NULL); /* pinfo */
6351 if (!NT_STATUS_IS_OK(status)) {
6352 DEBUG(3, ("Could not open rename source %s: %s\n",
6353 smb_fname_str_dbg(smb_fname_src),
6354 nt_errstr(status)));
6355 goto out;
6358 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6359 attrs, replace_if_exists);
6361 close_file(req, fsp, NORMAL_CLOSE);
6363 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
6364 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
6365 smb_fname_str_dbg(smb_fname_dst)));
6367 goto out;
6371 * Wildcards - process each file that matches.
6373 if (strequal(fname_src_mask, "????????.???")) {
6374 TALLOC_FREE(fname_src_mask);
6375 fname_src_mask = talloc_strdup(ctx, "*");
6376 if (!fname_src_mask) {
6377 status = NT_STATUS_NO_MEMORY;
6378 goto out;
6382 status = check_name(conn, fname_src_dir);
6383 if (!NT_STATUS_IS_OK(status)) {
6384 goto out;
6387 dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask,
6388 attrs);
6389 if (dir_hnd == NULL) {
6390 status = map_nt_error_from_unix(errno);
6391 goto out;
6394 status = NT_STATUS_NO_SUCH_FILE;
6396 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
6397 * - gentest fix. JRA
6400 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
6401 &talloced))) {
6402 files_struct *fsp = NULL;
6403 char *destname = NULL;
6404 bool sysdir_entry = False;
6406 /* Quick check for "." and ".." */
6407 if (ISDOT(dname) || ISDOTDOT(dname)) {
6408 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
6409 sysdir_entry = True;
6410 } else {
6411 TALLOC_FREE(talloced);
6412 continue;
6416 if (!is_visible_file(conn, fname_src_dir, dname,
6417 &smb_fname_src->st, false)) {
6418 TALLOC_FREE(talloced);
6419 continue;
6422 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
6423 TALLOC_FREE(talloced);
6424 continue;
6427 if (sysdir_entry) {
6428 status = NT_STATUS_OBJECT_NAME_INVALID;
6429 break;
6432 TALLOC_FREE(smb_fname_src->base_name);
6433 if (ISDOT(fname_src_dir)) {
6434 /* Ensure we use canonical names on open. */
6435 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6436 "%s",
6437 dname);
6438 } else {
6439 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6440 "%s/%s",
6441 fname_src_dir,
6442 dname);
6444 if (!smb_fname_src->base_name) {
6445 status = NT_STATUS_NO_MEMORY;
6446 goto out;
6449 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6450 smb_fname_dst->base_name,
6451 &destname)) {
6452 DEBUG(6, ("resolve_wildcards %s %s failed\n",
6453 smb_fname_src->base_name, destname));
6454 TALLOC_FREE(talloced);
6455 continue;
6457 if (!destname) {
6458 status = NT_STATUS_NO_MEMORY;
6459 goto out;
6462 TALLOC_FREE(smb_fname_dst->base_name);
6463 smb_fname_dst->base_name = destname;
6465 ZERO_STRUCT(smb_fname_src->st);
6466 if (posix_pathnames) {
6467 SMB_VFS_LSTAT(conn, smb_fname_src);
6468 } else {
6469 SMB_VFS_STAT(conn, smb_fname_src);
6472 create_options = 0;
6474 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6475 create_options |= FILE_DIRECTORY_FILE;
6478 status = SMB_VFS_CREATE_FILE(
6479 conn, /* conn */
6480 req, /* req */
6481 0, /* root_dir_fid */
6482 smb_fname_src, /* fname */
6483 access_mask, /* access_mask */
6484 (FILE_SHARE_READ | /* share_access */
6485 FILE_SHARE_WRITE),
6486 FILE_OPEN, /* create_disposition*/
6487 create_options, /* create_options */
6488 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6489 0, /* oplock_request */
6490 0, /* allocation_size */
6491 0, /* private_flags */
6492 NULL, /* sd */
6493 NULL, /* ea_list */
6494 &fsp, /* result */
6495 NULL); /* pinfo */
6497 if (!NT_STATUS_IS_OK(status)) {
6498 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
6499 "returned %s rename %s -> %s\n",
6500 nt_errstr(status),
6501 smb_fname_str_dbg(smb_fname_src),
6502 smb_fname_str_dbg(smb_fname_dst)));
6503 break;
6506 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6507 dname);
6508 if (!smb_fname_dst->original_lcomp) {
6509 status = NT_STATUS_NO_MEMORY;
6510 goto out;
6513 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6514 attrs, replace_if_exists);
6516 close_file(req, fsp, NORMAL_CLOSE);
6518 if (!NT_STATUS_IS_OK(status)) {
6519 DEBUG(3, ("rename_internals_fsp returned %s for "
6520 "rename %s -> %s\n", nt_errstr(status),
6521 smb_fname_str_dbg(smb_fname_src),
6522 smb_fname_str_dbg(smb_fname_dst)));
6523 break;
6526 count++;
6528 DEBUG(3,("rename_internals: doing rename on %s -> "
6529 "%s\n", smb_fname_str_dbg(smb_fname_src),
6530 smb_fname_str_dbg(smb_fname_src)));
6531 TALLOC_FREE(talloced);
6533 TALLOC_FREE(dir_hnd);
6535 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
6536 status = map_nt_error_from_unix(errno);
6539 out:
6540 TALLOC_FREE(talloced);
6541 TALLOC_FREE(fname_src_dir);
6542 TALLOC_FREE(fname_src_mask);
6543 return status;
6546 /****************************************************************************
6547 Reply to a mv.
6548 ****************************************************************************/
6550 void reply_mv(struct smb_request *req)
6552 connection_struct *conn = req->conn;
6553 char *name = NULL;
6554 char *newname = NULL;
6555 const char *p;
6556 uint32 attrs;
6557 NTSTATUS status;
6558 bool src_has_wcard = False;
6559 bool dest_has_wcard = False;
6560 TALLOC_CTX *ctx = talloc_tos();
6561 struct smb_filename *smb_fname_src = NULL;
6562 struct smb_filename *smb_fname_dst = NULL;
6563 bool stream_rename = false;
6565 START_PROFILE(SMBmv);
6567 if (req->wct < 1) {
6568 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6569 goto out;
6572 attrs = SVAL(req->vwv+0, 0);
6574 p = (const char *)req->buf + 1;
6575 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
6576 &status, &src_has_wcard);
6577 if (!NT_STATUS_IS_OK(status)) {
6578 reply_nterror(req, status);
6579 goto out;
6581 p++;
6582 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
6583 &status, &dest_has_wcard);
6584 if (!NT_STATUS_IS_OK(status)) {
6585 reply_nterror(req, status);
6586 goto out;
6589 if (!lp_posix_pathnames()) {
6590 /* The newname must begin with a ':' if the
6591 name contains a ':'. */
6592 if (strchr_m(name, ':')) {
6593 if (newname[0] != ':') {
6594 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6595 goto out;
6597 stream_rename = true;
6601 status = filename_convert(ctx,
6602 conn,
6603 req->flags2 & FLAGS2_DFS_PATHNAMES,
6604 name,
6605 UCF_COND_ALLOW_WCARD_LCOMP,
6606 &src_has_wcard,
6607 &smb_fname_src);
6609 if (!NT_STATUS_IS_OK(status)) {
6610 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6611 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6612 ERRSRV, ERRbadpath);
6613 goto out;
6615 reply_nterror(req, status);
6616 goto out;
6619 status = filename_convert(ctx,
6620 conn,
6621 req->flags2 & FLAGS2_DFS_PATHNAMES,
6622 newname,
6623 UCF_COND_ALLOW_WCARD_LCOMP | UCF_SAVE_LCOMP,
6624 &dest_has_wcard,
6625 &smb_fname_dst);
6627 if (!NT_STATUS_IS_OK(status)) {
6628 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6629 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6630 ERRSRV, ERRbadpath);
6631 goto out;
6633 reply_nterror(req, status);
6634 goto out;
6637 if (stream_rename) {
6638 /* smb_fname_dst->base_name must be the same as
6639 smb_fname_src->base_name. */
6640 TALLOC_FREE(smb_fname_dst->base_name);
6641 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
6642 smb_fname_src->base_name);
6643 if (!smb_fname_dst->base_name) {
6644 reply_nterror(req, NT_STATUS_NO_MEMORY);
6645 goto out;
6649 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
6650 smb_fname_str_dbg(smb_fname_dst)));
6652 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
6653 attrs, False, src_has_wcard, dest_has_wcard,
6654 DELETE_ACCESS);
6655 if (!NT_STATUS_IS_OK(status)) {
6656 if (open_was_deferred(req->mid)) {
6657 /* We have re-scheduled this call. */
6658 goto out;
6660 reply_nterror(req, status);
6661 goto out;
6664 reply_outbuf(req, 0, 0);
6665 out:
6666 TALLOC_FREE(smb_fname_src);
6667 TALLOC_FREE(smb_fname_dst);
6668 END_PROFILE(SMBmv);
6669 return;
6672 /*******************************************************************
6673 Copy a file as part of a reply_copy.
6674 ******************************************************************/
6677 * TODO: check error codes on all callers
6680 NTSTATUS copy_file(TALLOC_CTX *ctx,
6681 connection_struct *conn,
6682 struct smb_filename *smb_fname_src,
6683 struct smb_filename *smb_fname_dst,
6684 int ofun,
6685 int count,
6686 bool target_is_directory)
6688 struct smb_filename *smb_fname_dst_tmp = NULL;
6689 SMB_OFF_T ret=-1;
6690 files_struct *fsp1,*fsp2;
6691 uint32 dosattrs;
6692 uint32 new_create_disposition;
6693 NTSTATUS status;
6696 status = copy_smb_filename(ctx, smb_fname_dst, &smb_fname_dst_tmp);
6697 if (!NT_STATUS_IS_OK(status)) {
6698 return status;
6702 * If the target is a directory, extract the last component from the
6703 * src filename and append it to the dst filename
6705 if (target_is_directory) {
6706 const char *p;
6708 /* dest/target can't be a stream if it's a directory. */
6709 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
6711 p = strrchr_m(smb_fname_src->base_name,'/');
6712 if (p) {
6713 p++;
6714 } else {
6715 p = smb_fname_src->base_name;
6717 smb_fname_dst_tmp->base_name =
6718 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
6720 if (!smb_fname_dst_tmp->base_name) {
6721 status = NT_STATUS_NO_MEMORY;
6722 goto out;
6726 status = vfs_file_exist(conn, smb_fname_src);
6727 if (!NT_STATUS_IS_OK(status)) {
6728 goto out;
6731 if (!target_is_directory && count) {
6732 new_create_disposition = FILE_OPEN;
6733 } else {
6734 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp, 0, ofun,
6735 NULL, NULL,
6736 &new_create_disposition,
6737 NULL,
6738 NULL)) {
6739 status = NT_STATUS_INVALID_PARAMETER;
6740 goto out;
6744 /* Open the src file for reading. */
6745 status = SMB_VFS_CREATE_FILE(
6746 conn, /* conn */
6747 NULL, /* req */
6748 0, /* root_dir_fid */
6749 smb_fname_src, /* fname */
6750 FILE_GENERIC_READ, /* access_mask */
6751 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6752 FILE_OPEN, /* create_disposition*/
6753 0, /* create_options */
6754 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
6755 INTERNAL_OPEN_ONLY, /* oplock_request */
6756 0, /* allocation_size */
6757 0, /* private_flags */
6758 NULL, /* sd */
6759 NULL, /* ea_list */
6760 &fsp1, /* result */
6761 NULL); /* psbuf */
6763 if (!NT_STATUS_IS_OK(status)) {
6764 goto out;
6767 dosattrs = dos_mode(conn, smb_fname_src);
6769 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
6770 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
6773 /* Open the dst file for writing. */
6774 status = SMB_VFS_CREATE_FILE(
6775 conn, /* conn */
6776 NULL, /* req */
6777 0, /* root_dir_fid */
6778 smb_fname_dst, /* fname */
6779 FILE_GENERIC_WRITE, /* access_mask */
6780 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6781 new_create_disposition, /* create_disposition*/
6782 0, /* create_options */
6783 dosattrs, /* file_attributes */
6784 INTERNAL_OPEN_ONLY, /* oplock_request */
6785 0, /* allocation_size */
6786 0, /* private_flags */
6787 NULL, /* sd */
6788 NULL, /* ea_list */
6789 &fsp2, /* result */
6790 NULL); /* psbuf */
6792 if (!NT_STATUS_IS_OK(status)) {
6793 close_file(NULL, fsp1, ERROR_CLOSE);
6794 goto out;
6797 if (ofun & OPENX_FILE_EXISTS_OPEN) {
6798 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
6799 if (ret == -1) {
6800 DEBUG(0, ("error - vfs lseek returned error %s\n",
6801 strerror(errno)));
6802 status = map_nt_error_from_unix(errno);
6803 close_file(NULL, fsp1, ERROR_CLOSE);
6804 close_file(NULL, fsp2, ERROR_CLOSE);
6805 goto out;
6809 /* Do the actual copy. */
6810 if (smb_fname_src->st.st_ex_size) {
6811 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
6812 } else {
6813 ret = 0;
6816 close_file(NULL, fsp1, NORMAL_CLOSE);
6818 /* Ensure the modtime is set correctly on the destination file. */
6819 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
6822 * As we are opening fsp1 read-only we only expect
6823 * an error on close on fsp2 if we are out of space.
6824 * Thus we don't look at the error return from the
6825 * close of fsp1.
6827 status = close_file(NULL, fsp2, NORMAL_CLOSE);
6829 if (!NT_STATUS_IS_OK(status)) {
6830 goto out;
6833 if (ret != (SMB_OFF_T)smb_fname_src->st.st_ex_size) {
6834 status = NT_STATUS_DISK_FULL;
6835 goto out;
6838 status = NT_STATUS_OK;
6840 out:
6841 TALLOC_FREE(smb_fname_dst_tmp);
6842 return status;
6845 /****************************************************************************
6846 Reply to a file copy.
6847 ****************************************************************************/
6849 void reply_copy(struct smb_request *req)
6851 connection_struct *conn = req->conn;
6852 struct smb_filename *smb_fname_src = NULL;
6853 struct smb_filename *smb_fname_dst = NULL;
6854 char *fname_src = NULL;
6855 char *fname_dst = NULL;
6856 char *fname_src_mask = NULL;
6857 char *fname_src_dir = NULL;
6858 const char *p;
6859 int count=0;
6860 int error = ERRnoaccess;
6861 int tid2;
6862 int ofun;
6863 int flags;
6864 bool target_is_directory=False;
6865 bool source_has_wild = False;
6866 bool dest_has_wild = False;
6867 NTSTATUS status;
6868 TALLOC_CTX *ctx = talloc_tos();
6870 START_PROFILE(SMBcopy);
6872 if (req->wct < 3) {
6873 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6874 goto out;
6877 tid2 = SVAL(req->vwv+0, 0);
6878 ofun = SVAL(req->vwv+1, 0);
6879 flags = SVAL(req->vwv+2, 0);
6881 p = (const char *)req->buf;
6882 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
6883 &status, &source_has_wild);
6884 if (!NT_STATUS_IS_OK(status)) {
6885 reply_nterror(req, status);
6886 goto out;
6888 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
6889 &status, &dest_has_wild);
6890 if (!NT_STATUS_IS_OK(status)) {
6891 reply_nterror(req, status);
6892 goto out;
6895 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
6897 if (tid2 != conn->cnum) {
6898 /* can't currently handle inter share copies XXXX */
6899 DEBUG(3,("Rejecting inter-share copy\n"));
6900 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
6901 goto out;
6904 status = filename_convert(ctx, conn,
6905 req->flags2 & FLAGS2_DFS_PATHNAMES,
6906 fname_src,
6907 UCF_COND_ALLOW_WCARD_LCOMP,
6908 &source_has_wild,
6909 &smb_fname_src);
6910 if (!NT_STATUS_IS_OK(status)) {
6911 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6912 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6913 ERRSRV, ERRbadpath);
6914 goto out;
6916 reply_nterror(req, status);
6917 goto out;
6920 status = filename_convert(ctx, conn,
6921 req->flags2 & FLAGS2_DFS_PATHNAMES,
6922 fname_dst,
6923 UCF_COND_ALLOW_WCARD_LCOMP,
6924 &dest_has_wild,
6925 &smb_fname_dst);
6926 if (!NT_STATUS_IS_OK(status)) {
6927 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6928 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6929 ERRSRV, ERRbadpath);
6930 goto out;
6932 reply_nterror(req, status);
6933 goto out;
6936 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
6938 if ((flags&1) && target_is_directory) {
6939 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
6940 goto out;
6943 if ((flags&2) && !target_is_directory) {
6944 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
6945 goto out;
6948 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
6949 /* wants a tree copy! XXXX */
6950 DEBUG(3,("Rejecting tree copy\n"));
6951 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6952 goto out;
6955 /* Split up the directory from the filename/mask. */
6956 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6957 &fname_src_dir, &fname_src_mask);
6958 if (!NT_STATUS_IS_OK(status)) {
6959 reply_nterror(req, NT_STATUS_NO_MEMORY);
6960 goto out;
6964 * We should only check the mangled cache
6965 * here if unix_convert failed. This means
6966 * that the path in 'mask' doesn't exist
6967 * on the file system and so we need to look
6968 * for a possible mangle. This patch from
6969 * Tine Smukavec <valentin.smukavec@hermes.si>.
6971 if (!VALID_STAT(smb_fname_src->st) &&
6972 mangle_is_mangled(fname_src_mask, conn->params)) {
6973 char *new_mask = NULL;
6974 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
6975 &new_mask, conn->params);
6977 /* Use demangled name if one was successfully found. */
6978 if (new_mask) {
6979 TALLOC_FREE(fname_src_mask);
6980 fname_src_mask = new_mask;
6984 if (!source_has_wild) {
6987 * Only one file needs to be copied. Append the mask back onto
6988 * the directory.
6990 TALLOC_FREE(smb_fname_src->base_name);
6991 if (ISDOT(fname_src_dir)) {
6992 /* Ensure we use canonical names on open. */
6993 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6994 "%s",
6995 fname_src_mask);
6996 } else {
6997 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6998 "%s/%s",
6999 fname_src_dir,
7000 fname_src_mask);
7002 if (!smb_fname_src->base_name) {
7003 reply_nterror(req, NT_STATUS_NO_MEMORY);
7004 goto out;
7007 if (dest_has_wild) {
7008 char *fname_dst_mod = NULL;
7009 if (!resolve_wildcards(smb_fname_dst,
7010 smb_fname_src->base_name,
7011 smb_fname_dst->base_name,
7012 &fname_dst_mod)) {
7013 reply_nterror(req, NT_STATUS_NO_MEMORY);
7014 goto out;
7016 TALLOC_FREE(smb_fname_dst->base_name);
7017 smb_fname_dst->base_name = fname_dst_mod;
7020 status = check_name(conn, smb_fname_src->base_name);
7021 if (!NT_STATUS_IS_OK(status)) {
7022 reply_nterror(req, status);
7023 goto out;
7026 status = check_name(conn, smb_fname_dst->base_name);
7027 if (!NT_STATUS_IS_OK(status)) {
7028 reply_nterror(req, status);
7029 goto out;
7032 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7033 ofun, count, target_is_directory);
7035 if(!NT_STATUS_IS_OK(status)) {
7036 reply_nterror(req, status);
7037 goto out;
7038 } else {
7039 count++;
7041 } else {
7042 struct smb_Dir *dir_hnd = NULL;
7043 const char *dname = NULL;
7044 char *talloced = NULL;
7045 long offset = 0;
7048 * There is a wildcard that requires us to actually read the
7049 * src dir and copy each file matching the mask to the dst.
7050 * Right now streams won't be copied, but this could
7051 * presumably be added with a nested loop for reach dir entry.
7053 SMB_ASSERT(!smb_fname_src->stream_name);
7054 SMB_ASSERT(!smb_fname_dst->stream_name);
7056 smb_fname_src->stream_name = NULL;
7057 smb_fname_dst->stream_name = NULL;
7059 if (strequal(fname_src_mask,"????????.???")) {
7060 TALLOC_FREE(fname_src_mask);
7061 fname_src_mask = talloc_strdup(ctx, "*");
7062 if (!fname_src_mask) {
7063 reply_nterror(req, NT_STATUS_NO_MEMORY);
7064 goto out;
7068 status = check_name(conn, fname_src_dir);
7069 if (!NT_STATUS_IS_OK(status)) {
7070 reply_nterror(req, status);
7071 goto out;
7074 dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0);
7075 if (dir_hnd == NULL) {
7076 status = map_nt_error_from_unix(errno);
7077 reply_nterror(req, status);
7078 goto out;
7081 error = ERRbadfile;
7083 /* Iterate over the src dir copying each entry to the dst. */
7084 while ((dname = ReadDirName(dir_hnd, &offset,
7085 &smb_fname_src->st, &talloced))) {
7086 char *destname = NULL;
7088 if (ISDOT(dname) || ISDOTDOT(dname)) {
7089 TALLOC_FREE(talloced);
7090 continue;
7093 if (!is_visible_file(conn, fname_src_dir, dname,
7094 &smb_fname_src->st, false)) {
7095 TALLOC_FREE(talloced);
7096 continue;
7099 if(!mask_match(dname, fname_src_mask,
7100 conn->case_sensitive)) {
7101 TALLOC_FREE(talloced);
7102 continue;
7105 error = ERRnoaccess;
7107 /* Get the src smb_fname struct setup. */
7108 TALLOC_FREE(smb_fname_src->base_name);
7109 if (ISDOT(fname_src_dir)) {
7110 /* Ensure we use canonical names on open. */
7111 smb_fname_src->base_name =
7112 talloc_asprintf(smb_fname_src, "%s",
7113 dname);
7114 } else {
7115 smb_fname_src->base_name =
7116 talloc_asprintf(smb_fname_src, "%s/%s",
7117 fname_src_dir, dname);
7120 if (!smb_fname_src->base_name) {
7121 TALLOC_FREE(dir_hnd);
7122 TALLOC_FREE(talloced);
7123 reply_nterror(req, NT_STATUS_NO_MEMORY);
7124 goto out;
7127 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7128 smb_fname_dst->base_name,
7129 &destname)) {
7130 TALLOC_FREE(talloced);
7131 continue;
7133 if (!destname) {
7134 TALLOC_FREE(dir_hnd);
7135 TALLOC_FREE(talloced);
7136 reply_nterror(req, NT_STATUS_NO_MEMORY);
7137 goto out;
7140 TALLOC_FREE(smb_fname_dst->base_name);
7141 smb_fname_dst->base_name = destname;
7143 status = check_name(conn, smb_fname_src->base_name);
7144 if (!NT_STATUS_IS_OK(status)) {
7145 TALLOC_FREE(dir_hnd);
7146 TALLOC_FREE(talloced);
7147 reply_nterror(req, status);
7148 goto out;
7151 status = check_name(conn, smb_fname_dst->base_name);
7152 if (!NT_STATUS_IS_OK(status)) {
7153 TALLOC_FREE(dir_hnd);
7154 TALLOC_FREE(talloced);
7155 reply_nterror(req, status);
7156 goto out;
7159 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7160 smb_fname_src->base_name,
7161 smb_fname_dst->base_name));
7163 status = copy_file(ctx, conn, smb_fname_src,
7164 smb_fname_dst, ofun, count,
7165 target_is_directory);
7166 if (NT_STATUS_IS_OK(status)) {
7167 count++;
7170 TALLOC_FREE(talloced);
7172 TALLOC_FREE(dir_hnd);
7175 if (count == 0) {
7176 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7177 goto out;
7180 reply_outbuf(req, 1, 0);
7181 SSVAL(req->outbuf,smb_vwv0,count);
7182 out:
7183 TALLOC_FREE(smb_fname_src);
7184 TALLOC_FREE(smb_fname_dst);
7185 TALLOC_FREE(fname_src);
7186 TALLOC_FREE(fname_dst);
7187 TALLOC_FREE(fname_src_mask);
7188 TALLOC_FREE(fname_src_dir);
7190 END_PROFILE(SMBcopy);
7191 return;
7194 #undef DBGC_CLASS
7195 #define DBGC_CLASS DBGC_LOCKING
7197 /****************************************************************************
7198 Get a lock pid, dealing with large count requests.
7199 ****************************************************************************/
7201 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7202 bool large_file_format)
7204 if(!large_file_format)
7205 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7206 else
7207 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7210 /****************************************************************************
7211 Get a lock count, dealing with large count requests.
7212 ****************************************************************************/
7214 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7215 bool large_file_format)
7217 uint64_t count = 0;
7219 if(!large_file_format) {
7220 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7221 } else {
7223 #if defined(HAVE_LONGLONG)
7224 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7225 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7226 #else /* HAVE_LONGLONG */
7229 * NT4.x seems to be broken in that it sends large file (64 bit)
7230 * lockingX calls even if the CAP_LARGE_FILES was *not*
7231 * negotiated. For boxes without large unsigned ints truncate the
7232 * lock count by dropping the top 32 bits.
7235 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
7236 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
7237 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
7238 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
7239 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
7242 count = (uint64_t)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
7243 #endif /* HAVE_LONGLONG */
7246 return count;
7249 #if !defined(HAVE_LONGLONG)
7250 /****************************************************************************
7251 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
7252 ****************************************************************************/
7254 static uint32 map_lock_offset(uint32 high, uint32 low)
7256 unsigned int i;
7257 uint32 mask = 0;
7258 uint32 highcopy = high;
7261 * Try and find out how many significant bits there are in high.
7264 for(i = 0; highcopy; i++)
7265 highcopy >>= 1;
7268 * We use 31 bits not 32 here as POSIX
7269 * lock offsets may not be negative.
7272 mask = (~0) << (31 - i);
7274 if(low & mask)
7275 return 0; /* Fail. */
7277 high <<= (31 - i);
7279 return (high|low);
7281 #endif /* !defined(HAVE_LONGLONG) */
7283 /****************************************************************************
7284 Get a lock offset, dealing with large offset requests.
7285 ****************************************************************************/
7287 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7288 bool large_file_format, bool *err)
7290 uint64_t offset = 0;
7292 *err = False;
7294 if(!large_file_format) {
7295 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7296 } else {
7298 #if defined(HAVE_LONGLONG)
7299 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7300 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7301 #else /* HAVE_LONGLONG */
7304 * NT4.x seems to be broken in that it sends large file (64 bit)
7305 * lockingX calls even if the CAP_LARGE_FILES was *not*
7306 * negotiated. For boxes without large unsigned ints mangle the
7307 * lock offset by mapping the top 32 bits onto the lower 32.
7310 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
7311 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7312 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
7313 uint32 new_low = 0;
7315 if((new_low = map_lock_offset(high, low)) == 0) {
7316 *err = True;
7317 return (uint64_t)-1;
7320 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
7321 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
7322 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
7323 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
7326 offset = (uint64_t)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7327 #endif /* HAVE_LONGLONG */
7330 return offset;
7333 NTSTATUS smbd_do_locking(struct smb_request *req,
7334 files_struct *fsp,
7335 uint8_t type,
7336 int32_t timeout,
7337 uint16_t num_ulocks,
7338 struct smbd_lock_element *ulocks,
7339 uint16_t num_locks,
7340 struct smbd_lock_element *locks,
7341 bool *async)
7343 connection_struct *conn = req->conn;
7344 int i;
7345 NTSTATUS status = NT_STATUS_OK;
7347 *async = false;
7349 /* Data now points at the beginning of the list
7350 of smb_unlkrng structs */
7351 for(i = 0; i < (int)num_ulocks; i++) {
7352 struct smbd_lock_element *e = &ulocks[i];
7354 DEBUG(10,("smbd_do_locking: unlock start=%.0f, len=%.0f for "
7355 "pid %u, file %s\n",
7356 (double)e->offset,
7357 (double)e->count,
7358 (unsigned int)e->smblctx,
7359 fsp_str_dbg(fsp)));
7361 if (e->brltype != UNLOCK_LOCK) {
7362 /* this can only happen with SMB2 */
7363 return NT_STATUS_INVALID_PARAMETER;
7366 status = do_unlock(req->sconn->msg_ctx,
7367 fsp,
7368 e->smblctx,
7369 e->count,
7370 e->offset,
7371 WINDOWS_LOCK);
7373 DEBUG(10, ("smbd_do_locking: unlock returned %s\n",
7374 nt_errstr(status)));
7376 if (!NT_STATUS_IS_OK(status)) {
7377 return status;
7381 /* Setup the timeout in seconds. */
7383 if (!lp_blocking_locks(SNUM(conn))) {
7384 timeout = 0;
7387 /* Data now points at the beginning of the list
7388 of smb_lkrng structs */
7390 for(i = 0; i < (int)num_locks; i++) {
7391 struct smbd_lock_element *e = &locks[i];
7393 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
7394 "%llu, file %s timeout = %d\n",
7395 (double)e->offset,
7396 (double)e->count,
7397 (unsigned long long)e->smblctx,
7398 fsp_str_dbg(fsp),
7399 (int)timeout));
7401 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7402 struct blocking_lock_record *blr = NULL;
7404 if (num_locks > 1) {
7406 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
7407 * if the lock vector contains one entry. When given mutliple cancel
7408 * requests in a single PDU we expect the server to return an
7409 * error. Windows servers seem to accept the request but only
7410 * cancel the first lock.
7411 * JRA - Do what Windows does (tm) :-).
7414 #if 0
7415 /* MS-CIFS (2.2.4.32.1) behavior. */
7416 return NT_STATUS_DOS(ERRDOS,
7417 ERRcancelviolation);
7418 #else
7419 /* Windows behavior. */
7420 if (i != 0) {
7421 DEBUG(10,("smbd_do_locking: ignoring subsequent "
7422 "cancel request\n"));
7423 continue;
7425 #endif
7428 if (lp_blocking_locks(SNUM(conn))) {
7430 /* Schedule a message to ourselves to
7431 remove the blocking lock record and
7432 return the right error. */
7434 blr = blocking_lock_cancel_smb1(fsp,
7435 e->smblctx,
7436 e->offset,
7437 e->count,
7438 WINDOWS_LOCK,
7439 type,
7440 NT_STATUS_FILE_LOCK_CONFLICT);
7441 if (blr == NULL) {
7442 return NT_STATUS_DOS(
7443 ERRDOS,
7444 ERRcancelviolation);
7447 /* Remove a matching pending lock. */
7448 status = do_lock_cancel(fsp,
7449 e->smblctx,
7450 e->count,
7451 e->offset,
7452 WINDOWS_LOCK,
7453 blr);
7454 } else {
7455 bool blocking_lock = timeout ? true : false;
7456 bool defer_lock = false;
7457 struct byte_range_lock *br_lck;
7458 uint64_t block_smblctx;
7460 br_lck = do_lock(req->sconn->msg_ctx,
7461 fsp,
7462 e->smblctx,
7463 e->count,
7464 e->offset,
7465 e->brltype,
7466 WINDOWS_LOCK,
7467 blocking_lock,
7468 &status,
7469 &block_smblctx,
7470 NULL);
7472 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
7473 /* Windows internal resolution for blocking locks seems
7474 to be about 200ms... Don't wait for less than that. JRA. */
7475 if (timeout != -1 && timeout < lp_lock_spin_time()) {
7476 timeout = lp_lock_spin_time();
7478 defer_lock = true;
7481 /* If a lock sent with timeout of zero would fail, and
7482 * this lock has been requested multiple times,
7483 * according to brl_lock_failed() we convert this
7484 * request to a blocking lock with a timeout of between
7485 * 150 - 300 milliseconds.
7487 * If lp_lock_spin_time() has been set to 0, we skip
7488 * this blocking retry and fail immediately.
7490 * Replacement for do_lock_spin(). JRA. */
7492 if (!req->sconn->using_smb2 &&
7493 br_lck && lp_blocking_locks(SNUM(conn)) &&
7494 lp_lock_spin_time() && !blocking_lock &&
7495 NT_STATUS_EQUAL((status),
7496 NT_STATUS_FILE_LOCK_CONFLICT))
7498 defer_lock = true;
7499 timeout = lp_lock_spin_time();
7502 if (br_lck && defer_lock) {
7504 * A blocking lock was requested. Package up
7505 * this smb into a queued request and push it
7506 * onto the blocking lock queue.
7508 if(push_blocking_lock_request(br_lck,
7509 req,
7510 fsp,
7511 timeout,
7513 e->smblctx,
7514 e->brltype,
7515 WINDOWS_LOCK,
7516 e->offset,
7517 e->count,
7518 block_smblctx)) {
7519 TALLOC_FREE(br_lck);
7520 *async = true;
7521 return NT_STATUS_OK;
7525 TALLOC_FREE(br_lck);
7528 if (!NT_STATUS_IS_OK(status)) {
7529 break;
7533 /* If any of the above locks failed, then we must unlock
7534 all of the previous locks (X/Open spec). */
7536 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
7538 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7539 i = -1; /* we want to skip the for loop */
7543 * Ensure we don't do a remove on the lock that just failed,
7544 * as under POSIX rules, if we have a lock already there, we
7545 * will delete it (and we shouldn't) .....
7547 for(i--; i >= 0; i--) {
7548 struct smbd_lock_element *e = &locks[i];
7550 do_unlock(req->sconn->msg_ctx,
7551 fsp,
7552 e->smblctx,
7553 e->count,
7554 e->offset,
7555 WINDOWS_LOCK);
7557 return status;
7560 DEBUG(3, ("smbd_do_locking: fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
7561 fsp->fnum, (unsigned int)type, num_locks, num_ulocks));
7563 return NT_STATUS_OK;
7566 /****************************************************************************
7567 Reply to a lockingX request.
7568 ****************************************************************************/
7570 void reply_lockingX(struct smb_request *req)
7572 connection_struct *conn = req->conn;
7573 files_struct *fsp;
7574 unsigned char locktype;
7575 unsigned char oplocklevel;
7576 uint16 num_ulocks;
7577 uint16 num_locks;
7578 int32 lock_timeout;
7579 int i;
7580 const uint8_t *data;
7581 bool large_file_format;
7582 bool err;
7583 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
7584 struct smbd_lock_element *ulocks;
7585 struct smbd_lock_element *locks;
7586 bool async = false;
7588 START_PROFILE(SMBlockingX);
7590 if (req->wct < 8) {
7591 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7592 END_PROFILE(SMBlockingX);
7593 return;
7596 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
7597 locktype = CVAL(req->vwv+3, 0);
7598 oplocklevel = CVAL(req->vwv+3, 1);
7599 num_ulocks = SVAL(req->vwv+6, 0);
7600 num_locks = SVAL(req->vwv+7, 0);
7601 lock_timeout = IVAL(req->vwv+4, 0);
7602 large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
7604 if (!check_fsp(conn, req, fsp)) {
7605 END_PROFILE(SMBlockingX);
7606 return;
7609 data = req->buf;
7611 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
7612 /* we don't support these - and CANCEL_LOCK makes w2k
7613 and XP reboot so I don't really want to be
7614 compatible! (tridge) */
7615 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
7616 END_PROFILE(SMBlockingX);
7617 return;
7620 /* Check if this is an oplock break on a file
7621 we have granted an oplock on.
7623 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
7624 /* Client can insist on breaking to none. */
7625 bool break_to_none = (oplocklevel == 0);
7626 bool result;
7628 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
7629 "for fnum = %d\n", (unsigned int)oplocklevel,
7630 fsp->fnum ));
7633 * Make sure we have granted an exclusive or batch oplock on
7634 * this file.
7637 if (fsp->oplock_type == 0) {
7639 /* The Samba4 nbench simulator doesn't understand
7640 the difference between break to level2 and break
7641 to none from level2 - it sends oplock break
7642 replies in both cases. Don't keep logging an error
7643 message here - just ignore it. JRA. */
7645 DEBUG(5,("reply_lockingX: Error : oplock break from "
7646 "client for fnum = %d (oplock=%d) and no "
7647 "oplock granted on this file (%s).\n",
7648 fsp->fnum, fsp->oplock_type,
7649 fsp_str_dbg(fsp)));
7651 /* if this is a pure oplock break request then don't
7652 * send a reply */
7653 if (num_locks == 0 && num_ulocks == 0) {
7654 END_PROFILE(SMBlockingX);
7655 return;
7656 } else {
7657 END_PROFILE(SMBlockingX);
7658 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
7659 return;
7663 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
7664 (break_to_none)) {
7665 result = remove_oplock(fsp);
7666 } else {
7667 result = downgrade_oplock(fsp);
7670 if (!result) {
7671 DEBUG(0, ("reply_lockingX: error in removing "
7672 "oplock on file %s\n", fsp_str_dbg(fsp)));
7673 /* Hmmm. Is this panic justified? */
7674 smb_panic("internal tdb error");
7677 reply_to_oplock_break_requests(fsp);
7679 /* if this is a pure oplock break request then don't send a
7680 * reply */
7681 if (num_locks == 0 && num_ulocks == 0) {
7682 /* Sanity check - ensure a pure oplock break is not a
7683 chained request. */
7684 if(CVAL(req->vwv+0, 0) != 0xff)
7685 DEBUG(0,("reply_lockingX: Error : pure oplock "
7686 "break is a chained %d request !\n",
7687 (unsigned int)CVAL(req->vwv+0, 0)));
7688 END_PROFILE(SMBlockingX);
7689 return;
7693 if (req->buflen <
7694 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
7695 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7696 END_PROFILE(SMBlockingX);
7697 return;
7700 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
7701 if (ulocks == NULL) {
7702 reply_nterror(req, NT_STATUS_NO_MEMORY);
7703 END_PROFILE(SMBlockingX);
7704 return;
7707 locks = talloc_array(req, struct smbd_lock_element, num_locks);
7708 if (locks == NULL) {
7709 reply_nterror(req, NT_STATUS_NO_MEMORY);
7710 END_PROFILE(SMBlockingX);
7711 return;
7714 /* Data now points at the beginning of the list
7715 of smb_unlkrng structs */
7716 for(i = 0; i < (int)num_ulocks; i++) {
7717 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
7718 ulocks[i].count = get_lock_count(data, i, large_file_format);
7719 ulocks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7720 ulocks[i].brltype = UNLOCK_LOCK;
7723 * There is no error code marked "stupid client bug".... :-).
7725 if(err) {
7726 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7727 END_PROFILE(SMBlockingX);
7728 return;
7732 /* Now do any requested locks */
7733 data += ((large_file_format ? 20 : 10)*num_ulocks);
7735 /* Data now points at the beginning of the list
7736 of smb_lkrng structs */
7738 for(i = 0; i < (int)num_locks; i++) {
7739 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
7740 locks[i].count = get_lock_count(data, i, large_file_format);
7741 locks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7743 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
7744 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7745 locks[i].brltype = PENDING_READ_LOCK;
7746 } else {
7747 locks[i].brltype = READ_LOCK;
7749 } else {
7750 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7751 locks[i].brltype = PENDING_WRITE_LOCK;
7752 } else {
7753 locks[i].brltype = WRITE_LOCK;
7758 * There is no error code marked "stupid client bug".... :-).
7760 if(err) {
7761 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7762 END_PROFILE(SMBlockingX);
7763 return;
7767 status = smbd_do_locking(req, fsp,
7768 locktype, lock_timeout,
7769 num_ulocks, ulocks,
7770 num_locks, locks,
7771 &async);
7772 if (!NT_STATUS_IS_OK(status)) {
7773 END_PROFILE(SMBlockingX);
7774 reply_nterror(req, status);
7775 return;
7777 if (async) {
7778 END_PROFILE(SMBlockingX);
7779 return;
7782 reply_outbuf(req, 2, 0);
7784 DEBUG(3, ("lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
7785 fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks));
7787 END_PROFILE(SMBlockingX);
7788 chain_reply(req);
7791 #undef DBGC_CLASS
7792 #define DBGC_CLASS DBGC_ALL
7794 /****************************************************************************
7795 Reply to a SMBreadbmpx (read block multiplex) request.
7796 Always reply with an error, if someone has a platform really needs this,
7797 please contact vl@samba.org
7798 ****************************************************************************/
7800 void reply_readbmpx(struct smb_request *req)
7802 START_PROFILE(SMBreadBmpx);
7803 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7804 END_PROFILE(SMBreadBmpx);
7805 return;
7808 /****************************************************************************
7809 Reply to a SMBreadbs (read block multiplex secondary) request.
7810 Always reply with an error, if someone has a platform really needs this,
7811 please contact vl@samba.org
7812 ****************************************************************************/
7814 void reply_readbs(struct smb_request *req)
7816 START_PROFILE(SMBreadBs);
7817 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7818 END_PROFILE(SMBreadBs);
7819 return;
7822 /****************************************************************************
7823 Reply to a SMBsetattrE.
7824 ****************************************************************************/
7826 void reply_setattrE(struct smb_request *req)
7828 connection_struct *conn = req->conn;
7829 struct smb_file_time ft;
7830 files_struct *fsp;
7831 NTSTATUS status;
7833 START_PROFILE(SMBsetattrE);
7834 ZERO_STRUCT(ft);
7836 if (req->wct < 7) {
7837 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7838 goto out;
7841 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
7843 if(!fsp || (fsp->conn != conn)) {
7844 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
7845 goto out;
7849 * Convert the DOS times into unix times.
7852 ft.atime = convert_time_t_to_timespec(
7853 srv_make_unix_date2(req->vwv+3));
7854 ft.mtime = convert_time_t_to_timespec(
7855 srv_make_unix_date2(req->vwv+5));
7856 ft.create_time = convert_time_t_to_timespec(
7857 srv_make_unix_date2(req->vwv+1));
7859 reply_outbuf(req, 0, 0);
7862 * Patch from Ray Frush <frush@engr.colostate.edu>
7863 * Sometimes times are sent as zero - ignore them.
7866 /* Ensure we have a valid stat struct for the source. */
7867 status = vfs_stat_fsp(fsp);
7868 if (!NT_STATUS_IS_OK(status)) {
7869 reply_nterror(req, status);
7870 goto out;
7873 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
7874 if (!NT_STATUS_IS_OK(status)) {
7875 reply_nterror(req, status);
7876 goto out;
7879 DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u "
7880 " createtime=%u\n",
7881 fsp->fnum,
7882 (unsigned int)ft.atime.tv_sec,
7883 (unsigned int)ft.mtime.tv_sec,
7884 (unsigned int)ft.create_time.tv_sec
7886 out:
7887 END_PROFILE(SMBsetattrE);
7888 return;
7892 /* Back from the dead for OS/2..... JRA. */
7894 /****************************************************************************
7895 Reply to a SMBwritebmpx (write block multiplex primary) request.
7896 Always reply with an error, if someone has a platform really needs this,
7897 please contact vl@samba.org
7898 ****************************************************************************/
7900 void reply_writebmpx(struct smb_request *req)
7902 START_PROFILE(SMBwriteBmpx);
7903 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7904 END_PROFILE(SMBwriteBmpx);
7905 return;
7908 /****************************************************************************
7909 Reply to a SMBwritebs (write block multiplex secondary) request.
7910 Always reply with an error, if someone has a platform really needs this,
7911 please contact vl@samba.org
7912 ****************************************************************************/
7914 void reply_writebs(struct smb_request *req)
7916 START_PROFILE(SMBwriteBs);
7917 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7918 END_PROFILE(SMBwriteBs);
7919 return;
7922 /****************************************************************************
7923 Reply to a SMBgetattrE.
7924 ****************************************************************************/
7926 void reply_getattrE(struct smb_request *req)
7928 connection_struct *conn = req->conn;
7929 int mode;
7930 files_struct *fsp;
7931 struct timespec create_ts;
7933 START_PROFILE(SMBgetattrE);
7935 if (req->wct < 1) {
7936 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7937 END_PROFILE(SMBgetattrE);
7938 return;
7941 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
7943 if(!fsp || (fsp->conn != conn)) {
7944 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
7945 END_PROFILE(SMBgetattrE);
7946 return;
7949 /* Do an fstat on this file */
7950 if(fsp_stat(fsp)) {
7951 reply_nterror(req, map_nt_error_from_unix(errno));
7952 END_PROFILE(SMBgetattrE);
7953 return;
7956 mode = dos_mode(conn, fsp->fsp_name);
7959 * Convert the times into dos times. Set create
7960 * date to be last modify date as UNIX doesn't save
7961 * this.
7964 reply_outbuf(req, 11, 0);
7966 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
7967 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
7968 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
7969 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
7970 /* Should we check pending modtime here ? JRA */
7971 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
7972 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
7974 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
7975 SIVAL(req->outbuf, smb_vwv6, 0);
7976 SIVAL(req->outbuf, smb_vwv8, 0);
7977 } else {
7978 uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
7979 SIVAL(req->outbuf, smb_vwv6, (uint32)fsp->fsp_name->st.st_ex_size);
7980 SIVAL(req->outbuf, smb_vwv8, allocation_size);
7982 SSVAL(req->outbuf,smb_vwv10, mode);
7984 DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
7986 END_PROFILE(SMBgetattrE);
7987 return;