libcli/smb: fix padding in smb2_create_blob*
[Samba/gebeck_regimport.git] / source3 / smbd / reply.c
blob1b4a1620d6c6bc6240eb8e7e01fe60389cc5acda
1 /*
2 Unix SMB/CIFS implementation.
3 Main SMB reply routines
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Andrew Bartlett 2001
6 Copyright (C) Jeremy Allison 1992-2007.
7 Copyright (C) Volker Lendecke 2007
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 This file handles most of the reply_ calls that the server
24 makes to handle specific protocols
27 #include "includes.h"
28 #include "system/filesys.h"
29 #include "printing.h"
30 #include "smbd/smbd.h"
31 #include "smbd/globals.h"
32 #include "fake_file.h"
33 #include "rpc_client/rpc_client.h"
34 #include "../librpc/gen_ndr/ndr_spoolss_c.h"
35 #include "../librpc/gen_ndr/open_files.h"
36 #include "rpc_client/cli_spoolss.h"
37 #include "rpc_client/init_spoolss.h"
38 #include "rpc_server/rpc_ncacn_np.h"
39 #include "libcli/security/security.h"
40 #include "libsmb/nmblib.h"
41 #include "auth.h"
42 #include "smbprofile.h"
43 #include "../lib/tsocket/tsocket.h"
44 #include "lib/tevent_wait.h"
45 #include "libcli/smb/smb_signing.h"
47 /****************************************************************************
48 Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
49 path or anything including wildcards.
50 We're assuming here that '/' is not the second byte in any multibyte char
51 set (a safe assumption). '\\' *may* be the second byte in a multibyte char
52 set.
53 ****************************************************************************/
55 /* Custom version for processing POSIX paths. */
56 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
58 static NTSTATUS check_path_syntax_internal(char *path,
59 bool posix_path,
60 bool *p_last_component_contains_wcard)
62 char *d = path;
63 const char *s = path;
64 NTSTATUS ret = NT_STATUS_OK;
65 bool start_of_name_component = True;
66 bool stream_started = false;
68 *p_last_component_contains_wcard = False;
70 while (*s) {
71 if (stream_started) {
72 switch (*s) {
73 case '/':
74 case '\\':
75 return NT_STATUS_OBJECT_NAME_INVALID;
76 case ':':
77 if (s[1] == '\0') {
78 return NT_STATUS_OBJECT_NAME_INVALID;
80 if (strchr_m(&s[1], ':')) {
81 return NT_STATUS_OBJECT_NAME_INVALID;
83 break;
87 if ((*s == ':') && !posix_path && !stream_started) {
88 if (*p_last_component_contains_wcard) {
89 return NT_STATUS_OBJECT_NAME_INVALID;
91 /* Stream names allow more characters than file names.
92 We're overloading posix_path here to allow a wider
93 range of characters. If stream_started is true this
94 is still a Windows path even if posix_path is true.
95 JRA.
97 stream_started = true;
98 start_of_name_component = false;
99 posix_path = true;
101 if (s[1] == '\0') {
102 return NT_STATUS_OBJECT_NAME_INVALID;
106 if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
108 * Safe to assume is not the second part of a mb char
109 * as this is handled below.
111 /* Eat multiple '/' or '\\' */
112 while (IS_PATH_SEP(*s,posix_path)) {
113 s++;
115 if ((d != path) && (*s != '\0')) {
116 /* We only care about non-leading or trailing '/' or '\\' */
117 *d++ = '/';
120 start_of_name_component = True;
121 /* New component. */
122 *p_last_component_contains_wcard = False;
123 continue;
126 if (start_of_name_component) {
127 if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
128 /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
131 * No mb char starts with '.' so we're safe checking the directory separator here.
134 /* If we just added a '/' - delete it */
135 if ((d > path) && (*(d-1) == '/')) {
136 *(d-1) = '\0';
137 d--;
140 /* Are we at the start ? Can't go back further if so. */
141 if (d <= path) {
142 ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
143 break;
145 /* Go back one level... */
146 /* We know this is safe as '/' cannot be part of a mb sequence. */
147 /* NOTE - if this assumption is invalid we are not in good shape... */
148 /* Decrement d first as d points to the *next* char to write into. */
149 for (d--; d > path; d--) {
150 if (*d == '/')
151 break;
153 s += 2; /* Else go past the .. */
154 /* We're still at the start of a name component, just the previous one. */
155 continue;
157 } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
158 if (posix_path) {
159 /* Eat the '.' */
160 s++;
161 continue;
167 if (!(*s & 0x80)) {
168 if (!posix_path) {
169 if (*s <= 0x1f || *s == '|') {
170 return NT_STATUS_OBJECT_NAME_INVALID;
172 switch (*s) {
173 case '*':
174 case '?':
175 case '<':
176 case '>':
177 case '"':
178 *p_last_component_contains_wcard = True;
179 break;
180 default:
181 break;
184 *d++ = *s++;
185 } else {
186 size_t siz;
187 /* Get the size of the next MB character. */
188 next_codepoint(s,&siz);
189 switch(siz) {
190 case 5:
191 *d++ = *s++;
192 /*fall through*/
193 case 4:
194 *d++ = *s++;
195 /*fall through*/
196 case 3:
197 *d++ = *s++;
198 /*fall through*/
199 case 2:
200 *d++ = *s++;
201 /*fall through*/
202 case 1:
203 *d++ = *s++;
204 break;
205 default:
206 DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
207 *d = '\0';
208 return NT_STATUS_INVALID_PARAMETER;
211 start_of_name_component = False;
214 *d = '\0';
216 return ret;
219 /****************************************************************************
220 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
221 No wildcards allowed.
222 ****************************************************************************/
224 NTSTATUS check_path_syntax(char *path)
226 bool ignore;
227 return check_path_syntax_internal(path, False, &ignore);
230 /****************************************************************************
231 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
232 Wildcards allowed - p_contains_wcard returns true if the last component contained
233 a wildcard.
234 ****************************************************************************/
236 NTSTATUS check_path_syntax_wcard(char *path, bool *p_contains_wcard)
238 return check_path_syntax_internal(path, False, p_contains_wcard);
241 /****************************************************************************
242 Check the path for a POSIX client.
243 We're assuming here that '/' is not the second byte in any multibyte char
244 set (a safe assumption).
245 ****************************************************************************/
247 NTSTATUS check_path_syntax_posix(char *path)
249 bool ignore;
250 return check_path_syntax_internal(path, True, &ignore);
253 /****************************************************************************
254 Pull a string and check the path allowing a wilcard - provide for error return.
255 ****************************************************************************/
257 size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
258 const char *base_ptr,
259 uint16 smb_flags2,
260 char **pp_dest,
261 const char *src,
262 size_t src_len,
263 int flags,
264 NTSTATUS *err,
265 bool *contains_wcard)
267 size_t ret;
269 *pp_dest = NULL;
271 ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
272 src_len, flags);
274 if (!*pp_dest) {
275 *err = NT_STATUS_INVALID_PARAMETER;
276 return ret;
279 *contains_wcard = False;
281 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
283 * For a DFS path the function parse_dfs_path()
284 * will do the path processing, just make a copy.
286 *err = NT_STATUS_OK;
287 return ret;
290 if (lp_posix_pathnames()) {
291 *err = check_path_syntax_posix(*pp_dest);
292 } else {
293 *err = check_path_syntax_wcard(*pp_dest, contains_wcard);
296 return ret;
299 /****************************************************************************
300 Pull a string and check the path - provide for error return.
301 ****************************************************************************/
303 size_t srvstr_get_path(TALLOC_CTX *ctx,
304 const char *base_ptr,
305 uint16 smb_flags2,
306 char **pp_dest,
307 const char *src,
308 size_t src_len,
309 int flags,
310 NTSTATUS *err)
312 bool ignore;
313 return srvstr_get_path_wcard(ctx, base_ptr, smb_flags2, pp_dest, src,
314 src_len, flags, err, &ignore);
317 size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req,
318 char **pp_dest, const char *src, int flags,
319 NTSTATUS *err, bool *contains_wcard)
321 return srvstr_get_path_wcard(mem_ctx, (const char *)req->inbuf, req->flags2,
322 pp_dest, src, smbreq_bufrem(req, src),
323 flags, err, contains_wcard);
326 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
327 char **pp_dest, const char *src, int flags,
328 NTSTATUS *err)
330 bool ignore;
331 return srvstr_get_path_req_wcard(mem_ctx, req, pp_dest, src,
332 flags, err, &ignore);
335 /****************************************************************************
336 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
337 ****************************************************************************/
339 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
340 files_struct *fsp)
342 if ((fsp == NULL) || (conn == NULL)) {
343 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
344 return False;
346 if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
347 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
348 return False;
350 return True;
353 /****************************************************************************
354 Check if we have a correct fsp pointing to a file.
355 ****************************************************************************/
357 bool check_fsp(connection_struct *conn, struct smb_request *req,
358 files_struct *fsp)
360 if (!check_fsp_open(conn, req, fsp)) {
361 return False;
363 if (fsp->is_directory) {
364 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
365 return False;
367 if (fsp->fh->fd == -1) {
368 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
369 return False;
371 fsp->num_smb_operations++;
372 return True;
375 /****************************************************************************
376 Check if we have a correct fsp pointing to a quota fake file. Replacement for
377 the CHECK_NTQUOTA_HANDLE_OK macro.
378 ****************************************************************************/
380 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
381 files_struct *fsp)
383 if (!check_fsp_open(conn, req, fsp)) {
384 return false;
387 if (fsp->is_directory) {
388 return false;
391 if (fsp->fake_file_handle == NULL) {
392 return false;
395 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
396 return false;
399 if (fsp->fake_file_handle->private_data == NULL) {
400 return false;
403 return true;
406 static bool netbios_session_retarget(struct smbd_server_connection *sconn,
407 const char *name, int name_type)
409 char *trim_name;
410 char *trim_name_type;
411 const char *retarget_parm;
412 char *retarget;
413 char *p;
414 int retarget_type = 0x20;
415 int retarget_port = NBT_SMB_PORT;
416 struct sockaddr_storage retarget_addr;
417 struct sockaddr_in *in_addr;
418 bool ret = false;
419 uint8_t outbuf[10];
421 if (get_socket_port(sconn->sock) != NBT_SMB_PORT) {
422 return false;
425 trim_name = talloc_strdup(talloc_tos(), name);
426 if (trim_name == NULL) {
427 goto fail;
429 trim_char(trim_name, ' ', ' ');
431 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
432 name_type);
433 if (trim_name_type == NULL) {
434 goto fail;
437 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
438 trim_name_type, NULL);
439 if (retarget_parm == NULL) {
440 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
441 trim_name, NULL);
443 if (retarget_parm == NULL) {
444 goto fail;
447 retarget = talloc_strdup(trim_name, retarget_parm);
448 if (retarget == NULL) {
449 goto fail;
452 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
454 p = strchr(retarget, ':');
455 if (p != NULL) {
456 *p++ = '\0';
457 retarget_port = atoi(p);
460 p = strchr_m(retarget, '#');
461 if (p != NULL) {
462 *p++ = '\0';
463 if (sscanf(p, "%x", &retarget_type) != 1) {
464 goto fail;
468 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
469 if (!ret) {
470 DEBUG(10, ("could not resolve %s\n", retarget));
471 goto fail;
474 if (retarget_addr.ss_family != AF_INET) {
475 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
476 goto fail;
479 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
481 _smb_setlen(outbuf, 6);
482 SCVAL(outbuf, 0, 0x84);
483 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
484 *(uint16_t *)(outbuf+8) = htons(retarget_port);
486 if (!srv_send_smb(sconn, (char *)outbuf, false, 0, false,
487 NULL)) {
488 exit_server_cleanly("netbios_session_retarget: srv_send_smb "
489 "failed.");
492 ret = true;
493 fail:
494 TALLOC_FREE(trim_name);
495 return ret;
498 static void reply_called_name_not_present(char *outbuf)
500 smb_setlen(outbuf, 1);
501 SCVAL(outbuf, 0, 0x83);
502 SCVAL(outbuf, 4, 0x82);
505 /****************************************************************************
506 Reply to a (netbios-level) special message.
507 ****************************************************************************/
509 void reply_special(struct smbd_server_connection *sconn, char *inbuf, size_t inbuf_size)
511 int msg_type = CVAL(inbuf,0);
512 int msg_flags = CVAL(inbuf,1);
514 * We only really use 4 bytes of the outbuf, but for the smb_setlen
515 * calculation & friends (srv_send_smb uses that) we need the full smb
516 * header.
518 char outbuf[smb_size];
520 memset(outbuf, '\0', sizeof(outbuf));
522 smb_setlen(outbuf,0);
524 switch (msg_type) {
525 case NBSSrequest: /* session request */
527 /* inbuf_size is guarenteed to be at least 4. */
528 fstring name1,name2;
529 int name_type1, name_type2;
530 int name_len1, name_len2;
532 *name1 = *name2 = 0;
534 if (sconn->nbt.got_session) {
535 exit_server_cleanly("multiple session request not permitted");
538 SCVAL(outbuf,0,NBSSpositive);
539 SCVAL(outbuf,3,0);
541 /* inbuf_size is guaranteed to be at least 4. */
542 name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
543 if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
544 DEBUG(0,("Invalid name length in session request\n"));
545 reply_called_name_not_present(outbuf);
546 break;
548 name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
549 if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
550 DEBUG(0,("Invalid name length in session request\n"));
551 reply_called_name_not_present(outbuf);
552 break;
555 name_type1 = name_extract((unsigned char *)inbuf,
556 inbuf_size,(unsigned int)4,name1);
557 name_type2 = name_extract((unsigned char *)inbuf,
558 inbuf_size,(unsigned int)(4 + name_len1),name2);
560 if (name_type1 == -1 || name_type2 == -1) {
561 DEBUG(0,("Invalid name type in session request\n"));
562 reply_called_name_not_present(outbuf);
563 break;
566 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
567 name1, name_type1, name2, name_type2));
569 if (netbios_session_retarget(sconn, name1, name_type1)) {
570 exit_server_cleanly("retargeted client");
574 * Windows NT/2k uses "*SMBSERVER" and XP uses
575 * "*SMBSERV" arrggg!!!
577 if (strequal(name1, "*SMBSERVER ")
578 || strequal(name1, "*SMBSERV ")) {
579 char *raddr;
581 raddr = tsocket_address_inet_addr_string(sconn->remote_address,
582 talloc_tos());
583 if (raddr == NULL) {
584 exit_server_cleanly("could not allocate raddr");
587 fstrcpy(name1, raddr);
590 set_local_machine_name(name1, True);
591 set_remote_machine_name(name2, True);
593 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
594 get_local_machine_name(), get_remote_machine_name(),
595 name_type2));
597 if (name_type2 == 'R') {
598 /* We are being asked for a pathworks session ---
599 no thanks! */
600 reply_called_name_not_present(outbuf);
601 break;
604 reload_services(sconn, conn_snum_used, true);
605 reopen_logs();
607 sconn->nbt.got_session = true;
608 break;
611 case 0x89: /* session keepalive request
612 (some old clients produce this?) */
613 SCVAL(outbuf,0,NBSSkeepalive);
614 SCVAL(outbuf,3,0);
615 break;
617 case NBSSpositive: /* positive session response */
618 case NBSSnegative: /* negative session response */
619 case NBSSretarget: /* retarget session response */
620 DEBUG(0,("Unexpected session response\n"));
621 break;
623 case NBSSkeepalive: /* session keepalive */
624 default:
625 return;
628 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
629 msg_type, msg_flags));
631 srv_send_smb(sconn, outbuf, false, 0, false, NULL);
633 if (CVAL(outbuf, 0) != 0x82) {
634 exit_server_cleanly("invalid netbios session");
636 return;
639 /****************************************************************************
640 Reply to a tcon.
641 conn POINTER CAN BE NULL HERE !
642 ****************************************************************************/
644 void reply_tcon(struct smb_request *req)
646 connection_struct *conn = req->conn;
647 const char *service;
648 char *service_buf = NULL;
649 char *password = NULL;
650 char *dev = NULL;
651 int pwlen=0;
652 NTSTATUS nt_status;
653 const char *p;
654 TALLOC_CTX *ctx = talloc_tos();
655 struct smbd_server_connection *sconn = req->sconn;
657 START_PROFILE(SMBtcon);
659 if (req->buflen < 4) {
660 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
661 END_PROFILE(SMBtcon);
662 return;
665 p = (const char *)req->buf + 1;
666 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
667 p += 1;
668 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
669 p += pwlen+1;
670 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
671 p += 1;
673 if (service_buf == NULL || password == NULL || dev == NULL) {
674 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
675 END_PROFILE(SMBtcon);
676 return;
678 p = strrchr_m(service_buf,'\\');
679 if (p) {
680 service = p+1;
681 } else {
682 service = service_buf;
685 conn = make_connection(sconn,service,dev,
686 req->vuid,&nt_status);
687 req->conn = conn;
689 if (!conn) {
690 reply_nterror(req, nt_status);
691 END_PROFILE(SMBtcon);
692 return;
695 reply_outbuf(req, 2, 0);
696 SSVAL(req->outbuf,smb_vwv0,sconn->smb1.negprot.max_recv);
697 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
698 SSVAL(req->outbuf,smb_tid,conn->cnum);
700 DEBUG(3,("tcon service=%s cnum=%d\n",
701 service, conn->cnum));
703 END_PROFILE(SMBtcon);
704 return;
707 /****************************************************************************
708 Reply to a tcon and X.
709 conn POINTER CAN BE NULL HERE !
710 ****************************************************************************/
712 void reply_tcon_and_X(struct smb_request *req)
714 connection_struct *conn = req->conn;
715 const char *service = NULL;
716 TALLOC_CTX *ctx = talloc_tos();
717 /* what the cleint thinks the device is */
718 char *client_devicetype = NULL;
719 /* what the server tells the client the share represents */
720 const char *server_devicetype;
721 NTSTATUS nt_status;
722 int passlen;
723 char *path = NULL;
724 const char *p, *q;
725 uint16_t tcon_flags;
726 struct smbXsrv_session *session = NULL;
727 NTTIME now = timeval_to_nttime(&req->request_time);
728 bool session_key_updated = false;
729 uint16_t optional_support = 0;
730 struct smbd_server_connection *sconn = req->sconn;
732 START_PROFILE(SMBtconX);
734 if (req->wct < 4) {
735 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
736 END_PROFILE(SMBtconX);
737 return;
740 passlen = SVAL(req->vwv+3, 0);
741 tcon_flags = SVAL(req->vwv+2, 0);
743 /* we might have to close an old one */
744 if ((tcon_flags & TCONX_FLAG_DISCONNECT_TID) && conn) {
745 struct smbXsrv_tcon *tcon;
746 NTSTATUS status;
748 tcon = conn->tcon;
749 req->conn = NULL;
750 conn = NULL;
753 * TODO: cancel all outstanding requests on the tcon
755 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
756 if (!NT_STATUS_IS_OK(status)) {
757 DEBUG(0, ("reply_tcon_and_X: "
758 "smbXsrv_tcon_disconnect() failed: %s\n",
759 nt_errstr(status)));
761 * If we hit this case, there is something completely
762 * wrong, so we better disconnect the transport connection.
764 END_PROFILE(SMBtconX);
765 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
766 return;
769 TALLOC_FREE(tcon);
772 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
773 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
774 END_PROFILE(SMBtconX);
775 return;
778 if (sconn->smb1.negprot.encrypted_passwords) {
779 p = (const char *)req->buf + passlen;
780 } else {
781 p = (const char *)req->buf + passlen + 1;
784 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
786 if (path == NULL) {
787 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
788 END_PROFILE(SMBtconX);
789 return;
793 * the service name can be either: \\server\share
794 * or share directly like on the DELL PowerVault 705
796 if (*path=='\\') {
797 q = strchr_m(path+2,'\\');
798 if (!q) {
799 reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
800 END_PROFILE(SMBtconX);
801 return;
803 service = q+1;
804 } else {
805 service = path;
808 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
809 &client_devicetype, p,
810 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
812 if (client_devicetype == NULL) {
813 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
814 END_PROFILE(SMBtconX);
815 return;
818 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
820 nt_status = smb1srv_session_lookup(req->sconn->conn,
821 req->vuid, now, &session);
822 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_USER_SESSION_DELETED)) {
823 reply_force_doserror(req, ERRSRV, ERRbaduid);
824 END_PROFILE(SMBtconX);
825 return;
827 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
828 reply_nterror(req, nt_status);
829 END_PROFILE(SMBtconX);
830 return;
832 if (!NT_STATUS_IS_OK(nt_status)) {
833 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
834 END_PROFILE(SMBtconX);
835 return;
838 if (session->global->auth_session_info == NULL) {
839 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
840 END_PROFILE(SMBtconX);
841 return;
845 * If there is no application key defined yet
846 * we create one.
848 * This means we setup the application key on the
849 * first tcon that happens via the given session.
851 * Once the application key is defined, it does not
852 * change any more.
854 if (session->global->application_key.length == 0 &&
855 session->global->signing_key.length > 0)
857 struct smbXsrv_session *x = session;
858 struct auth_session_info *session_info =
859 session->global->auth_session_info;
860 uint8_t session_key[16];
862 ZERO_STRUCT(session_key);
863 memcpy(session_key, x->global->signing_key.data,
864 MIN(x->global->signing_key.length, sizeof(session_key)));
867 * The application key is truncated/padded to 16 bytes
869 x->global->application_key = data_blob_talloc(x->global,
870 session_key,
871 sizeof(session_key));
872 ZERO_STRUCT(session_key);
873 if (x->global->application_key.data == NULL) {
874 reply_nterror(req, NT_STATUS_NO_MEMORY);
875 END_PROFILE(SMBtconX);
876 return;
879 if (tcon_flags & TCONX_FLAG_EXTENDED_SIGNATURES) {
880 smb_key_derivation(x->global->application_key.data,
881 x->global->application_key.length,
882 x->global->application_key.data);
883 optional_support |= SMB_EXTENDED_SIGNATURES;
887 * Place the application key into the session_info
889 data_blob_clear_free(&session_info->session_key);
890 session_info->session_key = data_blob_dup_talloc(session_info,
891 x->global->application_key);
892 if (session_info->session_key.data == NULL) {
893 data_blob_clear_free(&x->global->application_key);
894 reply_nterror(req, NT_STATUS_NO_MEMORY);
895 END_PROFILE(SMBtconX);
896 return;
898 session_key_updated = true;
901 conn = make_connection(sconn, service, client_devicetype,
902 req->vuid, &nt_status);
903 req->conn =conn;
905 if (!conn) {
906 if (session_key_updated) {
907 struct smbXsrv_session *x = session;
908 struct auth_session_info *session_info =
909 session->global->auth_session_info;
910 data_blob_clear_free(&x->global->application_key);
911 data_blob_clear_free(&session_info->session_key);
913 reply_nterror(req, nt_status);
914 END_PROFILE(SMBtconX);
915 return;
918 if ( IS_IPC(conn) )
919 server_devicetype = "IPC";
920 else if ( IS_PRINT(conn) )
921 server_devicetype = "LPT1:";
922 else
923 server_devicetype = "A:";
925 if (get_Protocol() < PROTOCOL_NT1) {
926 reply_outbuf(req, 2, 0);
927 if (message_push_string(&req->outbuf, server_devicetype,
928 STR_TERMINATE|STR_ASCII) == -1) {
929 reply_nterror(req, NT_STATUS_NO_MEMORY);
930 END_PROFILE(SMBtconX);
931 return;
933 } else {
934 /* NT sets the fstype of IPC$ to the null string */
935 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(ctx, SNUM(conn));
937 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
938 /* Return permissions. */
939 uint32 perm1 = 0;
940 uint32 perm2 = 0;
942 reply_outbuf(req, 7, 0);
944 if (IS_IPC(conn)) {
945 perm1 = FILE_ALL_ACCESS;
946 perm2 = FILE_ALL_ACCESS;
947 } else {
948 perm1 = conn->share_access;
951 SIVAL(req->outbuf, smb_vwv3, perm1);
952 SIVAL(req->outbuf, smb_vwv5, perm2);
953 } else {
954 reply_outbuf(req, 3, 0);
957 if ((message_push_string(&req->outbuf, server_devicetype,
958 STR_TERMINATE|STR_ASCII) == -1)
959 || (message_push_string(&req->outbuf, fstype,
960 STR_TERMINATE) == -1)) {
961 reply_nterror(req, NT_STATUS_NO_MEMORY);
962 END_PROFILE(SMBtconX);
963 return;
966 /* what does setting this bit do? It is set by NT4 and
967 may affect the ability to autorun mounted cdroms */
968 optional_support |= SMB_SUPPORT_SEARCH_BITS;
969 optional_support |=
970 (lp_csc_policy(SNUM(conn)) << SMB_CSC_POLICY_SHIFT);
972 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
973 DEBUG(2,("Serving %s as a Dfs root\n",
974 lp_servicename(ctx, SNUM(conn)) ));
975 optional_support |= SMB_SHARE_IN_DFS;
978 SSVAL(req->outbuf, smb_vwv2, optional_support);
981 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
982 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
984 DEBUG(3,("tconX service=%s \n",
985 service));
987 /* set the incoming and outgoing tid to the just created one */
988 SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
989 SSVAL(req->outbuf,smb_tid,conn->cnum);
991 END_PROFILE(SMBtconX);
993 req->tid = conn->cnum;
996 /****************************************************************************
997 Reply to an unknown type.
998 ****************************************************************************/
1000 void reply_unknown_new(struct smb_request *req, uint8 type)
1002 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
1003 smb_fn_name(type), type, type));
1004 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
1005 return;
1008 /****************************************************************************
1009 Reply to an ioctl.
1010 conn POINTER CAN BE NULL HERE !
1011 ****************************************************************************/
1013 void reply_ioctl(struct smb_request *req)
1015 connection_struct *conn = req->conn;
1016 uint16 device;
1017 uint16 function;
1018 uint32 ioctl_code;
1019 int replysize;
1020 char *p;
1022 START_PROFILE(SMBioctl);
1024 if (req->wct < 3) {
1025 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1026 END_PROFILE(SMBioctl);
1027 return;
1030 device = SVAL(req->vwv+1, 0);
1031 function = SVAL(req->vwv+2, 0);
1032 ioctl_code = (device << 16) + function;
1034 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
1036 switch (ioctl_code) {
1037 case IOCTL_QUERY_JOB_INFO:
1038 replysize = 32;
1039 break;
1040 default:
1041 reply_force_doserror(req, ERRSRV, ERRnosupport);
1042 END_PROFILE(SMBioctl);
1043 return;
1046 reply_outbuf(req, 8, replysize+1);
1047 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
1048 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
1049 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
1050 p = smb_buf(req->outbuf);
1051 memset(p, '\0', replysize+1); /* valgrind-safe. */
1052 p += 1; /* Allow for alignment */
1054 switch (ioctl_code) {
1055 case IOCTL_QUERY_JOB_INFO:
1057 files_struct *fsp = file_fsp(
1058 req, SVAL(req->vwv+0, 0));
1059 if (!fsp) {
1060 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
1061 END_PROFILE(SMBioctl);
1062 return;
1064 /* Job number */
1065 SSVAL(p, 0, print_spool_rap_jobid(fsp->print_file));
1067 srvstr_push((char *)req->outbuf, req->flags2, p+2,
1068 lp_netbios_name(), 15,
1069 STR_TERMINATE|STR_ASCII);
1070 if (conn) {
1071 srvstr_push((char *)req->outbuf, req->flags2,
1072 p+18,
1073 lp_servicename(talloc_tos(),
1074 SNUM(conn)),
1075 13, STR_TERMINATE|STR_ASCII);
1076 } else {
1077 memset(p+18, 0, 13);
1079 break;
1083 END_PROFILE(SMBioctl);
1084 return;
1087 /****************************************************************************
1088 Strange checkpath NTSTATUS mapping.
1089 ****************************************************************************/
1091 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
1093 /* Strange DOS error code semantics only for checkpath... */
1094 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
1095 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
1096 /* We need to map to ERRbadpath */
1097 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1100 return status;
1103 /****************************************************************************
1104 Reply to a checkpath.
1105 ****************************************************************************/
1107 void reply_checkpath(struct smb_request *req)
1109 connection_struct *conn = req->conn;
1110 struct smb_filename *smb_fname = NULL;
1111 char *name = NULL;
1112 NTSTATUS status;
1113 TALLOC_CTX *ctx = talloc_tos();
1115 START_PROFILE(SMBcheckpath);
1117 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
1118 STR_TERMINATE, &status);
1120 if (!NT_STATUS_IS_OK(status)) {
1121 status = map_checkpath_error(req->flags2, status);
1122 reply_nterror(req, status);
1123 END_PROFILE(SMBcheckpath);
1124 return;
1127 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1129 status = filename_convert(ctx,
1130 conn,
1131 req->flags2 & FLAGS2_DFS_PATHNAMES,
1132 name,
1134 NULL,
1135 &smb_fname);
1137 if (!NT_STATUS_IS_OK(status)) {
1138 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1139 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1140 ERRSRV, ERRbadpath);
1141 END_PROFILE(SMBcheckpath);
1142 return;
1144 goto path_err;
1147 if (!VALID_STAT(smb_fname->st) &&
1148 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1149 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1150 smb_fname_str_dbg(smb_fname), strerror(errno)));
1151 status = map_nt_error_from_unix(errno);
1152 goto path_err;
1155 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1156 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1157 ERRDOS, ERRbadpath);
1158 goto out;
1161 reply_outbuf(req, 0, 0);
1163 path_err:
1164 /* We special case this - as when a Windows machine
1165 is parsing a path is steps through the components
1166 one at a time - if a component fails it expects
1167 ERRbadpath, not ERRbadfile.
1169 status = map_checkpath_error(req->flags2, status);
1170 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1172 * Windows returns different error codes if
1173 * the parent directory is valid but not the
1174 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1175 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1176 * if the path is invalid.
1178 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1179 ERRDOS, ERRbadpath);
1180 goto out;
1183 reply_nterror(req, status);
1185 out:
1186 TALLOC_FREE(smb_fname);
1187 END_PROFILE(SMBcheckpath);
1188 return;
1191 /****************************************************************************
1192 Reply to a getatr.
1193 ****************************************************************************/
1195 void reply_getatr(struct smb_request *req)
1197 connection_struct *conn = req->conn;
1198 struct smb_filename *smb_fname = NULL;
1199 char *fname = NULL;
1200 int mode=0;
1201 off_t size=0;
1202 time_t mtime=0;
1203 const char *p;
1204 NTSTATUS status;
1205 TALLOC_CTX *ctx = talloc_tos();
1206 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1208 START_PROFILE(SMBgetatr);
1210 p = (const char *)req->buf + 1;
1211 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1212 if (!NT_STATUS_IS_OK(status)) {
1213 reply_nterror(req, status);
1214 goto out;
1217 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1218 under WfWg - weird! */
1219 if (*fname == '\0') {
1220 mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1221 if (!CAN_WRITE(conn)) {
1222 mode |= FILE_ATTRIBUTE_READONLY;
1224 size = 0;
1225 mtime = 0;
1226 } else {
1227 status = filename_convert(ctx,
1228 conn,
1229 req->flags2 & FLAGS2_DFS_PATHNAMES,
1230 fname,
1232 NULL,
1233 &smb_fname);
1234 if (!NT_STATUS_IS_OK(status)) {
1235 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1236 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1237 ERRSRV, ERRbadpath);
1238 goto out;
1240 reply_nterror(req, status);
1241 goto out;
1243 if (!VALID_STAT(smb_fname->st) &&
1244 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1245 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1246 smb_fname_str_dbg(smb_fname),
1247 strerror(errno)));
1248 reply_nterror(req, map_nt_error_from_unix(errno));
1249 goto out;
1252 mode = dos_mode(conn, smb_fname);
1253 size = smb_fname->st.st_ex_size;
1255 if (ask_sharemode) {
1256 struct timespec write_time_ts;
1257 struct file_id fileid;
1259 ZERO_STRUCT(write_time_ts);
1260 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1261 get_file_infos(fileid, 0, NULL, &write_time_ts);
1262 if (!null_timespec(write_time_ts)) {
1263 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1267 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1268 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1269 size = 0;
1273 reply_outbuf(req, 10, 0);
1275 SSVAL(req->outbuf,smb_vwv0,mode);
1276 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1277 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1278 } else {
1279 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1281 SIVAL(req->outbuf,smb_vwv3,(uint32)size);
1283 if (get_Protocol() >= PROTOCOL_NT1) {
1284 SSVAL(req->outbuf, smb_flg2,
1285 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1288 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1289 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1291 out:
1292 TALLOC_FREE(smb_fname);
1293 TALLOC_FREE(fname);
1294 END_PROFILE(SMBgetatr);
1295 return;
1298 /****************************************************************************
1299 Reply to a setatr.
1300 ****************************************************************************/
1302 void reply_setatr(struct smb_request *req)
1304 struct smb_file_time ft;
1305 connection_struct *conn = req->conn;
1306 struct smb_filename *smb_fname = NULL;
1307 char *fname = NULL;
1308 int mode;
1309 time_t mtime;
1310 const char *p;
1311 NTSTATUS status;
1312 TALLOC_CTX *ctx = talloc_tos();
1314 START_PROFILE(SMBsetatr);
1316 ZERO_STRUCT(ft);
1318 if (req->wct < 2) {
1319 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1320 goto out;
1323 p = (const char *)req->buf + 1;
1324 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1325 if (!NT_STATUS_IS_OK(status)) {
1326 reply_nterror(req, status);
1327 goto out;
1330 status = filename_convert(ctx,
1331 conn,
1332 req->flags2 & FLAGS2_DFS_PATHNAMES,
1333 fname,
1335 NULL,
1336 &smb_fname);
1337 if (!NT_STATUS_IS_OK(status)) {
1338 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1339 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1340 ERRSRV, ERRbadpath);
1341 goto out;
1343 reply_nterror(req, status);
1344 goto out;
1347 if (smb_fname->base_name[0] == '.' &&
1348 smb_fname->base_name[1] == '\0') {
1350 * Not sure here is the right place to catch this
1351 * condition. Might be moved to somewhere else later -- vl
1353 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1354 goto out;
1357 mode = SVAL(req->vwv+0, 0);
1358 mtime = srv_make_unix_date3(req->vwv+1);
1360 if (mode != FILE_ATTRIBUTE_NORMAL) {
1361 if (VALID_STAT_OF_DIR(smb_fname->st))
1362 mode |= FILE_ATTRIBUTE_DIRECTORY;
1363 else
1364 mode &= ~FILE_ATTRIBUTE_DIRECTORY;
1366 status = check_access(conn, NULL, smb_fname,
1367 FILE_WRITE_ATTRIBUTES);
1368 if (!NT_STATUS_IS_OK(status)) {
1369 reply_nterror(req, status);
1370 goto out;
1373 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1374 false) != 0) {
1375 reply_nterror(req, map_nt_error_from_unix(errno));
1376 goto out;
1380 ft.mtime = convert_time_t_to_timespec(mtime);
1381 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1382 if (!NT_STATUS_IS_OK(status)) {
1383 reply_nterror(req, status);
1384 goto out;
1387 reply_outbuf(req, 0, 0);
1389 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1390 mode));
1391 out:
1392 TALLOC_FREE(smb_fname);
1393 END_PROFILE(SMBsetatr);
1394 return;
1397 /****************************************************************************
1398 Reply to a dskattr.
1399 ****************************************************************************/
1401 void reply_dskattr(struct smb_request *req)
1403 connection_struct *conn = req->conn;
1404 uint64_t dfree,dsize,bsize;
1405 START_PROFILE(SMBdskattr);
1407 if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (uint64_t)-1) {
1408 reply_nterror(req, map_nt_error_from_unix(errno));
1409 END_PROFILE(SMBdskattr);
1410 return;
1413 reply_outbuf(req, 5, 0);
1415 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1416 double total_space, free_space;
1417 /* we need to scale this to a number that DOS6 can handle. We
1418 use floating point so we can handle large drives on systems
1419 that don't have 64 bit integers
1421 we end up displaying a maximum of 2G to DOS systems
1423 total_space = dsize * (double)bsize;
1424 free_space = dfree * (double)bsize;
1426 dsize = (uint64_t)((total_space+63*512) / (64*512));
1427 dfree = (uint64_t)((free_space+63*512) / (64*512));
1429 if (dsize > 0xFFFF) dsize = 0xFFFF;
1430 if (dfree > 0xFFFF) dfree = 0xFFFF;
1432 SSVAL(req->outbuf,smb_vwv0,dsize);
1433 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1434 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1435 SSVAL(req->outbuf,smb_vwv3,dfree);
1436 } else {
1437 SSVAL(req->outbuf,smb_vwv0,dsize);
1438 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1439 SSVAL(req->outbuf,smb_vwv2,512);
1440 SSVAL(req->outbuf,smb_vwv3,dfree);
1443 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1445 END_PROFILE(SMBdskattr);
1446 return;
1450 * Utility function to split the filename from the directory.
1452 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1453 char **fname_dir_out,
1454 char **fname_mask_out)
1456 const char *p = NULL;
1457 char *fname_dir = NULL;
1458 char *fname_mask = NULL;
1460 p = strrchr_m(fname_in, '/');
1461 if (!p) {
1462 fname_dir = talloc_strdup(ctx, ".");
1463 fname_mask = talloc_strdup(ctx, fname_in);
1464 } else {
1465 fname_dir = talloc_strndup(ctx, fname_in,
1466 PTR_DIFF(p, fname_in));
1467 fname_mask = talloc_strdup(ctx, p+1);
1470 if (!fname_dir || !fname_mask) {
1471 TALLOC_FREE(fname_dir);
1472 TALLOC_FREE(fname_mask);
1473 return NT_STATUS_NO_MEMORY;
1476 *fname_dir_out = fname_dir;
1477 *fname_mask_out = fname_mask;
1478 return NT_STATUS_OK;
1481 /****************************************************************************
1482 Reply to a search.
1483 Can be called from SMBsearch, SMBffirst or SMBfunique.
1484 ****************************************************************************/
1486 void reply_search(struct smb_request *req)
1488 connection_struct *conn = req->conn;
1489 char *path = NULL;
1490 const char *mask = NULL;
1491 char *directory = NULL;
1492 struct smb_filename *smb_fname = NULL;
1493 char *fname = NULL;
1494 off_t size;
1495 uint32 mode;
1496 struct timespec date;
1497 uint32 dirtype;
1498 unsigned int numentries = 0;
1499 unsigned int maxentries = 0;
1500 bool finished = False;
1501 const char *p;
1502 int status_len;
1503 char status[21];
1504 int dptr_num= -1;
1505 bool check_descend = False;
1506 bool expect_close = False;
1507 NTSTATUS nt_status;
1508 bool mask_contains_wcard = False;
1509 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1510 TALLOC_CTX *ctx = talloc_tos();
1511 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1512 struct dptr_struct *dirptr = NULL;
1513 struct smbd_server_connection *sconn = req->sconn;
1515 START_PROFILE(SMBsearch);
1517 if (req->wct < 2) {
1518 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1519 goto out;
1522 if (lp_posix_pathnames()) {
1523 reply_unknown_new(req, req->cmd);
1524 goto out;
1527 /* If we were called as SMBffirst then we must expect close. */
1528 if(req->cmd == SMBffirst) {
1529 expect_close = True;
1532 reply_outbuf(req, 1, 3);
1533 maxentries = SVAL(req->vwv+0, 0);
1534 dirtype = SVAL(req->vwv+1, 0);
1535 p = (const char *)req->buf + 1;
1536 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1537 &nt_status, &mask_contains_wcard);
1538 if (!NT_STATUS_IS_OK(nt_status)) {
1539 reply_nterror(req, nt_status);
1540 goto out;
1543 p++;
1544 status_len = SVAL(p, 0);
1545 p += 2;
1547 /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1549 if (status_len == 0) {
1550 nt_status = filename_convert(ctx, conn,
1551 req->flags2 & FLAGS2_DFS_PATHNAMES,
1552 path,
1553 UCF_ALWAYS_ALLOW_WCARD_LCOMP,
1554 &mask_contains_wcard,
1555 &smb_fname);
1556 if (!NT_STATUS_IS_OK(nt_status)) {
1557 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1558 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1559 ERRSRV, ERRbadpath);
1560 goto out;
1562 reply_nterror(req, nt_status);
1563 goto out;
1566 directory = smb_fname->base_name;
1568 p = strrchr_m(directory,'/');
1569 if ((p != NULL) && (*directory != '/')) {
1570 mask = p + 1;
1571 directory = talloc_strndup(ctx, directory,
1572 PTR_DIFF(p, directory));
1573 } else {
1574 mask = directory;
1575 directory = talloc_strdup(ctx,".");
1578 if (!directory) {
1579 reply_nterror(req, NT_STATUS_NO_MEMORY);
1580 goto out;
1583 memset((char *)status,'\0',21);
1584 SCVAL(status,0,(dirtype & 0x1F));
1586 nt_status = dptr_create(conn,
1587 NULL, /* req */
1588 NULL, /* fsp */
1589 directory,
1590 True,
1591 expect_close,
1592 req->smbpid,
1593 mask,
1594 mask_contains_wcard,
1595 dirtype,
1596 &dirptr);
1597 if (!NT_STATUS_IS_OK(nt_status)) {
1598 reply_nterror(req, nt_status);
1599 goto out;
1601 dptr_num = dptr_dnum(dirptr);
1602 } else {
1603 int status_dirtype;
1604 const char *dirpath;
1606 memcpy(status,p,21);
1607 status_dirtype = CVAL(status,0) & 0x1F;
1608 if (status_dirtype != (dirtype & 0x1F)) {
1609 dirtype = status_dirtype;
1612 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1613 if (!dirptr) {
1614 goto SearchEmpty;
1616 dirpath = dptr_path(sconn, dptr_num);
1617 directory = talloc_strdup(ctx, dirpath);
1618 if (!directory) {
1619 reply_nterror(req, NT_STATUS_NO_MEMORY);
1620 goto out;
1623 mask = dptr_wcard(sconn, dptr_num);
1624 if (!mask) {
1625 goto SearchEmpty;
1628 * For a 'continue' search we have no string. So
1629 * check from the initial saved string.
1631 mask_contains_wcard = ms_has_wild(mask);
1632 dirtype = dptr_attr(sconn, dptr_num);
1635 DEBUG(4,("dptr_num is %d\n",dptr_num));
1637 /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
1638 dptr_init_search_op(dirptr);
1640 if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1641 char buf[DIR_STRUCT_SIZE];
1642 memcpy(buf,status,21);
1643 if (!make_dir_struct(ctx,buf,"???????????",volume_label(ctx, SNUM(conn)),
1644 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1645 reply_nterror(req, NT_STATUS_NO_MEMORY);
1646 goto out;
1648 dptr_fill(sconn, buf+12,dptr_num);
1649 if (dptr_zero(buf+12) && (status_len==0)) {
1650 numentries = 1;
1651 } else {
1652 numentries = 0;
1654 if (message_push_blob(&req->outbuf,
1655 data_blob_const(buf, sizeof(buf)))
1656 == -1) {
1657 reply_nterror(req, NT_STATUS_NO_MEMORY);
1658 goto out;
1660 } else {
1661 unsigned int i;
1662 maxentries = MIN(
1663 maxentries,
1664 ((BUFFER_SIZE -
1665 ((uint8 *)smb_buf(req->outbuf) + 3 - req->outbuf))
1666 /DIR_STRUCT_SIZE));
1668 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1669 directory,lp_dontdescend(ctx, SNUM(conn))));
1670 if (in_list(directory, lp_dontdescend(ctx, SNUM(conn)),True)) {
1671 check_descend = True;
1674 for (i=numentries;(i<maxentries) && !finished;i++) {
1675 finished = !get_dir_entry(ctx,
1676 dirptr,
1677 mask,
1678 dirtype,
1679 &fname,
1680 &size,
1681 &mode,
1682 &date,
1683 check_descend,
1684 ask_sharemode);
1685 if (!finished) {
1686 char buf[DIR_STRUCT_SIZE];
1687 memcpy(buf,status,21);
1688 if (!make_dir_struct(ctx,
1689 buf,
1690 mask,
1691 fname,
1692 size,
1693 mode,
1694 convert_timespec_to_time_t(date),
1695 !allow_long_path_components)) {
1696 reply_nterror(req, NT_STATUS_NO_MEMORY);
1697 goto out;
1699 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1700 break;
1702 if (message_push_blob(&req->outbuf,
1703 data_blob_const(buf, sizeof(buf)))
1704 == -1) {
1705 reply_nterror(req, NT_STATUS_NO_MEMORY);
1706 goto out;
1708 numentries++;
1713 SearchEmpty:
1715 /* If we were called as SMBffirst with smb_search_id == NULL
1716 and no entries were found then return error and close dirptr
1717 (X/Open spec) */
1719 if (numentries == 0) {
1720 dptr_close(sconn, &dptr_num);
1721 } else if(expect_close && status_len == 0) {
1722 /* Close the dptr - we know it's gone */
1723 dptr_close(sconn, &dptr_num);
1726 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1727 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1728 dptr_close(sconn, &dptr_num);
1731 if ((numentries == 0) && !mask_contains_wcard) {
1732 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1733 goto out;
1736 SSVAL(req->outbuf,smb_vwv0,numentries);
1737 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1738 SCVAL(smb_buf(req->outbuf),0,5);
1739 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1741 /* The replies here are never long name. */
1742 SSVAL(req->outbuf, smb_flg2,
1743 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1744 if (!allow_long_path_components) {
1745 SSVAL(req->outbuf, smb_flg2,
1746 SVAL(req->outbuf, smb_flg2)
1747 & (~FLAGS2_LONG_PATH_COMPONENTS));
1750 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
1751 SSVAL(req->outbuf, smb_flg2,
1752 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
1754 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
1755 smb_fn_name(req->cmd),
1756 mask,
1757 directory,
1758 dirtype,
1759 numentries,
1760 maxentries ));
1761 out:
1762 TALLOC_FREE(directory);
1763 TALLOC_FREE(smb_fname);
1764 END_PROFILE(SMBsearch);
1765 return;
1768 /****************************************************************************
1769 Reply to a fclose (stop directory search).
1770 ****************************************************************************/
1772 void reply_fclose(struct smb_request *req)
1774 int status_len;
1775 char status[21];
1776 int dptr_num= -2;
1777 const char *p;
1778 char *path = NULL;
1779 NTSTATUS err;
1780 bool path_contains_wcard = False;
1781 TALLOC_CTX *ctx = talloc_tos();
1782 struct smbd_server_connection *sconn = req->sconn;
1784 START_PROFILE(SMBfclose);
1786 if (lp_posix_pathnames()) {
1787 reply_unknown_new(req, req->cmd);
1788 END_PROFILE(SMBfclose);
1789 return;
1792 p = (const char *)req->buf + 1;
1793 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1794 &err, &path_contains_wcard);
1795 if (!NT_STATUS_IS_OK(err)) {
1796 reply_nterror(req, err);
1797 END_PROFILE(SMBfclose);
1798 return;
1800 p++;
1801 status_len = SVAL(p,0);
1802 p += 2;
1804 if (status_len == 0) {
1805 reply_force_doserror(req, ERRSRV, ERRsrverror);
1806 END_PROFILE(SMBfclose);
1807 return;
1810 memcpy(status,p,21);
1812 if(dptr_fetch(sconn, status+12,&dptr_num)) {
1813 /* Close the dptr - we know it's gone */
1814 dptr_close(sconn, &dptr_num);
1817 reply_outbuf(req, 1, 0);
1818 SSVAL(req->outbuf,smb_vwv0,0);
1820 DEBUG(3,("search close\n"));
1822 END_PROFILE(SMBfclose);
1823 return;
1826 /****************************************************************************
1827 Reply to an open.
1828 ****************************************************************************/
1830 void reply_open(struct smb_request *req)
1832 connection_struct *conn = req->conn;
1833 struct smb_filename *smb_fname = NULL;
1834 char *fname = NULL;
1835 uint32 fattr=0;
1836 off_t size = 0;
1837 time_t mtime=0;
1838 int info;
1839 files_struct *fsp;
1840 int oplock_request;
1841 int deny_mode;
1842 uint32 dos_attr;
1843 uint32 access_mask;
1844 uint32 share_mode;
1845 uint32 create_disposition;
1846 uint32 create_options = 0;
1847 uint32_t private_flags = 0;
1848 NTSTATUS status;
1849 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1850 TALLOC_CTX *ctx = talloc_tos();
1852 START_PROFILE(SMBopen);
1854 if (req->wct < 2) {
1855 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1856 goto out;
1859 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1860 deny_mode = SVAL(req->vwv+0, 0);
1861 dos_attr = SVAL(req->vwv+1, 0);
1863 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
1864 STR_TERMINATE, &status);
1865 if (!NT_STATUS_IS_OK(status)) {
1866 reply_nterror(req, status);
1867 goto out;
1870 status = filename_convert(ctx,
1871 conn,
1872 req->flags2 & FLAGS2_DFS_PATHNAMES,
1873 fname,
1875 NULL,
1876 &smb_fname);
1877 if (!NT_STATUS_IS_OK(status)) {
1878 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1879 reply_botherror(req,
1880 NT_STATUS_PATH_NOT_COVERED,
1881 ERRSRV, ERRbadpath);
1882 goto out;
1884 reply_nterror(req, status);
1885 goto out;
1888 if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode,
1889 OPENX_FILE_EXISTS_OPEN, &access_mask,
1890 &share_mode, &create_disposition,
1891 &create_options, &private_flags)) {
1892 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1893 goto out;
1896 status = SMB_VFS_CREATE_FILE(
1897 conn, /* conn */
1898 req, /* req */
1899 0, /* root_dir_fid */
1900 smb_fname, /* fname */
1901 access_mask, /* access_mask */
1902 share_mode, /* share_access */
1903 create_disposition, /* create_disposition*/
1904 create_options, /* create_options */
1905 dos_attr, /* file_attributes */
1906 oplock_request, /* oplock_request */
1907 0, /* allocation_size */
1908 private_flags,
1909 NULL, /* sd */
1910 NULL, /* ea_list */
1911 &fsp, /* result */
1912 &info); /* pinfo */
1914 if (!NT_STATUS_IS_OK(status)) {
1915 if (open_was_deferred(req->sconn, req->mid)) {
1916 /* We have re-scheduled this call. */
1917 goto out;
1919 reply_openerror(req, status);
1920 goto out;
1923 size = smb_fname->st.st_ex_size;
1924 fattr = dos_mode(conn, smb_fname);
1926 /* Deal with other possible opens having a modified
1927 write time. JRA. */
1928 if (ask_sharemode) {
1929 struct timespec write_time_ts;
1931 ZERO_STRUCT(write_time_ts);
1932 get_file_infos(fsp->file_id, 0, NULL, &write_time_ts);
1933 if (!null_timespec(write_time_ts)) {
1934 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1938 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1940 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
1941 DEBUG(3,("attempt to open a directory %s\n",
1942 fsp_str_dbg(fsp)));
1943 close_file(req, fsp, ERROR_CLOSE);
1944 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
1945 ERRDOS, ERRnoaccess);
1946 goto out;
1949 reply_outbuf(req, 7, 0);
1950 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
1951 SSVAL(req->outbuf,smb_vwv1,fattr);
1952 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1953 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
1954 } else {
1955 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
1957 SIVAL(req->outbuf,smb_vwv4,(uint32)size);
1958 SSVAL(req->outbuf,smb_vwv6,deny_mode);
1960 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1961 SCVAL(req->outbuf,smb_flg,
1962 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1965 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1966 SCVAL(req->outbuf,smb_flg,
1967 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1969 out:
1970 TALLOC_FREE(smb_fname);
1971 END_PROFILE(SMBopen);
1972 return;
1975 /****************************************************************************
1976 Reply to an open and X.
1977 ****************************************************************************/
1979 void reply_open_and_X(struct smb_request *req)
1981 connection_struct *conn = req->conn;
1982 struct smb_filename *smb_fname = NULL;
1983 char *fname = NULL;
1984 uint16 open_flags;
1985 int deny_mode;
1986 uint32 smb_attr;
1987 /* Breakout the oplock request bits so we can set the
1988 reply bits separately. */
1989 int ex_oplock_request;
1990 int core_oplock_request;
1991 int oplock_request;
1992 #if 0
1993 int smb_sattr = SVAL(req->vwv+4, 0);
1994 uint32 smb_time = make_unix_date3(req->vwv+6);
1995 #endif
1996 int smb_ofun;
1997 uint32 fattr=0;
1998 int mtime=0;
1999 int smb_action = 0;
2000 files_struct *fsp;
2001 NTSTATUS status;
2002 uint64_t allocation_size;
2003 ssize_t retval = -1;
2004 uint32 access_mask;
2005 uint32 share_mode;
2006 uint32 create_disposition;
2007 uint32 create_options = 0;
2008 uint32_t private_flags = 0;
2009 TALLOC_CTX *ctx = talloc_tos();
2011 START_PROFILE(SMBopenX);
2013 if (req->wct < 15) {
2014 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2015 goto out;
2018 open_flags = SVAL(req->vwv+2, 0);
2019 deny_mode = SVAL(req->vwv+3, 0);
2020 smb_attr = SVAL(req->vwv+5, 0);
2021 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
2022 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2023 oplock_request = ex_oplock_request | core_oplock_request;
2024 smb_ofun = SVAL(req->vwv+8, 0);
2025 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
2027 /* If it's an IPC, pass off the pipe handler. */
2028 if (IS_IPC(conn)) {
2029 if (lp_nt_pipe_support()) {
2030 reply_open_pipe_and_X(conn, req);
2031 } else {
2032 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
2034 goto out;
2037 /* XXXX we need to handle passed times, sattr and flags */
2038 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
2039 STR_TERMINATE, &status);
2040 if (!NT_STATUS_IS_OK(status)) {
2041 reply_nterror(req, status);
2042 goto out;
2045 status = filename_convert(ctx,
2046 conn,
2047 req->flags2 & FLAGS2_DFS_PATHNAMES,
2048 fname,
2050 NULL,
2051 &smb_fname);
2052 if (!NT_STATUS_IS_OK(status)) {
2053 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2054 reply_botherror(req,
2055 NT_STATUS_PATH_NOT_COVERED,
2056 ERRSRV, ERRbadpath);
2057 goto out;
2059 reply_nterror(req, status);
2060 goto out;
2063 if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode,
2064 smb_ofun,
2065 &access_mask, &share_mode,
2066 &create_disposition,
2067 &create_options,
2068 &private_flags)) {
2069 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2070 goto out;
2073 status = SMB_VFS_CREATE_FILE(
2074 conn, /* conn */
2075 req, /* req */
2076 0, /* root_dir_fid */
2077 smb_fname, /* fname */
2078 access_mask, /* access_mask */
2079 share_mode, /* share_access */
2080 create_disposition, /* create_disposition*/
2081 create_options, /* create_options */
2082 smb_attr, /* file_attributes */
2083 oplock_request, /* oplock_request */
2084 0, /* allocation_size */
2085 private_flags,
2086 NULL, /* sd */
2087 NULL, /* ea_list */
2088 &fsp, /* result */
2089 &smb_action); /* pinfo */
2091 if (!NT_STATUS_IS_OK(status)) {
2092 if (open_was_deferred(req->sconn, req->mid)) {
2093 /* We have re-scheduled this call. */
2094 goto out;
2096 reply_openerror(req, status);
2097 goto out;
2100 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2101 if the file is truncated or created. */
2102 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2103 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2104 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2105 close_file(req, fsp, ERROR_CLOSE);
2106 reply_nterror(req, NT_STATUS_DISK_FULL);
2107 goto out;
2109 retval = vfs_set_filelen(fsp, (off_t)allocation_size);
2110 if (retval < 0) {
2111 close_file(req, fsp, ERROR_CLOSE);
2112 reply_nterror(req, NT_STATUS_DISK_FULL);
2113 goto out;
2115 status = vfs_stat_fsp(fsp);
2116 if (!NT_STATUS_IS_OK(status)) {
2117 close_file(req, fsp, ERROR_CLOSE);
2118 reply_nterror(req, status);
2119 goto out;
2123 fattr = dos_mode(conn, fsp->fsp_name);
2124 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2125 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2126 close_file(req, fsp, ERROR_CLOSE);
2127 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2128 goto out;
2131 /* If the caller set the extended oplock request bit
2132 and we granted one (by whatever means) - set the
2133 correct bit for extended oplock reply.
2136 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2137 smb_action |= EXTENDED_OPLOCK_GRANTED;
2140 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2141 smb_action |= EXTENDED_OPLOCK_GRANTED;
2144 /* If the caller set the core oplock request bit
2145 and we granted one (by whatever means) - set the
2146 correct bit for core oplock reply.
2149 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2150 reply_outbuf(req, 19, 0);
2151 } else {
2152 reply_outbuf(req, 15, 0);
2155 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2156 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2158 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2159 SCVAL(req->outbuf, smb_flg,
2160 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2163 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2164 SCVAL(req->outbuf, smb_flg,
2165 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2168 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2169 SSVAL(req->outbuf,smb_vwv3,fattr);
2170 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2171 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2172 } else {
2173 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2175 SIVAL(req->outbuf,smb_vwv6,(uint32)fsp->fsp_name->st.st_ex_size);
2176 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2177 SSVAL(req->outbuf,smb_vwv11,smb_action);
2179 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2180 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2183 out:
2184 TALLOC_FREE(smb_fname);
2185 END_PROFILE(SMBopenX);
2186 return;
2189 /****************************************************************************
2190 Reply to a SMBulogoffX.
2191 ****************************************************************************/
2193 void reply_ulogoffX(struct smb_request *req)
2195 struct smbd_server_connection *sconn = req->sconn;
2196 struct user_struct *vuser;
2197 struct smbXsrv_session *session = NULL;
2198 NTSTATUS status;
2200 START_PROFILE(SMBulogoffX);
2202 vuser = get_valid_user_struct(sconn, req->vuid);
2204 if(vuser == NULL) {
2205 DEBUG(3,("ulogoff, vuser id %llu does not map to user.\n",
2206 (unsigned long long)req->vuid));
2208 req->vuid = UID_FIELD_INVALID;
2209 reply_force_doserror(req, ERRSRV, ERRbaduid);
2210 END_PROFILE(SMBulogoffX);
2211 return;
2214 session = vuser->session;
2215 vuser = NULL;
2218 * TODO: cancel all outstanding requests on the session
2220 status = smbXsrv_session_logoff(session);
2221 if (!NT_STATUS_IS_OK(status)) {
2222 DEBUG(0, ("reply_ulogoff: "
2223 "smbXsrv_session_logoff() failed: %s\n",
2224 nt_errstr(status)));
2226 * If we hit this case, there is something completely
2227 * wrong, so we better disconnect the transport connection.
2229 END_PROFILE(SMBulogoffX);
2230 exit_server(__location__ ": smbXsrv_session_logoff failed");
2231 return;
2234 TALLOC_FREE(session);
2236 reply_outbuf(req, 2, 0);
2237 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2238 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2240 DEBUG(3, ("ulogoffX vuid=%llu\n",
2241 (unsigned long long)req->vuid));
2243 END_PROFILE(SMBulogoffX);
2244 req->vuid = UID_FIELD_INVALID;
2247 /****************************************************************************
2248 Reply to a mknew or a create.
2249 ****************************************************************************/
2251 void reply_mknew(struct smb_request *req)
2253 connection_struct *conn = req->conn;
2254 struct smb_filename *smb_fname = NULL;
2255 char *fname = NULL;
2256 uint32 fattr = 0;
2257 struct smb_file_time ft;
2258 files_struct *fsp;
2259 int oplock_request = 0;
2260 NTSTATUS status;
2261 uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2262 uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2263 uint32 create_disposition;
2264 uint32 create_options = 0;
2265 TALLOC_CTX *ctx = talloc_tos();
2267 START_PROFILE(SMBcreate);
2268 ZERO_STRUCT(ft);
2270 if (req->wct < 3) {
2271 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2272 goto out;
2275 fattr = SVAL(req->vwv+0, 0);
2276 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2278 /* mtime. */
2279 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2281 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2282 STR_TERMINATE, &status);
2283 if (!NT_STATUS_IS_OK(status)) {
2284 reply_nterror(req, status);
2285 goto out;
2288 status = filename_convert(ctx,
2289 conn,
2290 req->flags2 & FLAGS2_DFS_PATHNAMES,
2291 fname,
2293 NULL,
2294 &smb_fname);
2295 if (!NT_STATUS_IS_OK(status)) {
2296 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2297 reply_botherror(req,
2298 NT_STATUS_PATH_NOT_COVERED,
2299 ERRSRV, ERRbadpath);
2300 goto out;
2302 reply_nterror(req, status);
2303 goto out;
2306 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2307 DEBUG(0,("Attempt to create file (%s) with volid set - "
2308 "please report this\n",
2309 smb_fname_str_dbg(smb_fname)));
2312 if(req->cmd == SMBmknew) {
2313 /* We should fail if file exists. */
2314 create_disposition = FILE_CREATE;
2315 } else {
2316 /* Create if file doesn't exist, truncate if it does. */
2317 create_disposition = FILE_OVERWRITE_IF;
2320 status = SMB_VFS_CREATE_FILE(
2321 conn, /* conn */
2322 req, /* req */
2323 0, /* root_dir_fid */
2324 smb_fname, /* fname */
2325 access_mask, /* access_mask */
2326 share_mode, /* share_access */
2327 create_disposition, /* create_disposition*/
2328 create_options, /* create_options */
2329 fattr, /* file_attributes */
2330 oplock_request, /* oplock_request */
2331 0, /* allocation_size */
2332 0, /* private_flags */
2333 NULL, /* sd */
2334 NULL, /* ea_list */
2335 &fsp, /* result */
2336 NULL); /* pinfo */
2338 if (!NT_STATUS_IS_OK(status)) {
2339 if (open_was_deferred(req->sconn, req->mid)) {
2340 /* We have re-scheduled this call. */
2341 goto out;
2343 reply_openerror(req, status);
2344 goto out;
2347 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2348 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2349 if (!NT_STATUS_IS_OK(status)) {
2350 END_PROFILE(SMBcreate);
2351 goto out;
2354 reply_outbuf(req, 1, 0);
2355 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2357 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2358 SCVAL(req->outbuf,smb_flg,
2359 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2362 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2363 SCVAL(req->outbuf,smb_flg,
2364 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2367 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2368 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2369 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2370 (unsigned int)fattr));
2372 out:
2373 TALLOC_FREE(smb_fname);
2374 END_PROFILE(SMBcreate);
2375 return;
2378 /****************************************************************************
2379 Reply to a create temporary file.
2380 ****************************************************************************/
2382 void reply_ctemp(struct smb_request *req)
2384 connection_struct *conn = req->conn;
2385 struct smb_filename *smb_fname = NULL;
2386 char *fname = NULL;
2387 uint32 fattr;
2388 files_struct *fsp;
2389 int oplock_request;
2390 int tmpfd;
2391 char *s;
2392 NTSTATUS status;
2393 TALLOC_CTX *ctx = talloc_tos();
2395 START_PROFILE(SMBctemp);
2397 if (req->wct < 3) {
2398 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2399 goto out;
2402 fattr = SVAL(req->vwv+0, 0);
2403 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2405 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
2406 STR_TERMINATE, &status);
2407 if (!NT_STATUS_IS_OK(status)) {
2408 reply_nterror(req, status);
2409 goto out;
2411 if (*fname) {
2412 fname = talloc_asprintf(ctx,
2413 "%s/TMXXXXXX",
2414 fname);
2415 } else {
2416 fname = talloc_strdup(ctx, "TMXXXXXX");
2419 if (!fname) {
2420 reply_nterror(req, NT_STATUS_NO_MEMORY);
2421 goto out;
2424 status = filename_convert(ctx, conn,
2425 req->flags2 & FLAGS2_DFS_PATHNAMES,
2426 fname,
2428 NULL,
2429 &smb_fname);
2430 if (!NT_STATUS_IS_OK(status)) {
2431 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2432 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2433 ERRSRV, ERRbadpath);
2434 goto out;
2436 reply_nterror(req, status);
2437 goto out;
2440 tmpfd = mkstemp(smb_fname->base_name);
2441 if (tmpfd == -1) {
2442 reply_nterror(req, map_nt_error_from_unix(errno));
2443 goto out;
2446 SMB_VFS_STAT(conn, smb_fname);
2448 /* We should fail if file does not exist. */
2449 status = SMB_VFS_CREATE_FILE(
2450 conn, /* conn */
2451 req, /* req */
2452 0, /* root_dir_fid */
2453 smb_fname, /* fname */
2454 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2455 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2456 FILE_OPEN, /* create_disposition*/
2457 0, /* create_options */
2458 fattr, /* file_attributes */
2459 oplock_request, /* oplock_request */
2460 0, /* allocation_size */
2461 0, /* private_flags */
2462 NULL, /* sd */
2463 NULL, /* ea_list */
2464 &fsp, /* result */
2465 NULL); /* pinfo */
2467 /* close fd from mkstemp() */
2468 close(tmpfd);
2470 if (!NT_STATUS_IS_OK(status)) {
2471 if (open_was_deferred(req->sconn, req->mid)) {
2472 /* We have re-scheduled this call. */
2473 goto out;
2475 reply_openerror(req, status);
2476 goto out;
2479 reply_outbuf(req, 1, 0);
2480 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2482 /* the returned filename is relative to the directory */
2483 s = strrchr_m(fsp->fsp_name->base_name, '/');
2484 if (!s) {
2485 s = fsp->fsp_name->base_name;
2486 } else {
2487 s++;
2490 #if 0
2491 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2492 thing in the byte section. JRA */
2493 SSVALS(p, 0, -1); /* what is this? not in spec */
2494 #endif
2495 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2496 == -1) {
2497 reply_nterror(req, NT_STATUS_NO_MEMORY);
2498 goto out;
2501 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2502 SCVAL(req->outbuf, smb_flg,
2503 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2506 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2507 SCVAL(req->outbuf, smb_flg,
2508 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2511 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2512 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2513 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2514 out:
2515 TALLOC_FREE(smb_fname);
2516 END_PROFILE(SMBctemp);
2517 return;
2520 /*******************************************************************
2521 Check if a user is allowed to rename a file.
2522 ********************************************************************/
2524 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2525 uint16 dirtype)
2527 if (!CAN_WRITE(conn)) {
2528 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2531 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
2532 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2533 /* Only bother to read the DOS attribute if we might deny the
2534 rename on the grounds of attribute missmatch. */
2535 uint32_t fmode = dos_mode(conn, fsp->fsp_name);
2536 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2537 return NT_STATUS_NO_SUCH_FILE;
2541 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2542 if (fsp->posix_open) {
2543 return NT_STATUS_OK;
2546 /* If no pathnames are open below this
2547 directory, allow the rename. */
2549 if (file_find_subpath(fsp)) {
2550 return NT_STATUS_ACCESS_DENIED;
2552 return NT_STATUS_OK;
2555 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2556 return NT_STATUS_OK;
2559 return NT_STATUS_ACCESS_DENIED;
2562 /*******************************************************************
2563 * unlink a file with all relevant access checks
2564 *******************************************************************/
2566 static NTSTATUS do_unlink(connection_struct *conn,
2567 struct smb_request *req,
2568 struct smb_filename *smb_fname,
2569 uint32 dirtype)
2571 uint32 fattr;
2572 files_struct *fsp;
2573 uint32 dirtype_orig = dirtype;
2574 NTSTATUS status;
2575 int ret;
2576 bool posix_paths = lp_posix_pathnames();
2578 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2579 smb_fname_str_dbg(smb_fname),
2580 dirtype));
2582 if (!CAN_WRITE(conn)) {
2583 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2586 if (posix_paths) {
2587 ret = SMB_VFS_LSTAT(conn, smb_fname);
2588 } else {
2589 ret = SMB_VFS_STAT(conn, smb_fname);
2591 if (ret != 0) {
2592 return map_nt_error_from_unix(errno);
2595 fattr = dos_mode(conn, smb_fname);
2597 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2598 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
2601 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
2602 if (!dirtype) {
2603 return NT_STATUS_NO_SUCH_FILE;
2606 if (!dir_check_ftype(conn, fattr, dirtype)) {
2607 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2608 return NT_STATUS_FILE_IS_A_DIRECTORY;
2610 return NT_STATUS_NO_SUCH_FILE;
2613 if (dirtype_orig & 0x8000) {
2614 /* These will never be set for POSIX. */
2615 return NT_STATUS_NO_SUCH_FILE;
2618 #if 0
2619 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2620 return NT_STATUS_FILE_IS_A_DIRECTORY;
2623 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2624 return NT_STATUS_NO_SUCH_FILE;
2627 if (dirtype & 0xFF00) {
2628 /* These will never be set for POSIX. */
2629 return NT_STATUS_NO_SUCH_FILE;
2632 dirtype &= 0xFF;
2633 if (!dirtype) {
2634 return NT_STATUS_NO_SUCH_FILE;
2637 /* Can't delete a directory. */
2638 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2639 return NT_STATUS_FILE_IS_A_DIRECTORY;
2641 #endif
2643 #if 0 /* JRATEST */
2644 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
2645 return NT_STATUS_OBJECT_NAME_INVALID;
2646 #endif /* JRATEST */
2648 /* On open checks the open itself will check the share mode, so
2649 don't do it here as we'll get it wrong. */
2651 status = SMB_VFS_CREATE_FILE
2652 (conn, /* conn */
2653 req, /* req */
2654 0, /* root_dir_fid */
2655 smb_fname, /* fname */
2656 DELETE_ACCESS, /* access_mask */
2657 FILE_SHARE_NONE, /* share_access */
2658 FILE_OPEN, /* create_disposition*/
2659 FILE_NON_DIRECTORY_FILE, /* create_options */
2660 /* file_attributes */
2661 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2662 FILE_ATTRIBUTE_NORMAL,
2663 0, /* oplock_request */
2664 0, /* allocation_size */
2665 0, /* private_flags */
2666 NULL, /* sd */
2667 NULL, /* ea_list */
2668 &fsp, /* result */
2669 NULL); /* pinfo */
2671 if (!NT_STATUS_IS_OK(status)) {
2672 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2673 nt_errstr(status)));
2674 return status;
2677 status = can_set_delete_on_close(fsp, fattr);
2678 if (!NT_STATUS_IS_OK(status)) {
2679 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2680 "(%s)\n",
2681 smb_fname_str_dbg(smb_fname),
2682 nt_errstr(status)));
2683 close_file(req, fsp, NORMAL_CLOSE);
2684 return status;
2687 /* The set is across all open files on this dev/inode pair. */
2688 if (!set_delete_on_close(fsp, True,
2689 conn->session_info->security_token,
2690 conn->session_info->unix_token)) {
2691 close_file(req, fsp, NORMAL_CLOSE);
2692 return NT_STATUS_ACCESS_DENIED;
2695 return close_file(req, fsp, NORMAL_CLOSE);
2698 /****************************************************************************
2699 The guts of the unlink command, split out so it may be called by the NT SMB
2700 code.
2701 ****************************************************************************/
2703 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2704 uint32 dirtype, struct smb_filename *smb_fname,
2705 bool has_wild)
2707 char *fname_dir = NULL;
2708 char *fname_mask = NULL;
2709 int count=0;
2710 NTSTATUS status = NT_STATUS_OK;
2711 TALLOC_CTX *ctx = talloc_tos();
2713 /* Split up the directory from the filename/mask. */
2714 status = split_fname_dir_mask(ctx, smb_fname->base_name,
2715 &fname_dir, &fname_mask);
2716 if (!NT_STATUS_IS_OK(status)) {
2717 goto out;
2721 * We should only check the mangled cache
2722 * here if unix_convert failed. This means
2723 * that the path in 'mask' doesn't exist
2724 * on the file system and so we need to look
2725 * for a possible mangle. This patch from
2726 * Tine Smukavec <valentin.smukavec@hermes.si>.
2729 if (!VALID_STAT(smb_fname->st) &&
2730 mangle_is_mangled(fname_mask, conn->params)) {
2731 char *new_mask = NULL;
2732 mangle_lookup_name_from_8_3(ctx, fname_mask,
2733 &new_mask, conn->params);
2734 if (new_mask) {
2735 TALLOC_FREE(fname_mask);
2736 fname_mask = new_mask;
2740 if (!has_wild) {
2743 * Only one file needs to be unlinked. Append the mask back
2744 * onto the directory.
2746 TALLOC_FREE(smb_fname->base_name);
2747 if (ISDOT(fname_dir)) {
2748 /* Ensure we use canonical names on open. */
2749 smb_fname->base_name = talloc_asprintf(smb_fname,
2750 "%s",
2751 fname_mask);
2752 } else {
2753 smb_fname->base_name = talloc_asprintf(smb_fname,
2754 "%s/%s",
2755 fname_dir,
2756 fname_mask);
2758 if (!smb_fname->base_name) {
2759 status = NT_STATUS_NO_MEMORY;
2760 goto out;
2762 if (dirtype == 0) {
2763 dirtype = FILE_ATTRIBUTE_NORMAL;
2766 status = check_name(conn, smb_fname->base_name);
2767 if (!NT_STATUS_IS_OK(status)) {
2768 goto out;
2771 status = do_unlink(conn, req, smb_fname, dirtype);
2772 if (!NT_STATUS_IS_OK(status)) {
2773 goto out;
2776 count++;
2777 } else {
2778 struct smb_Dir *dir_hnd = NULL;
2779 long offset = 0;
2780 const char *dname = NULL;
2781 char *talloced = NULL;
2783 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
2784 status = NT_STATUS_OBJECT_NAME_INVALID;
2785 goto out;
2788 if (strequal(fname_mask,"????????.???")) {
2789 TALLOC_FREE(fname_mask);
2790 fname_mask = talloc_strdup(ctx, "*");
2791 if (!fname_mask) {
2792 status = NT_STATUS_NO_MEMORY;
2793 goto out;
2797 status = check_name(conn, fname_dir);
2798 if (!NT_STATUS_IS_OK(status)) {
2799 goto out;
2802 dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask,
2803 dirtype);
2804 if (dir_hnd == NULL) {
2805 status = map_nt_error_from_unix(errno);
2806 goto out;
2809 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2810 the pattern matches against the long name, otherwise the short name
2811 We don't implement this yet XXXX
2814 status = NT_STATUS_NO_SUCH_FILE;
2816 while ((dname = ReadDirName(dir_hnd, &offset,
2817 &smb_fname->st, &talloced))) {
2818 TALLOC_CTX *frame = talloc_stackframe();
2820 if (!is_visible_file(conn, fname_dir, dname,
2821 &smb_fname->st, true)) {
2822 TALLOC_FREE(frame);
2823 TALLOC_FREE(talloced);
2824 continue;
2827 /* Quick check for "." and ".." */
2828 if (ISDOT(dname) || ISDOTDOT(dname)) {
2829 TALLOC_FREE(frame);
2830 TALLOC_FREE(talloced);
2831 continue;
2834 if(!mask_match(dname, fname_mask,
2835 conn->case_sensitive)) {
2836 TALLOC_FREE(frame);
2837 TALLOC_FREE(talloced);
2838 continue;
2841 TALLOC_FREE(smb_fname->base_name);
2842 if (ISDOT(fname_dir)) {
2843 /* Ensure we use canonical names on open. */
2844 smb_fname->base_name =
2845 talloc_asprintf(smb_fname, "%s",
2846 dname);
2847 } else {
2848 smb_fname->base_name =
2849 talloc_asprintf(smb_fname, "%s/%s",
2850 fname_dir, dname);
2853 if (!smb_fname->base_name) {
2854 TALLOC_FREE(dir_hnd);
2855 status = NT_STATUS_NO_MEMORY;
2856 TALLOC_FREE(frame);
2857 TALLOC_FREE(talloced);
2858 goto out;
2861 status = check_name(conn, smb_fname->base_name);
2862 if (!NT_STATUS_IS_OK(status)) {
2863 TALLOC_FREE(dir_hnd);
2864 TALLOC_FREE(frame);
2865 TALLOC_FREE(talloced);
2866 goto out;
2869 status = do_unlink(conn, req, smb_fname, dirtype);
2870 if (!NT_STATUS_IS_OK(status)) {
2871 TALLOC_FREE(frame);
2872 TALLOC_FREE(talloced);
2873 continue;
2876 count++;
2877 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
2878 smb_fname->base_name));
2880 TALLOC_FREE(frame);
2881 TALLOC_FREE(talloced);
2883 TALLOC_FREE(dir_hnd);
2886 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
2887 status = map_nt_error_from_unix(errno);
2890 out:
2891 TALLOC_FREE(fname_dir);
2892 TALLOC_FREE(fname_mask);
2893 return status;
2896 /****************************************************************************
2897 Reply to a unlink
2898 ****************************************************************************/
2900 void reply_unlink(struct smb_request *req)
2902 connection_struct *conn = req->conn;
2903 char *name = NULL;
2904 struct smb_filename *smb_fname = NULL;
2905 uint32 dirtype;
2906 NTSTATUS status;
2907 bool path_contains_wcard = False;
2908 TALLOC_CTX *ctx = talloc_tos();
2910 START_PROFILE(SMBunlink);
2912 if (req->wct < 1) {
2913 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2914 goto out;
2917 dirtype = SVAL(req->vwv+0, 0);
2919 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
2920 STR_TERMINATE, &status,
2921 &path_contains_wcard);
2922 if (!NT_STATUS_IS_OK(status)) {
2923 reply_nterror(req, status);
2924 goto out;
2927 status = filename_convert(ctx, conn,
2928 req->flags2 & FLAGS2_DFS_PATHNAMES,
2929 name,
2930 UCF_COND_ALLOW_WCARD_LCOMP,
2931 &path_contains_wcard,
2932 &smb_fname);
2933 if (!NT_STATUS_IS_OK(status)) {
2934 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2935 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2936 ERRSRV, ERRbadpath);
2937 goto out;
2939 reply_nterror(req, status);
2940 goto out;
2943 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
2945 status = unlink_internals(conn, req, dirtype, smb_fname,
2946 path_contains_wcard);
2947 if (!NT_STATUS_IS_OK(status)) {
2948 if (open_was_deferred(req->sconn, req->mid)) {
2949 /* We have re-scheduled this call. */
2950 goto out;
2952 reply_nterror(req, status);
2953 goto out;
2956 reply_outbuf(req, 0, 0);
2957 out:
2958 TALLOC_FREE(smb_fname);
2959 END_PROFILE(SMBunlink);
2960 return;
2963 /****************************************************************************
2964 Fail for readbraw.
2965 ****************************************************************************/
2967 static void fail_readraw(void)
2969 const char *errstr = talloc_asprintf(talloc_tos(),
2970 "FAIL ! reply_readbraw: socket write fail (%s)",
2971 strerror(errno));
2972 if (!errstr) {
2973 errstr = "";
2975 exit_server_cleanly(errstr);
2978 /****************************************************************************
2979 Fake (read/write) sendfile. Returns -1 on read or write fail.
2980 ****************************************************************************/
2982 ssize_t fake_sendfile(files_struct *fsp, off_t startpos, size_t nread)
2984 size_t bufsize;
2985 size_t tosend = nread;
2986 char *buf;
2988 if (nread == 0) {
2989 return 0;
2992 bufsize = MIN(nread, 65536);
2994 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
2995 return -1;
2998 while (tosend > 0) {
2999 ssize_t ret;
3000 size_t cur_read;
3002 if (tosend > bufsize) {
3003 cur_read = bufsize;
3004 } else {
3005 cur_read = tosend;
3007 ret = read_file(fsp,buf,startpos,cur_read);
3008 if (ret == -1) {
3009 SAFE_FREE(buf);
3010 return -1;
3013 /* If we had a short read, fill with zeros. */
3014 if (ret < cur_read) {
3015 memset(buf + ret, '\0', cur_read - ret);
3018 if (write_data(fsp->conn->sconn->sock, buf, cur_read)
3019 != cur_read) {
3020 char addr[INET6_ADDRSTRLEN];
3022 * Try and give an error message saying what
3023 * client failed.
3025 DEBUG(0, ("write_data failed for client %s. "
3026 "Error %s\n",
3027 get_peer_addr(fsp->conn->sconn->sock, addr,
3028 sizeof(addr)),
3029 strerror(errno)));
3030 SAFE_FREE(buf);
3031 return -1;
3033 tosend -= cur_read;
3034 startpos += cur_read;
3037 SAFE_FREE(buf);
3038 return (ssize_t)nread;
3041 /****************************************************************************
3042 Deal with the case of sendfile reading less bytes from the file than
3043 requested. Fill with zeros (all we can do).
3044 ****************************************************************************/
3046 void sendfile_short_send(files_struct *fsp,
3047 ssize_t nread,
3048 size_t headersize,
3049 size_t smb_maxcnt)
3051 #define SHORT_SEND_BUFSIZE 1024
3052 if (nread < headersize) {
3053 DEBUG(0,("sendfile_short_send: sendfile failed to send "
3054 "header for file %s (%s). Terminating\n",
3055 fsp_str_dbg(fsp), strerror(errno)));
3056 exit_server_cleanly("sendfile_short_send failed");
3059 nread -= headersize;
3061 if (nread < smb_maxcnt) {
3062 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
3063 if (!buf) {
3064 exit_server_cleanly("sendfile_short_send: "
3065 "malloc failed");
3068 DEBUG(0,("sendfile_short_send: filling truncated file %s "
3069 "with zeros !\n", fsp_str_dbg(fsp)));
3071 while (nread < smb_maxcnt) {
3073 * We asked for the real file size and told sendfile
3074 * to not go beyond the end of the file. But it can
3075 * happen that in between our fstat call and the
3076 * sendfile call the file was truncated. This is very
3077 * bad because we have already announced the larger
3078 * number of bytes to the client.
3080 * The best we can do now is to send 0-bytes, just as
3081 * a read from a hole in a sparse file would do.
3083 * This should happen rarely enough that I don't care
3084 * about efficiency here :-)
3086 size_t to_write;
3088 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
3089 if (write_data(fsp->conn->sconn->sock, buf, to_write)
3090 != to_write) {
3091 char addr[INET6_ADDRSTRLEN];
3093 * Try and give an error message saying what
3094 * client failed.
3096 DEBUG(0, ("write_data failed for client %s. "
3097 "Error %s\n",
3098 get_peer_addr(
3099 fsp->conn->sconn->sock, addr,
3100 sizeof(addr)),
3101 strerror(errno)));
3102 exit_server_cleanly("sendfile_short_send: "
3103 "write_data failed");
3105 nread += to_write;
3107 SAFE_FREE(buf);
3111 /****************************************************************************
3112 Return a readbraw error (4 bytes of zero).
3113 ****************************************************************************/
3115 static void reply_readbraw_error(struct smbd_server_connection *sconn)
3117 char header[4];
3119 SIVAL(header,0,0);
3121 smbd_lock_socket(sconn);
3122 if (write_data(sconn->sock,header,4) != 4) {
3123 char addr[INET6_ADDRSTRLEN];
3125 * Try and give an error message saying what
3126 * client failed.
3128 DEBUG(0, ("write_data failed for client %s. "
3129 "Error %s\n",
3130 get_peer_addr(sconn->sock, addr, sizeof(addr)),
3131 strerror(errno)));
3133 fail_readraw();
3135 smbd_unlock_socket(sconn);
3138 /****************************************************************************
3139 Use sendfile in readbraw.
3140 ****************************************************************************/
3142 static void send_file_readbraw(connection_struct *conn,
3143 struct smb_request *req,
3144 files_struct *fsp,
3145 off_t startpos,
3146 size_t nread,
3147 ssize_t mincount)
3149 struct smbd_server_connection *sconn = req->sconn;
3150 char *outbuf = NULL;
3151 ssize_t ret=0;
3154 * We can only use sendfile on a non-chained packet
3155 * but we can use on a non-oplocked file. tridge proved this
3156 * on a train in Germany :-). JRA.
3157 * reply_readbraw has already checked the length.
3160 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3161 (fsp->wcp == NULL) &&
3162 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3163 ssize_t sendfile_read = -1;
3164 char header[4];
3165 DATA_BLOB header_blob;
3167 _smb_setlen(header,nread);
3168 header_blob = data_blob_const(header, 4);
3170 sendfile_read = SMB_VFS_SENDFILE(sconn->sock, fsp,
3171 &header_blob, startpos,
3172 nread);
3173 if (sendfile_read == -1) {
3174 /* Returning ENOSYS means no data at all was sent.
3175 * Do this as a normal read. */
3176 if (errno == ENOSYS) {
3177 goto normal_readbraw;
3181 * Special hack for broken Linux with no working sendfile. If we
3182 * return EINTR we sent the header but not the rest of the data.
3183 * Fake this up by doing read/write calls.
3185 if (errno == EINTR) {
3186 /* Ensure we don't do this again. */
3187 set_use_sendfile(SNUM(conn), False);
3188 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3190 if (fake_sendfile(fsp, startpos, nread) == -1) {
3191 DEBUG(0,("send_file_readbraw: "
3192 "fake_sendfile failed for "
3193 "file %s (%s).\n",
3194 fsp_str_dbg(fsp),
3195 strerror(errno)));
3196 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3198 return;
3201 DEBUG(0,("send_file_readbraw: sendfile failed for "
3202 "file %s (%s). Terminating\n",
3203 fsp_str_dbg(fsp), strerror(errno)));
3204 exit_server_cleanly("send_file_readbraw sendfile failed");
3205 } else if (sendfile_read == 0) {
3207 * Some sendfile implementations return 0 to indicate
3208 * that there was a short read, but nothing was
3209 * actually written to the socket. In this case,
3210 * fallback to the normal read path so the header gets
3211 * the correct byte count.
3213 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3214 "bytes falling back to the normal read: "
3215 "%s\n", fsp_str_dbg(fsp)));
3216 goto normal_readbraw;
3219 /* Deal with possible short send. */
3220 if (sendfile_read != 4+nread) {
3221 sendfile_short_send(fsp, sendfile_read, 4, nread);
3223 return;
3226 normal_readbraw:
3228 outbuf = talloc_array(NULL, char, nread+4);
3229 if (!outbuf) {
3230 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3231 (unsigned)(nread+4)));
3232 reply_readbraw_error(sconn);
3233 return;
3236 if (nread > 0) {
3237 ret = read_file(fsp,outbuf+4,startpos,nread);
3238 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3239 if (ret < mincount)
3240 ret = 0;
3241 #else
3242 if (ret < nread)
3243 ret = 0;
3244 #endif
3247 _smb_setlen(outbuf,ret);
3248 if (write_data(sconn->sock, outbuf, 4+ret) != 4+ret) {
3249 char addr[INET6_ADDRSTRLEN];
3251 * Try and give an error message saying what
3252 * client failed.
3254 DEBUG(0, ("write_data failed for client %s. "
3255 "Error %s\n",
3256 get_peer_addr(fsp->conn->sconn->sock, addr,
3257 sizeof(addr)),
3258 strerror(errno)));
3260 fail_readraw();
3263 TALLOC_FREE(outbuf);
3266 /****************************************************************************
3267 Reply to a readbraw (core+ protocol).
3268 ****************************************************************************/
3270 void reply_readbraw(struct smb_request *req)
3272 connection_struct *conn = req->conn;
3273 struct smbd_server_connection *sconn = req->sconn;
3274 ssize_t maxcount,mincount;
3275 size_t nread = 0;
3276 off_t startpos;
3277 files_struct *fsp;
3278 struct lock_struct lock;
3279 off_t size = 0;
3281 START_PROFILE(SMBreadbraw);
3283 if (srv_is_signing_active(sconn) ||
3284 is_encrypted_packet(sconn, req->inbuf)) {
3285 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3286 "raw reads/writes are disallowed.");
3289 if (req->wct < 8) {
3290 reply_readbraw_error(sconn);
3291 END_PROFILE(SMBreadbraw);
3292 return;
3295 if (sconn->smb1.echo_handler.trusted_fde) {
3296 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3297 "'async smb echo handler = yes'\n"));
3298 reply_readbraw_error(sconn);
3299 END_PROFILE(SMBreadbraw);
3300 return;
3304 * Special check if an oplock break has been issued
3305 * and the readraw request croses on the wire, we must
3306 * return a zero length response here.
3309 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3312 * We have to do a check_fsp by hand here, as
3313 * we must always return 4 zero bytes on error,
3314 * not a NTSTATUS.
3317 if (!fsp || !conn || conn != fsp->conn ||
3318 req->vuid != fsp->vuid ||
3319 fsp->is_directory || fsp->fh->fd == -1) {
3321 * fsp could be NULL here so use the value from the packet. JRA.
3323 DEBUG(3,("reply_readbraw: fnum %d not valid "
3324 "- cache prime?\n",
3325 (int)SVAL(req->vwv+0, 0)));
3326 reply_readbraw_error(sconn);
3327 END_PROFILE(SMBreadbraw);
3328 return;
3331 /* Do a "by hand" version of CHECK_READ. */
3332 if (!(fsp->can_read ||
3333 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3334 (fsp->access_mask & FILE_EXECUTE)))) {
3335 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3336 (int)SVAL(req->vwv+0, 0)));
3337 reply_readbraw_error(sconn);
3338 END_PROFILE(SMBreadbraw);
3339 return;
3342 flush_write_cache(fsp, READRAW_FLUSH);
3344 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3345 if(req->wct == 10) {
3347 * This is a large offset (64 bit) read.
3350 startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32);
3352 if(startpos < 0) {
3353 DEBUG(0,("reply_readbraw: negative 64 bit "
3354 "readraw offset (%.0f) !\n",
3355 (double)startpos ));
3356 reply_readbraw_error(sconn);
3357 END_PROFILE(SMBreadbraw);
3358 return;
3362 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3363 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3365 /* ensure we don't overrun the packet size */
3366 maxcount = MIN(65535,maxcount);
3368 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3369 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3370 &lock);
3372 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3373 reply_readbraw_error(sconn);
3374 END_PROFILE(SMBreadbraw);
3375 return;
3378 if (fsp_stat(fsp) == 0) {
3379 size = fsp->fsp_name->st.st_ex_size;
3382 if (startpos >= size) {
3383 nread = 0;
3384 } else {
3385 nread = MIN(maxcount,(size - startpos));
3388 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3389 if (nread < mincount)
3390 nread = 0;
3391 #endif
3393 DEBUG( 3, ( "reply_readbraw: %s start=%.0f max=%lu "
3394 "min=%lu nread=%lu\n",
3395 fsp_fnum_dbg(fsp), (double)startpos,
3396 (unsigned long)maxcount,
3397 (unsigned long)mincount,
3398 (unsigned long)nread ) );
3400 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3402 DEBUG(5,("reply_readbraw finished\n"));
3404 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3406 END_PROFILE(SMBreadbraw);
3407 return;
3410 #undef DBGC_CLASS
3411 #define DBGC_CLASS DBGC_LOCKING
3413 /****************************************************************************
3414 Reply to a lockread (core+ protocol).
3415 ****************************************************************************/
3417 void reply_lockread(struct smb_request *req)
3419 connection_struct *conn = req->conn;
3420 ssize_t nread = -1;
3421 char *data;
3422 off_t startpos;
3423 size_t numtoread;
3424 NTSTATUS status;
3425 files_struct *fsp;
3426 struct byte_range_lock *br_lck = NULL;
3427 char *p = NULL;
3428 struct smbd_server_connection *sconn = req->sconn;
3430 START_PROFILE(SMBlockread);
3432 if (req->wct < 5) {
3433 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3434 END_PROFILE(SMBlockread);
3435 return;
3438 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3440 if (!check_fsp(conn, req, fsp)) {
3441 END_PROFILE(SMBlockread);
3442 return;
3445 if (!CHECK_READ(fsp,req)) {
3446 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3447 END_PROFILE(SMBlockread);
3448 return;
3451 numtoread = SVAL(req->vwv+1, 0);
3452 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3454 numtoread = MIN(BUFFER_SIZE - (smb_size + 3*2 + 3), numtoread);
3456 reply_outbuf(req, 5, numtoread + 3);
3458 data = smb_buf(req->outbuf) + 3;
3461 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3462 * protocol request that predates the read/write lock concept.
3463 * Thus instead of asking for a read lock here we need to ask
3464 * for a write lock. JRA.
3465 * Note that the requested lock size is unaffected by max_recv.
3468 br_lck = do_lock(req->sconn->msg_ctx,
3469 fsp,
3470 (uint64_t)req->smbpid,
3471 (uint64_t)numtoread,
3472 (uint64_t)startpos,
3473 WRITE_LOCK,
3474 WINDOWS_LOCK,
3475 False, /* Non-blocking lock. */
3476 &status,
3477 NULL,
3478 NULL);
3479 TALLOC_FREE(br_lck);
3481 if (NT_STATUS_V(status)) {
3482 reply_nterror(req, status);
3483 END_PROFILE(SMBlockread);
3484 return;
3488 * However the requested READ size IS affected by max_recv. Insanity.... JRA.
3491 if (numtoread > sconn->smb1.negprot.max_recv) {
3492 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \
3493 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3494 (unsigned int)numtoread,
3495 (unsigned int)sconn->smb1.negprot.max_recv));
3496 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3498 nread = read_file(fsp,data,startpos,numtoread);
3500 if (nread < 0) {
3501 reply_nterror(req, map_nt_error_from_unix(errno));
3502 END_PROFILE(SMBlockread);
3503 return;
3506 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3508 SSVAL(req->outbuf,smb_vwv0,nread);
3509 SSVAL(req->outbuf,smb_vwv5,nread+3);
3510 p = smb_buf(req->outbuf);
3511 SCVAL(p,0,0); /* pad byte. */
3512 SSVAL(p,1,nread);
3514 DEBUG(3,("lockread %s num=%d nread=%d\n",
3515 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3517 END_PROFILE(SMBlockread);
3518 return;
3521 #undef DBGC_CLASS
3522 #define DBGC_CLASS DBGC_ALL
3524 /****************************************************************************
3525 Reply to a read.
3526 ****************************************************************************/
3528 void reply_read(struct smb_request *req)
3530 connection_struct *conn = req->conn;
3531 size_t numtoread;
3532 ssize_t nread = 0;
3533 char *data;
3534 off_t startpos;
3535 int outsize = 0;
3536 files_struct *fsp;
3537 struct lock_struct lock;
3538 struct smbd_server_connection *sconn = req->sconn;
3540 START_PROFILE(SMBread);
3542 if (req->wct < 3) {
3543 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3544 END_PROFILE(SMBread);
3545 return;
3548 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3550 if (!check_fsp(conn, req, fsp)) {
3551 END_PROFILE(SMBread);
3552 return;
3555 if (!CHECK_READ(fsp,req)) {
3556 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3557 END_PROFILE(SMBread);
3558 return;
3561 numtoread = SVAL(req->vwv+1, 0);
3562 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3564 numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
3567 * The requested read size cannot be greater than max_recv. JRA.
3569 if (numtoread > sconn->smb1.negprot.max_recv) {
3570 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \
3571 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3572 (unsigned int)numtoread,
3573 (unsigned int)sconn->smb1.negprot.max_recv));
3574 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3577 reply_outbuf(req, 5, numtoread+3);
3579 data = smb_buf(req->outbuf) + 3;
3581 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3582 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3583 &lock);
3585 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3586 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3587 END_PROFILE(SMBread);
3588 return;
3591 if (numtoread > 0)
3592 nread = read_file(fsp,data,startpos,numtoread);
3594 if (nread < 0) {
3595 reply_nterror(req, map_nt_error_from_unix(errno));
3596 goto strict_unlock;
3599 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3601 SSVAL(req->outbuf,smb_vwv0,nread);
3602 SSVAL(req->outbuf,smb_vwv5,nread+3);
3603 SCVAL(smb_buf(req->outbuf),0,1);
3604 SSVAL(smb_buf(req->outbuf),1,nread);
3606 DEBUG(3, ("read %s num=%d nread=%d\n",
3607 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3609 strict_unlock:
3610 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3612 END_PROFILE(SMBread);
3613 return;
3616 /****************************************************************************
3617 Setup readX header.
3618 ****************************************************************************/
3620 static int setup_readX_header(struct smb_request *req, char *outbuf,
3621 size_t smb_maxcnt)
3623 int outsize;
3625 outsize = srv_set_message(outbuf,12,smb_maxcnt,False);
3627 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3629 SCVAL(outbuf,smb_vwv0,0xFF);
3630 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3631 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3632 SSVAL(outbuf,smb_vwv6,
3633 (smb_wct - 4) /* offset from smb header to wct */
3634 + 1 /* the wct field */
3635 + 12 * sizeof(uint16_t) /* vwv */
3636 + 2); /* the buflen field */
3637 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3638 SSVAL(outbuf,smb_vwv11,smb_maxcnt);
3639 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3640 _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
3641 return outsize;
3644 /****************************************************************************
3645 Reply to a read and X - possibly using sendfile.
3646 ****************************************************************************/
3648 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3649 files_struct *fsp, off_t startpos,
3650 size_t smb_maxcnt)
3652 ssize_t nread = -1;
3653 struct lock_struct lock;
3654 int saved_errno = 0;
3656 if(fsp_stat(fsp) == -1) {
3657 reply_nterror(req, map_nt_error_from_unix(errno));
3658 return;
3661 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3662 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3663 &lock);
3665 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3666 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3667 return;
3670 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3671 (startpos > fsp->fsp_name->st.st_ex_size)
3672 || (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3674 * We already know that we would do a short read, so don't
3675 * try the sendfile() path.
3677 goto nosendfile_read;
3681 * We can only use sendfile on a non-chained packet
3682 * but we can use on a non-oplocked file. tridge proved this
3683 * on a train in Germany :-). JRA.
3686 if (!req_is_in_chain(req) &&
3687 !is_encrypted_packet(req->sconn, req->inbuf) &&
3688 (fsp->base_fsp == NULL) &&
3689 (fsp->wcp == NULL) &&
3690 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3691 uint8 headerbuf[smb_size + 12 * 2];
3692 DATA_BLOB header;
3695 * Set up the packet header before send. We
3696 * assume here the sendfile will work (get the
3697 * correct amount of data).
3700 header = data_blob_const(headerbuf, sizeof(headerbuf));
3702 construct_reply_common_req(req, (char *)headerbuf);
3703 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3705 nread = SMB_VFS_SENDFILE(req->sconn->sock, fsp, &header,
3706 startpos, smb_maxcnt);
3707 if (nread == -1) {
3708 /* Returning ENOSYS means no data at all was sent.
3709 Do this as a normal read. */
3710 if (errno == ENOSYS) {
3711 goto normal_read;
3715 * Special hack for broken Linux with no working sendfile. If we
3716 * return EINTR we sent the header but not the rest of the data.
3717 * Fake this up by doing read/write calls.
3720 if (errno == EINTR) {
3721 /* Ensure we don't do this again. */
3722 set_use_sendfile(SNUM(conn), False);
3723 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3724 nread = fake_sendfile(fsp, startpos,
3725 smb_maxcnt);
3726 if (nread == -1) {
3727 DEBUG(0,("send_file_readX: "
3728 "fake_sendfile failed for "
3729 "file %s (%s).\n",
3730 fsp_str_dbg(fsp),
3731 strerror(errno)));
3732 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3734 DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
3735 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3736 /* No outbuf here means successful sendfile. */
3737 goto strict_unlock;
3740 DEBUG(0,("send_file_readX: sendfile failed for file "
3741 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3742 strerror(errno)));
3743 exit_server_cleanly("send_file_readX sendfile failed");
3744 } else if (nread == 0) {
3746 * Some sendfile implementations return 0 to indicate
3747 * that there was a short read, but nothing was
3748 * actually written to the socket. In this case,
3749 * fallback to the normal read path so the header gets
3750 * the correct byte count.
3752 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
3753 "falling back to the normal read: %s\n",
3754 fsp_str_dbg(fsp)));
3755 goto normal_read;
3758 DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n",
3759 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3761 /* Deal with possible short send. */
3762 if (nread != smb_maxcnt + sizeof(headerbuf)) {
3763 sendfile_short_send(fsp, nread, sizeof(headerbuf), smb_maxcnt);
3765 /* No outbuf here means successful sendfile. */
3766 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
3767 SMB_PERFCOUNT_END(&req->pcd);
3768 goto strict_unlock;
3771 normal_read:
3773 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3774 uint8 headerbuf[smb_size + 2*12];
3776 construct_reply_common_req(req, (char *)headerbuf);
3777 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3779 /* Send out the header. */
3780 if (write_data(req->sconn->sock, (char *)headerbuf,
3781 sizeof(headerbuf)) != sizeof(headerbuf)) {
3783 char addr[INET6_ADDRSTRLEN];
3785 * Try and give an error message saying what
3786 * client failed.
3788 DEBUG(0, ("write_data failed for client %s. "
3789 "Error %s\n",
3790 get_peer_addr(req->sconn->sock, addr,
3791 sizeof(addr)),
3792 strerror(errno)));
3794 DEBUG(0,("send_file_readX: write_data failed for file "
3795 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3796 strerror(errno)));
3797 exit_server_cleanly("send_file_readX sendfile failed");
3799 nread = fake_sendfile(fsp, startpos, smb_maxcnt);
3800 if (nread == -1) {
3801 DEBUG(0,("send_file_readX: fake_sendfile failed for "
3802 "file %s (%s).\n", fsp_str_dbg(fsp),
3803 strerror(errno)));
3804 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3806 goto strict_unlock;
3809 nosendfile_read:
3811 reply_outbuf(req, 12, smb_maxcnt);
3812 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
3813 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
3815 nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt);
3816 saved_errno = errno;
3818 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3820 if (nread < 0) {
3821 reply_nterror(req, map_nt_error_from_unix(saved_errno));
3822 return;
3825 setup_readX_header(req, (char *)req->outbuf, nread);
3827 DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
3828 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3829 return;
3831 strict_unlock:
3832 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3833 TALLOC_FREE(req->outbuf);
3834 return;
3837 /****************************************************************************
3838 Reply to a read and X.
3839 ****************************************************************************/
3841 void reply_read_and_X(struct smb_request *req)
3843 struct smbd_server_connection *sconn = req->sconn;
3844 connection_struct *conn = req->conn;
3845 files_struct *fsp;
3846 off_t startpos;
3847 size_t smb_maxcnt;
3848 bool big_readX = False;
3849 #if 0
3850 size_t smb_mincnt = SVAL(req->vwv+6, 0);
3851 #endif
3853 START_PROFILE(SMBreadX);
3855 if ((req->wct != 10) && (req->wct != 12)) {
3856 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3857 return;
3860 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
3861 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3862 smb_maxcnt = SVAL(req->vwv+5, 0);
3864 /* If it's an IPC, pass off the pipe handler. */
3865 if (IS_IPC(conn)) {
3866 reply_pipe_read_and_X(req);
3867 END_PROFILE(SMBreadX);
3868 return;
3871 if (!check_fsp(conn, req, fsp)) {
3872 END_PROFILE(SMBreadX);
3873 return;
3876 if (!CHECK_READ(fsp,req)) {
3877 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3878 END_PROFILE(SMBreadX);
3879 return;
3882 if ((sconn->smb1.unix_info.client_cap_low & CIFS_UNIX_LARGE_READ_CAP) ||
3883 (get_remote_arch() == RA_SAMBA)) {
3885 * This is Samba only behavior (up to Samba 3.6)!
3887 * Windows 2008 R2 ignores the upper_size,
3888 * so we do unless unix extentions are active
3889 * or "smbclient" is talking to us.
3891 size_t upper_size = SVAL(req->vwv+7, 0);
3892 smb_maxcnt |= (upper_size<<16);
3893 if (upper_size > 1) {
3894 /* Can't do this on a chained packet. */
3895 if ((CVAL(req->vwv+0, 0) != 0xFF)) {
3896 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3897 END_PROFILE(SMBreadX);
3898 return;
3900 /* We currently don't do this on signed or sealed data. */
3901 if (srv_is_signing_active(req->sconn) ||
3902 is_encrypted_packet(req->sconn, req->inbuf)) {
3903 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3904 END_PROFILE(SMBreadX);
3905 return;
3907 /* Is there room in the reply for this data ? */
3908 if (smb_maxcnt > (0xFFFFFF - (smb_size -4 + 12*2))) {
3909 reply_nterror(req,
3910 NT_STATUS_INVALID_PARAMETER);
3911 END_PROFILE(SMBreadX);
3912 return;
3914 big_readX = True;
3918 if (req->wct == 12) {
3920 * This is a large offset (64 bit) read.
3922 startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
3926 if (!big_readX) {
3927 NTSTATUS status = schedule_aio_read_and_X(conn,
3928 req,
3929 fsp,
3930 startpos,
3931 smb_maxcnt);
3932 if (NT_STATUS_IS_OK(status)) {
3933 /* Read scheduled - we're done. */
3934 goto out;
3936 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
3937 /* Real error - report to client. */
3938 END_PROFILE(SMBreadX);
3939 reply_nterror(req, status);
3940 return;
3942 /* NT_STATUS_RETRY - fall back to sync read. */
3945 smbd_lock_socket(req->sconn);
3946 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
3947 smbd_unlock_socket(req->sconn);
3949 out:
3950 END_PROFILE(SMBreadX);
3951 return;
3954 /****************************************************************************
3955 Error replies to writebraw must have smb_wct == 1. Fix this up.
3956 ****************************************************************************/
3958 void error_to_writebrawerr(struct smb_request *req)
3960 uint8 *old_outbuf = req->outbuf;
3962 reply_outbuf(req, 1, 0);
3964 memcpy(req->outbuf, old_outbuf, smb_size);
3965 TALLOC_FREE(old_outbuf);
3968 /****************************************************************************
3969 Read 4 bytes of a smb packet and return the smb length of the packet.
3970 Store the result in the buffer. This version of the function will
3971 never return a session keepalive (length of zero).
3972 Timeout is in milliseconds.
3973 ****************************************************************************/
3975 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
3976 size_t *len)
3978 uint8_t msgtype = NBSSkeepalive;
3980 while (msgtype == NBSSkeepalive) {
3981 NTSTATUS status;
3983 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
3984 len);
3985 if (!NT_STATUS_IS_OK(status)) {
3986 char addr[INET6_ADDRSTRLEN];
3987 /* Try and give an error message
3988 * saying what client failed. */
3989 DEBUG(0, ("read_fd_with_timeout failed for "
3990 "client %s read error = %s.\n",
3991 get_peer_addr(fd,addr,sizeof(addr)),
3992 nt_errstr(status)));
3993 return status;
3996 msgtype = CVAL(inbuf, 0);
3999 DEBUG(10,("read_smb_length: got smb length of %lu\n",
4000 (unsigned long)len));
4002 return NT_STATUS_OK;
4005 /****************************************************************************
4006 Reply to a writebraw (core+ or LANMAN1.0 protocol).
4007 ****************************************************************************/
4009 void reply_writebraw(struct smb_request *req)
4011 connection_struct *conn = req->conn;
4012 char *buf = NULL;
4013 ssize_t nwritten=0;
4014 ssize_t total_written=0;
4015 size_t numtowrite=0;
4016 size_t tcount;
4017 off_t startpos;
4018 const char *data=NULL;
4019 bool write_through;
4020 files_struct *fsp;
4021 struct lock_struct lock;
4022 NTSTATUS status;
4024 START_PROFILE(SMBwritebraw);
4027 * If we ever reply with an error, it must have the SMB command
4028 * type of SMBwritec, not SMBwriteBraw, as this tells the client
4029 * we're finished.
4031 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
4033 if (srv_is_signing_active(req->sconn)) {
4034 END_PROFILE(SMBwritebraw);
4035 exit_server_cleanly("reply_writebraw: SMB signing is active - "
4036 "raw reads/writes are disallowed.");
4039 if (req->wct < 12) {
4040 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4041 error_to_writebrawerr(req);
4042 END_PROFILE(SMBwritebraw);
4043 return;
4046 if (req->sconn->smb1.echo_handler.trusted_fde) {
4047 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
4048 "'async smb echo handler = yes'\n"));
4049 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
4050 error_to_writebrawerr(req);
4051 END_PROFILE(SMBwritebraw);
4052 return;
4055 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4056 if (!check_fsp(conn, req, fsp)) {
4057 error_to_writebrawerr(req);
4058 END_PROFILE(SMBwritebraw);
4059 return;
4062 if (!CHECK_WRITE(fsp)) {
4063 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4064 error_to_writebrawerr(req);
4065 END_PROFILE(SMBwritebraw);
4066 return;
4069 tcount = IVAL(req->vwv+1, 0);
4070 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4071 write_through = BITSETW(req->vwv+7,0);
4073 /* We have to deal with slightly different formats depending
4074 on whether we are using the core+ or lanman1.0 protocol */
4076 if(get_Protocol() <= PROTOCOL_COREPLUS) {
4077 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
4078 data = smb_buf_const(req->inbuf);
4079 } else {
4080 numtowrite = SVAL(req->vwv+10, 0);
4081 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
4084 /* Ensure we don't write bytes past the end of this packet. */
4085 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
4086 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4087 error_to_writebrawerr(req);
4088 END_PROFILE(SMBwritebraw);
4089 return;
4092 if (!fsp->print_file) {
4093 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4094 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4095 &lock);
4097 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4098 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4099 error_to_writebrawerr(req);
4100 END_PROFILE(SMBwritebraw);
4101 return;
4105 if (numtowrite>0) {
4106 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4109 DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d "
4110 "wrote=%d sync=%d\n",
4111 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4112 (int)nwritten, (int)write_through));
4114 if (nwritten < (ssize_t)numtowrite) {
4115 reply_nterror(req, NT_STATUS_DISK_FULL);
4116 error_to_writebrawerr(req);
4117 goto strict_unlock;
4120 total_written = nwritten;
4122 /* Allocate a buffer of 64k + length. */
4123 buf = talloc_array(NULL, char, 65540);
4124 if (!buf) {
4125 reply_nterror(req, NT_STATUS_NO_MEMORY);
4126 error_to_writebrawerr(req);
4127 goto strict_unlock;
4130 /* Return a SMBwritebraw message to the redirector to tell
4131 * it to send more bytes */
4133 memcpy(buf, req->inbuf, smb_size);
4134 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4135 SCVAL(buf,smb_com,SMBwritebraw);
4136 SSVALS(buf,smb_vwv0,0xFFFF);
4137 show_msg(buf);
4138 if (!srv_send_smb(req->sconn,
4139 buf,
4140 false, 0, /* no signing */
4141 IS_CONN_ENCRYPTED(conn),
4142 &req->pcd)) {
4143 exit_server_cleanly("reply_writebraw: srv_send_smb "
4144 "failed.");
4147 /* Now read the raw data into the buffer and write it */
4148 status = read_smb_length(req->sconn->sock, buf, SMB_SECONDARY_WAIT,
4149 &numtowrite);
4150 if (!NT_STATUS_IS_OK(status)) {
4151 exit_server_cleanly("secondary writebraw failed");
4154 /* Set up outbuf to return the correct size */
4155 reply_outbuf(req, 1, 0);
4157 if (numtowrite != 0) {
4159 if (numtowrite > 0xFFFF) {
4160 DEBUG(0,("reply_writebraw: Oversize secondary write "
4161 "raw requested (%u). Terminating\n",
4162 (unsigned int)numtowrite ));
4163 exit_server_cleanly("secondary writebraw failed");
4166 if (tcount > nwritten+numtowrite) {
4167 DEBUG(3,("reply_writebraw: Client overestimated the "
4168 "write %d %d %d\n",
4169 (int)tcount,(int)nwritten,(int)numtowrite));
4172 status = read_data(req->sconn->sock, buf+4, numtowrite);
4174 if (!NT_STATUS_IS_OK(status)) {
4175 char addr[INET6_ADDRSTRLEN];
4176 /* Try and give an error message
4177 * saying what client failed. */
4178 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4179 "raw read failed (%s) for client %s. "
4180 "Terminating\n", nt_errstr(status),
4181 get_peer_addr(req->sconn->sock, addr,
4182 sizeof(addr))));
4183 exit_server_cleanly("secondary writebraw failed");
4186 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4187 if (nwritten == -1) {
4188 TALLOC_FREE(buf);
4189 reply_nterror(req, map_nt_error_from_unix(errno));
4190 error_to_writebrawerr(req);
4191 goto strict_unlock;
4194 if (nwritten < (ssize_t)numtowrite) {
4195 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4196 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4199 if (nwritten > 0) {
4200 total_written += nwritten;
4204 TALLOC_FREE(buf);
4205 SSVAL(req->outbuf,smb_vwv0,total_written);
4207 status = sync_file(conn, fsp, write_through);
4208 if (!NT_STATUS_IS_OK(status)) {
4209 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4210 fsp_str_dbg(fsp), nt_errstr(status)));
4211 reply_nterror(req, status);
4212 error_to_writebrawerr(req);
4213 goto strict_unlock;
4216 DEBUG(3,("reply_writebraw: secondart write %s start=%.0f num=%d "
4217 "wrote=%d\n",
4218 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4219 (int)total_written));
4221 if (!fsp->print_file) {
4222 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4225 /* We won't return a status if write through is not selected - this
4226 * follows what WfWg does */
4227 END_PROFILE(SMBwritebraw);
4229 if (!write_through && total_written==tcount) {
4231 #if RABBIT_PELLET_FIX
4233 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4234 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4235 * JRA.
4237 if (!send_keepalive(req->sconn->sock)) {
4238 exit_server_cleanly("reply_writebraw: send of "
4239 "keepalive failed");
4241 #endif
4242 TALLOC_FREE(req->outbuf);
4244 return;
4246 strict_unlock:
4247 if (!fsp->print_file) {
4248 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4251 END_PROFILE(SMBwritebraw);
4252 return;
4255 #undef DBGC_CLASS
4256 #define DBGC_CLASS DBGC_LOCKING
4258 /****************************************************************************
4259 Reply to a writeunlock (core+).
4260 ****************************************************************************/
4262 void reply_writeunlock(struct smb_request *req)
4264 connection_struct *conn = req->conn;
4265 ssize_t nwritten = -1;
4266 size_t numtowrite;
4267 off_t startpos;
4268 const char *data;
4269 NTSTATUS status = NT_STATUS_OK;
4270 files_struct *fsp;
4271 struct lock_struct lock;
4272 int saved_errno = 0;
4274 START_PROFILE(SMBwriteunlock);
4276 if (req->wct < 5) {
4277 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4278 END_PROFILE(SMBwriteunlock);
4279 return;
4282 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4284 if (!check_fsp(conn, req, fsp)) {
4285 END_PROFILE(SMBwriteunlock);
4286 return;
4289 if (!CHECK_WRITE(fsp)) {
4290 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4291 END_PROFILE(SMBwriteunlock);
4292 return;
4295 numtowrite = SVAL(req->vwv+1, 0);
4296 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4297 data = (const char *)req->buf + 3;
4299 if (!fsp->print_file && numtowrite > 0) {
4300 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4301 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4302 &lock);
4304 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4305 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4306 END_PROFILE(SMBwriteunlock);
4307 return;
4311 /* The special X/Open SMB protocol handling of
4312 zero length writes is *NOT* done for
4313 this call */
4314 if(numtowrite == 0) {
4315 nwritten = 0;
4316 } else {
4317 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4318 saved_errno = errno;
4321 status = sync_file(conn, fsp, False /* write through */);
4322 if (!NT_STATUS_IS_OK(status)) {
4323 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4324 fsp_str_dbg(fsp), nt_errstr(status)));
4325 reply_nterror(req, status);
4326 goto strict_unlock;
4329 if(nwritten < 0) {
4330 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4331 goto strict_unlock;
4334 if((nwritten < numtowrite) && (numtowrite != 0)) {
4335 reply_nterror(req, NT_STATUS_DISK_FULL);
4336 goto strict_unlock;
4339 if (numtowrite && !fsp->print_file) {
4340 status = do_unlock(req->sconn->msg_ctx,
4341 fsp,
4342 (uint64_t)req->smbpid,
4343 (uint64_t)numtowrite,
4344 (uint64_t)startpos,
4345 WINDOWS_LOCK);
4347 if (NT_STATUS_V(status)) {
4348 reply_nterror(req, status);
4349 goto strict_unlock;
4353 reply_outbuf(req, 1, 0);
4355 SSVAL(req->outbuf,smb_vwv0,nwritten);
4357 DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
4358 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4360 strict_unlock:
4361 if (numtowrite && !fsp->print_file) {
4362 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4365 END_PROFILE(SMBwriteunlock);
4366 return;
4369 #undef DBGC_CLASS
4370 #define DBGC_CLASS DBGC_ALL
4372 /****************************************************************************
4373 Reply to a write.
4374 ****************************************************************************/
4376 void reply_write(struct smb_request *req)
4378 connection_struct *conn = req->conn;
4379 size_t numtowrite;
4380 ssize_t nwritten = -1;
4381 off_t startpos;
4382 const char *data;
4383 files_struct *fsp;
4384 struct lock_struct lock;
4385 NTSTATUS status;
4386 int saved_errno = 0;
4388 START_PROFILE(SMBwrite);
4390 if (req->wct < 5) {
4391 END_PROFILE(SMBwrite);
4392 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4393 return;
4396 /* If it's an IPC, pass off the pipe handler. */
4397 if (IS_IPC(conn)) {
4398 reply_pipe_write(req);
4399 END_PROFILE(SMBwrite);
4400 return;
4403 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4405 if (!check_fsp(conn, req, fsp)) {
4406 END_PROFILE(SMBwrite);
4407 return;
4410 if (!CHECK_WRITE(fsp)) {
4411 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4412 END_PROFILE(SMBwrite);
4413 return;
4416 numtowrite = SVAL(req->vwv+1, 0);
4417 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4418 data = (const char *)req->buf + 3;
4420 if (!fsp->print_file) {
4421 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4422 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4423 &lock);
4425 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4426 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4427 END_PROFILE(SMBwrite);
4428 return;
4433 * X/Open SMB protocol says that if smb_vwv1 is
4434 * zero then the file size should be extended or
4435 * truncated to the size given in smb_vwv[2-3].
4438 if(numtowrite == 0) {
4440 * This is actually an allocate call, and set EOF. JRA.
4442 nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
4443 if (nwritten < 0) {
4444 reply_nterror(req, NT_STATUS_DISK_FULL);
4445 goto strict_unlock;
4447 nwritten = vfs_set_filelen(fsp, (off_t)startpos);
4448 if (nwritten < 0) {
4449 reply_nterror(req, NT_STATUS_DISK_FULL);
4450 goto strict_unlock;
4452 trigger_write_time_update_immediate(fsp);
4453 } else {
4454 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4457 status = sync_file(conn, fsp, False);
4458 if (!NT_STATUS_IS_OK(status)) {
4459 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4460 fsp_str_dbg(fsp), nt_errstr(status)));
4461 reply_nterror(req, status);
4462 goto strict_unlock;
4465 if(nwritten < 0) {
4466 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4467 goto strict_unlock;
4470 if((nwritten == 0) && (numtowrite != 0)) {
4471 reply_nterror(req, NT_STATUS_DISK_FULL);
4472 goto strict_unlock;
4475 reply_outbuf(req, 1, 0);
4477 SSVAL(req->outbuf,smb_vwv0,nwritten);
4479 if (nwritten < (ssize_t)numtowrite) {
4480 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4481 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4484 DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4486 strict_unlock:
4487 if (!fsp->print_file) {
4488 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4491 END_PROFILE(SMBwrite);
4492 return;
4495 /****************************************************************************
4496 Ensure a buffer is a valid writeX for recvfile purposes.
4497 ****************************************************************************/
4499 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4500 (2*14) + /* word count (including bcc) */ \
4501 1 /* pad byte */)
4503 bool is_valid_writeX_buffer(struct smbd_server_connection *sconn,
4504 const uint8_t *inbuf)
4506 size_t numtowrite;
4507 connection_struct *conn = NULL;
4508 unsigned int doff = 0;
4509 size_t len = smb_len_large(inbuf);
4510 struct smbXsrv_tcon *tcon;
4511 NTSTATUS status;
4512 NTTIME now = 0;
4514 if (is_encrypted_packet(sconn, inbuf)) {
4515 /* Can't do this on encrypted
4516 * connections. */
4517 return false;
4520 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4521 return false;
4524 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4525 CVAL(inbuf,smb_wct) != 14) {
4526 DEBUG(10,("is_valid_writeX_buffer: chained or "
4527 "invalid word length.\n"));
4528 return false;
4531 status = smb1srv_tcon_lookup(sconn->conn, SVAL(inbuf, smb_tid),
4532 now, &tcon);
4533 if (!NT_STATUS_IS_OK(status)) {
4534 DEBUG(10,("is_valid_writeX_buffer: bad tid\n"));
4535 return false;
4537 conn = tcon->compat;
4539 if (IS_IPC(conn)) {
4540 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4541 return false;
4543 if (IS_PRINT(conn)) {
4544 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4545 return false;
4547 doff = SVAL(inbuf,smb_vwv11);
4549 numtowrite = SVAL(inbuf,smb_vwv10);
4551 if (len > doff && len - doff > 0xFFFF) {
4552 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4555 if (numtowrite == 0) {
4556 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4557 return false;
4560 /* Ensure the sizes match up. */
4561 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4562 /* no pad byte...old smbclient :-( */
4563 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4564 (unsigned int)doff,
4565 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4566 return false;
4569 if (len - doff != numtowrite) {
4570 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4571 "len = %u, doff = %u, numtowrite = %u\n",
4572 (unsigned int)len,
4573 (unsigned int)doff,
4574 (unsigned int)numtowrite ));
4575 return false;
4578 DEBUG(10,("is_valid_writeX_buffer: true "
4579 "len = %u, doff = %u, numtowrite = %u\n",
4580 (unsigned int)len,
4581 (unsigned int)doff,
4582 (unsigned int)numtowrite ));
4584 return true;
4587 /****************************************************************************
4588 Reply to a write and X.
4589 ****************************************************************************/
4591 void reply_write_and_X(struct smb_request *req)
4593 connection_struct *conn = req->conn;
4594 files_struct *fsp;
4595 struct lock_struct lock;
4596 off_t startpos;
4597 size_t numtowrite;
4598 bool write_through;
4599 ssize_t nwritten;
4600 unsigned int smb_doff;
4601 unsigned int smblen;
4602 const char *data;
4603 NTSTATUS status;
4604 int saved_errno = 0;
4606 START_PROFILE(SMBwriteX);
4608 if ((req->wct != 12) && (req->wct != 14)) {
4609 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4610 goto out;
4613 numtowrite = SVAL(req->vwv+10, 0);
4614 smb_doff = SVAL(req->vwv+11, 0);
4615 smblen = smb_len(req->inbuf);
4617 if (req->unread_bytes > 0xFFFF ||
4618 (smblen > smb_doff &&
4619 smblen - smb_doff > 0xFFFF)) {
4620 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
4623 if (req->unread_bytes) {
4624 /* Can't do a recvfile write on IPC$ */
4625 if (IS_IPC(conn)) {
4626 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4627 goto out;
4629 if (numtowrite != req->unread_bytes) {
4630 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4631 goto out;
4633 } else {
4634 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4635 smb_doff + numtowrite > smblen) {
4636 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4637 goto out;
4641 /* If it's an IPC, pass off the pipe handler. */
4642 if (IS_IPC(conn)) {
4643 if (req->unread_bytes) {
4644 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4645 goto out;
4647 reply_pipe_write_and_X(req);
4648 goto out;
4651 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4652 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4653 write_through = BITSETW(req->vwv+7,0);
4655 if (!check_fsp(conn, req, fsp)) {
4656 goto out;
4659 if (!CHECK_WRITE(fsp)) {
4660 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4661 goto out;
4664 data = smb_base(req->inbuf) + smb_doff;
4666 if(req->wct == 14) {
4668 * This is a large offset (64 bit) write.
4670 startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
4674 /* X/Open SMB protocol says that, unlike SMBwrite
4675 if the length is zero then NO truncation is
4676 done, just a write of zero. To truncate a file,
4677 use SMBwrite. */
4679 if(numtowrite == 0) {
4680 nwritten = 0;
4681 } else {
4682 if (req->unread_bytes == 0) {
4683 status = schedule_aio_write_and_X(conn,
4684 req,
4685 fsp,
4686 data,
4687 startpos,
4688 numtowrite);
4690 if (NT_STATUS_IS_OK(status)) {
4691 /* write scheduled - we're done. */
4692 goto out;
4694 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4695 /* Real error - report to client. */
4696 reply_nterror(req, status);
4697 goto out;
4699 /* NT_STATUS_RETRY - fall through to sync write. */
4702 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4703 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4704 &lock);
4706 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4707 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4708 goto out;
4711 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4712 saved_errno = errno;
4714 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4717 if(nwritten < 0) {
4718 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4719 goto out;
4722 if((nwritten == 0) && (numtowrite != 0)) {
4723 reply_nterror(req, NT_STATUS_DISK_FULL);
4724 goto out;
4727 reply_outbuf(req, 6, 0);
4728 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
4729 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
4730 SSVAL(req->outbuf,smb_vwv2,nwritten);
4731 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4733 DEBUG(3,("writeX %s num=%d wrote=%d\n",
4734 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4736 status = sync_file(conn, fsp, write_through);
4737 if (!NT_STATUS_IS_OK(status)) {
4738 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4739 fsp_str_dbg(fsp), nt_errstr(status)));
4740 reply_nterror(req, status);
4741 goto out;
4744 END_PROFILE(SMBwriteX);
4745 return;
4747 out:
4748 if (req->unread_bytes) {
4749 /* writeX failed. drain socket. */
4750 if (drain_socket(req->sconn->sock, req->unread_bytes) !=
4751 req->unread_bytes) {
4752 smb_panic("failed to drain pending bytes");
4754 req->unread_bytes = 0;
4757 END_PROFILE(SMBwriteX);
4758 return;
4761 /****************************************************************************
4762 Reply to a lseek.
4763 ****************************************************************************/
4765 void reply_lseek(struct smb_request *req)
4767 connection_struct *conn = req->conn;
4768 off_t startpos;
4769 off_t res= -1;
4770 int mode,umode;
4771 files_struct *fsp;
4773 START_PROFILE(SMBlseek);
4775 if (req->wct < 4) {
4776 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4777 END_PROFILE(SMBlseek);
4778 return;
4781 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4783 if (!check_fsp(conn, req, fsp)) {
4784 return;
4787 flush_write_cache(fsp, SEEK_FLUSH);
4789 mode = SVAL(req->vwv+1, 0) & 3;
4790 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4791 startpos = (off_t)IVALS(req->vwv+2, 0);
4793 switch (mode) {
4794 case 0:
4795 umode = SEEK_SET;
4796 res = startpos;
4797 break;
4798 case 1:
4799 umode = SEEK_CUR;
4800 res = fsp->fh->pos + startpos;
4801 break;
4802 case 2:
4803 umode = SEEK_END;
4804 break;
4805 default:
4806 umode = SEEK_SET;
4807 res = startpos;
4808 break;
4811 if (umode == SEEK_END) {
4812 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
4813 if(errno == EINVAL) {
4814 off_t current_pos = startpos;
4816 if(fsp_stat(fsp) == -1) {
4817 reply_nterror(req,
4818 map_nt_error_from_unix(errno));
4819 END_PROFILE(SMBlseek);
4820 return;
4823 current_pos += fsp->fsp_name->st.st_ex_size;
4824 if(current_pos < 0)
4825 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
4829 if(res == -1) {
4830 reply_nterror(req, map_nt_error_from_unix(errno));
4831 END_PROFILE(SMBlseek);
4832 return;
4836 fsp->fh->pos = res;
4838 reply_outbuf(req, 2, 0);
4839 SIVAL(req->outbuf,smb_vwv0,res);
4841 DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n",
4842 fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode));
4844 END_PROFILE(SMBlseek);
4845 return;
4848 /****************************************************************************
4849 Reply to a flush.
4850 ****************************************************************************/
4852 void reply_flush(struct smb_request *req)
4854 connection_struct *conn = req->conn;
4855 uint16 fnum;
4856 files_struct *fsp;
4858 START_PROFILE(SMBflush);
4860 if (req->wct < 1) {
4861 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4862 return;
4865 fnum = SVAL(req->vwv+0, 0);
4866 fsp = file_fsp(req, fnum);
4868 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
4869 return;
4872 if (!fsp) {
4873 file_sync_all(conn);
4874 } else {
4875 NTSTATUS status = sync_file(conn, fsp, True);
4876 if (!NT_STATUS_IS_OK(status)) {
4877 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
4878 fsp_str_dbg(fsp), nt_errstr(status)));
4879 reply_nterror(req, status);
4880 END_PROFILE(SMBflush);
4881 return;
4885 reply_outbuf(req, 0, 0);
4887 DEBUG(3,("flush\n"));
4888 END_PROFILE(SMBflush);
4889 return;
4892 /****************************************************************************
4893 Reply to a exit.
4894 conn POINTER CAN BE NULL HERE !
4895 ****************************************************************************/
4897 void reply_exit(struct smb_request *req)
4899 START_PROFILE(SMBexit);
4901 file_close_pid(req->sconn, req->smbpid, req->vuid);
4903 reply_outbuf(req, 0, 0);
4905 DEBUG(3,("exit\n"));
4907 END_PROFILE(SMBexit);
4908 return;
4911 struct reply_close_state {
4912 files_struct *fsp;
4913 struct smb_request *smbreq;
4916 static void do_smb1_close(struct tevent_req *req);
4918 void reply_close(struct smb_request *req)
4920 connection_struct *conn = req->conn;
4921 NTSTATUS status = NT_STATUS_OK;
4922 files_struct *fsp = NULL;
4923 START_PROFILE(SMBclose);
4925 if (req->wct < 3) {
4926 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4927 END_PROFILE(SMBclose);
4928 return;
4931 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4934 * We can only use check_fsp if we know it's not a directory.
4937 if (!check_fsp_open(conn, req, fsp)) {
4938 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
4939 END_PROFILE(SMBclose);
4940 return;
4943 DEBUG(3, ("Close %s fd=%d %s (numopen=%d)\n",
4944 fsp->is_directory ? "directory" : "file",
4945 fsp->fh->fd, fsp_fnum_dbg(fsp),
4946 conn->num_files_open));
4948 if (!fsp->is_directory) {
4949 time_t t;
4952 * Take care of any time sent in the close.
4955 t = srv_make_unix_date3(req->vwv+1);
4956 set_close_write_time(fsp, convert_time_t_to_timespec(t));
4959 if (fsp->num_aio_requests != 0) {
4961 struct reply_close_state *state;
4963 DEBUG(10, ("closing with aio %u requests pending\n",
4964 fsp->num_aio_requests));
4967 * We depend on the aio_extra destructor to take care of this
4968 * close request once fsp->num_aio_request drops to 0.
4971 fsp->deferred_close = tevent_wait_send(
4972 fsp, fsp->conn->sconn->ev_ctx);
4973 if (fsp->deferred_close == NULL) {
4974 status = NT_STATUS_NO_MEMORY;
4975 goto done;
4978 state = talloc(fsp, struct reply_close_state);
4979 if (state == NULL) {
4980 TALLOC_FREE(fsp->deferred_close);
4981 status = NT_STATUS_NO_MEMORY;
4982 goto done;
4984 state->fsp = fsp;
4985 state->smbreq = talloc_move(fsp, &req);
4986 tevent_req_set_callback(fsp->deferred_close, do_smb1_close,
4987 state);
4988 END_PROFILE(SMBclose);
4989 return;
4993 * close_file() returns the unix errno if an error was detected on
4994 * close - normally this is due to a disk full error. If not then it
4995 * was probably an I/O error.
4998 status = close_file(req, fsp, NORMAL_CLOSE);
4999 done:
5000 if (!NT_STATUS_IS_OK(status)) {
5001 reply_nterror(req, status);
5002 END_PROFILE(SMBclose);
5003 return;
5006 reply_outbuf(req, 0, 0);
5007 END_PROFILE(SMBclose);
5008 return;
5011 static void do_smb1_close(struct tevent_req *req)
5013 struct reply_close_state *state = tevent_req_callback_data(
5014 req, struct reply_close_state);
5015 struct smb_request *smbreq;
5016 NTSTATUS status;
5017 int ret;
5019 ret = tevent_wait_recv(req);
5020 TALLOC_FREE(req);
5021 if (ret != 0) {
5022 DEBUG(10, ("tevent_wait_recv returned %s\n",
5023 strerror(ret)));
5025 * Continue anyway, this should never happen
5030 * fsp->smb2_close_request right now is a talloc grandchild of
5031 * fsp. When we close_file(fsp), it would go with it. No chance to
5032 * reply...
5034 smbreq = talloc_move(talloc_tos(), &state->smbreq);
5036 status = close_file(smbreq, state->fsp, NORMAL_CLOSE);
5037 if (NT_STATUS_IS_OK(status)) {
5038 reply_outbuf(smbreq, 0, 0);
5039 } else {
5040 reply_nterror(smbreq, status);
5042 if (!srv_send_smb(smbreq->sconn,
5043 (char *)smbreq->outbuf,
5044 true,
5045 smbreq->seqnum+1,
5046 IS_CONN_ENCRYPTED(smbreq->conn)||smbreq->encrypted,
5047 NULL)) {
5048 exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
5049 "failed.");
5051 TALLOC_FREE(smbreq);
5054 /****************************************************************************
5055 Reply to a writeclose (Core+ protocol).
5056 ****************************************************************************/
5058 void reply_writeclose(struct smb_request *req)
5060 connection_struct *conn = req->conn;
5061 size_t numtowrite;
5062 ssize_t nwritten = -1;
5063 NTSTATUS close_status = NT_STATUS_OK;
5064 off_t startpos;
5065 const char *data;
5066 struct timespec mtime;
5067 files_struct *fsp;
5068 struct lock_struct lock;
5070 START_PROFILE(SMBwriteclose);
5072 if (req->wct < 6) {
5073 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5074 END_PROFILE(SMBwriteclose);
5075 return;
5078 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5080 if (!check_fsp(conn, req, fsp)) {
5081 END_PROFILE(SMBwriteclose);
5082 return;
5084 if (!CHECK_WRITE(fsp)) {
5085 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5086 END_PROFILE(SMBwriteclose);
5087 return;
5090 numtowrite = SVAL(req->vwv+1, 0);
5091 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5092 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
5093 data = (const char *)req->buf + 1;
5095 if (!fsp->print_file) {
5096 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5097 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5098 &lock);
5100 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
5101 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5102 END_PROFILE(SMBwriteclose);
5103 return;
5107 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5109 set_close_write_time(fsp, mtime);
5112 * More insanity. W2K only closes the file if writelen > 0.
5113 * JRA.
5116 if (numtowrite) {
5117 DEBUG(3,("reply_writeclose: zero length write doesn't close "
5118 "file %s\n", fsp_str_dbg(fsp)));
5119 close_status = close_file(req, fsp, NORMAL_CLOSE);
5122 DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
5123 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
5124 conn->num_files_open));
5126 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
5127 reply_nterror(req, NT_STATUS_DISK_FULL);
5128 goto strict_unlock;
5131 if(!NT_STATUS_IS_OK(close_status)) {
5132 reply_nterror(req, close_status);
5133 goto strict_unlock;
5136 reply_outbuf(req, 1, 0);
5138 SSVAL(req->outbuf,smb_vwv0,nwritten);
5140 strict_unlock:
5141 if (numtowrite && !fsp->print_file) {
5142 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
5145 END_PROFILE(SMBwriteclose);
5146 return;
5149 #undef DBGC_CLASS
5150 #define DBGC_CLASS DBGC_LOCKING
5152 /****************************************************************************
5153 Reply to a lock.
5154 ****************************************************************************/
5156 void reply_lock(struct smb_request *req)
5158 connection_struct *conn = req->conn;
5159 uint64_t count,offset;
5160 NTSTATUS status;
5161 files_struct *fsp;
5162 struct byte_range_lock *br_lck = NULL;
5164 START_PROFILE(SMBlock);
5166 if (req->wct < 5) {
5167 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5168 END_PROFILE(SMBlock);
5169 return;
5172 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5174 if (!check_fsp(conn, req, fsp)) {
5175 END_PROFILE(SMBlock);
5176 return;
5179 count = (uint64_t)IVAL(req->vwv+1, 0);
5180 offset = (uint64_t)IVAL(req->vwv+3, 0);
5182 DEBUG(3,("lock fd=%d %s offset=%.0f count=%.0f\n",
5183 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count));
5185 br_lck = do_lock(req->sconn->msg_ctx,
5186 fsp,
5187 (uint64_t)req->smbpid,
5188 count,
5189 offset,
5190 WRITE_LOCK,
5191 WINDOWS_LOCK,
5192 False, /* Non-blocking lock. */
5193 &status,
5194 NULL,
5195 NULL);
5197 TALLOC_FREE(br_lck);
5199 if (NT_STATUS_V(status)) {
5200 reply_nterror(req, status);
5201 END_PROFILE(SMBlock);
5202 return;
5205 reply_outbuf(req, 0, 0);
5207 END_PROFILE(SMBlock);
5208 return;
5211 /****************************************************************************
5212 Reply to a unlock.
5213 ****************************************************************************/
5215 void reply_unlock(struct smb_request *req)
5217 connection_struct *conn = req->conn;
5218 uint64_t count,offset;
5219 NTSTATUS status;
5220 files_struct *fsp;
5222 START_PROFILE(SMBunlock);
5224 if (req->wct < 5) {
5225 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5226 END_PROFILE(SMBunlock);
5227 return;
5230 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5232 if (!check_fsp(conn, req, fsp)) {
5233 END_PROFILE(SMBunlock);
5234 return;
5237 count = (uint64_t)IVAL(req->vwv+1, 0);
5238 offset = (uint64_t)IVAL(req->vwv+3, 0);
5240 status = do_unlock(req->sconn->msg_ctx,
5241 fsp,
5242 (uint64_t)req->smbpid,
5243 count,
5244 offset,
5245 WINDOWS_LOCK);
5247 if (NT_STATUS_V(status)) {
5248 reply_nterror(req, status);
5249 END_PROFILE(SMBunlock);
5250 return;
5253 DEBUG( 3, ( "unlock fd=%d %s offset=%.0f count=%.0f\n",
5254 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count ) );
5256 reply_outbuf(req, 0, 0);
5258 END_PROFILE(SMBunlock);
5259 return;
5262 #undef DBGC_CLASS
5263 #define DBGC_CLASS DBGC_ALL
5265 /****************************************************************************
5266 Reply to a tdis.
5267 conn POINTER CAN BE NULL HERE !
5268 ****************************************************************************/
5270 void reply_tdis(struct smb_request *req)
5272 NTSTATUS status;
5273 connection_struct *conn = req->conn;
5274 struct smbXsrv_tcon *tcon;
5276 START_PROFILE(SMBtdis);
5278 if (!conn) {
5279 DEBUG(4,("Invalid connection in tdis\n"));
5280 reply_force_doserror(req, ERRSRV, ERRinvnid);
5281 END_PROFILE(SMBtdis);
5282 return;
5285 tcon = conn->tcon;
5286 req->conn = NULL;
5289 * TODO: cancel all outstanding requests on the tcon
5291 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
5292 if (!NT_STATUS_IS_OK(status)) {
5293 DEBUG(0, ("reply_tdis: "
5294 "smbXsrv_tcon_disconnect() failed: %s\n",
5295 nt_errstr(status)));
5297 * If we hit this case, there is something completely
5298 * wrong, so we better disconnect the transport connection.
5300 END_PROFILE(SMBtdis);
5301 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
5302 return;
5305 TALLOC_FREE(tcon);
5307 reply_outbuf(req, 0, 0);
5308 END_PROFILE(SMBtdis);
5309 return;
5312 /****************************************************************************
5313 Reply to a echo.
5314 conn POINTER CAN BE NULL HERE !
5315 ****************************************************************************/
5317 void reply_echo(struct smb_request *req)
5319 connection_struct *conn = req->conn;
5320 struct smb_perfcount_data local_pcd;
5321 struct smb_perfcount_data *cur_pcd;
5322 int smb_reverb;
5323 int seq_num;
5325 START_PROFILE(SMBecho);
5327 smb_init_perfcount_data(&local_pcd);
5329 if (req->wct < 1) {
5330 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5331 END_PROFILE(SMBecho);
5332 return;
5335 smb_reverb = SVAL(req->vwv+0, 0);
5337 reply_outbuf(req, 1, req->buflen);
5339 /* copy any incoming data back out */
5340 if (req->buflen > 0) {
5341 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5344 if (smb_reverb > 100) {
5345 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5346 smb_reverb = 100;
5349 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5351 /* this makes sure we catch the request pcd */
5352 if (seq_num == smb_reverb) {
5353 cur_pcd = &req->pcd;
5354 } else {
5355 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5356 cur_pcd = &local_pcd;
5359 SSVAL(req->outbuf,smb_vwv0,seq_num);
5361 show_msg((char *)req->outbuf);
5362 if (!srv_send_smb(req->sconn,
5363 (char *)req->outbuf,
5364 true, req->seqnum+1,
5365 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5366 cur_pcd))
5367 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5370 DEBUG(3,("echo %d times\n", smb_reverb));
5372 TALLOC_FREE(req->outbuf);
5374 END_PROFILE(SMBecho);
5375 return;
5378 /****************************************************************************
5379 Reply to a printopen.
5380 ****************************************************************************/
5382 void reply_printopen(struct smb_request *req)
5384 connection_struct *conn = req->conn;
5385 files_struct *fsp;
5386 NTSTATUS status;
5388 START_PROFILE(SMBsplopen);
5390 if (req->wct < 2) {
5391 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5392 END_PROFILE(SMBsplopen);
5393 return;
5396 if (!CAN_PRINT(conn)) {
5397 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5398 END_PROFILE(SMBsplopen);
5399 return;
5402 status = file_new(req, conn, &fsp);
5403 if(!NT_STATUS_IS_OK(status)) {
5404 reply_nterror(req, status);
5405 END_PROFILE(SMBsplopen);
5406 return;
5409 /* Open for exclusive use, write only. */
5410 status = print_spool_open(fsp, NULL, req->vuid);
5412 if (!NT_STATUS_IS_OK(status)) {
5413 file_free(req, fsp);
5414 reply_nterror(req, status);
5415 END_PROFILE(SMBsplopen);
5416 return;
5419 reply_outbuf(req, 1, 0);
5420 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5422 DEBUG(3,("openprint fd=%d %s\n",
5423 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5425 END_PROFILE(SMBsplopen);
5426 return;
5429 /****************************************************************************
5430 Reply to a printclose.
5431 ****************************************************************************/
5433 void reply_printclose(struct smb_request *req)
5435 connection_struct *conn = req->conn;
5436 files_struct *fsp;
5437 NTSTATUS status;
5439 START_PROFILE(SMBsplclose);
5441 if (req->wct < 1) {
5442 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5443 END_PROFILE(SMBsplclose);
5444 return;
5447 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5449 if (!check_fsp(conn, req, fsp)) {
5450 END_PROFILE(SMBsplclose);
5451 return;
5454 if (!CAN_PRINT(conn)) {
5455 reply_force_doserror(req, ERRSRV, ERRerror);
5456 END_PROFILE(SMBsplclose);
5457 return;
5460 DEBUG(3,("printclose fd=%d %s\n",
5461 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5463 status = close_file(req, fsp, NORMAL_CLOSE);
5465 if(!NT_STATUS_IS_OK(status)) {
5466 reply_nterror(req, status);
5467 END_PROFILE(SMBsplclose);
5468 return;
5471 reply_outbuf(req, 0, 0);
5473 END_PROFILE(SMBsplclose);
5474 return;
5477 /****************************************************************************
5478 Reply to a printqueue.
5479 ****************************************************************************/
5481 void reply_printqueue(struct smb_request *req)
5483 connection_struct *conn = req->conn;
5484 int max_count;
5485 int start_index;
5487 START_PROFILE(SMBsplretq);
5489 if (req->wct < 2) {
5490 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5491 END_PROFILE(SMBsplretq);
5492 return;
5495 max_count = SVAL(req->vwv+0, 0);
5496 start_index = SVAL(req->vwv+1, 0);
5498 /* we used to allow the client to get the cnum wrong, but that
5499 is really quite gross and only worked when there was only
5500 one printer - I think we should now only accept it if they
5501 get it right (tridge) */
5502 if (!CAN_PRINT(conn)) {
5503 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5504 END_PROFILE(SMBsplretq);
5505 return;
5508 reply_outbuf(req, 2, 3);
5509 SSVAL(req->outbuf,smb_vwv0,0);
5510 SSVAL(req->outbuf,smb_vwv1,0);
5511 SCVAL(smb_buf(req->outbuf),0,1);
5512 SSVAL(smb_buf(req->outbuf),1,0);
5514 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5515 start_index, max_count));
5518 TALLOC_CTX *mem_ctx = talloc_tos();
5519 NTSTATUS status;
5520 WERROR werr;
5521 const char *sharename = lp_servicename(mem_ctx, SNUM(conn));
5522 struct rpc_pipe_client *cli = NULL;
5523 struct dcerpc_binding_handle *b = NULL;
5524 struct policy_handle handle;
5525 struct spoolss_DevmodeContainer devmode_ctr;
5526 union spoolss_JobInfo *info;
5527 uint32_t count;
5528 uint32_t num_to_get;
5529 uint32_t first;
5530 uint32_t i;
5532 ZERO_STRUCT(handle);
5534 status = rpc_pipe_open_interface(conn,
5535 &ndr_table_spoolss.syntax_id,
5536 conn->session_info,
5537 conn->sconn->remote_address,
5538 conn->sconn->msg_ctx,
5539 &cli);
5540 if (!NT_STATUS_IS_OK(status)) {
5541 DEBUG(0, ("reply_printqueue: "
5542 "could not connect to spoolss: %s\n",
5543 nt_errstr(status)));
5544 reply_nterror(req, status);
5545 goto out;
5547 b = cli->binding_handle;
5549 ZERO_STRUCT(devmode_ctr);
5551 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5552 sharename,
5553 NULL, devmode_ctr,
5554 SEC_FLAG_MAXIMUM_ALLOWED,
5555 &handle,
5556 &werr);
5557 if (!NT_STATUS_IS_OK(status)) {
5558 reply_nterror(req, status);
5559 goto out;
5561 if (!W_ERROR_IS_OK(werr)) {
5562 reply_nterror(req, werror_to_ntstatus(werr));
5563 goto out;
5566 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5567 &handle,
5568 0, /* firstjob */
5569 0xff, /* numjobs */
5570 2, /* level */
5571 0, /* offered */
5572 &count,
5573 &info);
5574 if (!W_ERROR_IS_OK(werr)) {
5575 reply_nterror(req, werror_to_ntstatus(werr));
5576 goto out;
5579 if (max_count > 0) {
5580 first = start_index;
5581 } else {
5582 first = start_index + max_count + 1;
5585 if (first >= count) {
5586 num_to_get = first;
5587 } else {
5588 num_to_get = first + MIN(ABS(max_count), count - first);
5591 for (i = first; i < num_to_get; i++) {
5592 char blob[28];
5593 char *p = blob;
5594 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
5595 int qstatus;
5596 uint16_t qrapjobid = pjobid_to_rap(sharename,
5597 info[i].info2.job_id);
5599 if (info[i].info2.status == JOB_STATUS_PRINTING) {
5600 qstatus = 2;
5601 } else {
5602 qstatus = 3;
5605 srv_put_dos_date2(p, 0, qtime);
5606 SCVAL(p, 4, qstatus);
5607 SSVAL(p, 5, qrapjobid);
5608 SIVAL(p, 7, info[i].info2.size);
5609 SCVAL(p, 11, 0);
5610 srvstr_push(blob, req->flags2, p+12,
5611 info[i].info2.notify_name, 16, STR_ASCII);
5613 if (message_push_blob(
5614 &req->outbuf,
5615 data_blob_const(
5616 blob, sizeof(blob))) == -1) {
5617 reply_nterror(req, NT_STATUS_NO_MEMORY);
5618 goto out;
5622 if (count > 0) {
5623 SSVAL(req->outbuf,smb_vwv0,count);
5624 SSVAL(req->outbuf,smb_vwv1,
5625 (max_count>0?first+count:first-1));
5626 SCVAL(smb_buf(req->outbuf),0,1);
5627 SSVAL(smb_buf(req->outbuf),1,28*count);
5631 DEBUG(3, ("%u entries returned in queue\n",
5632 (unsigned)count));
5634 out:
5635 if (b && is_valid_policy_hnd(&handle)) {
5636 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5641 END_PROFILE(SMBsplretq);
5642 return;
5645 /****************************************************************************
5646 Reply to a printwrite.
5647 ****************************************************************************/
5649 void reply_printwrite(struct smb_request *req)
5651 connection_struct *conn = req->conn;
5652 int numtowrite;
5653 const char *data;
5654 files_struct *fsp;
5656 START_PROFILE(SMBsplwr);
5658 if (req->wct < 1) {
5659 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5660 END_PROFILE(SMBsplwr);
5661 return;
5664 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5666 if (!check_fsp(conn, req, fsp)) {
5667 END_PROFILE(SMBsplwr);
5668 return;
5671 if (!fsp->print_file) {
5672 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5673 END_PROFILE(SMBsplwr);
5674 return;
5677 if (!CHECK_WRITE(fsp)) {
5678 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5679 END_PROFILE(SMBsplwr);
5680 return;
5683 numtowrite = SVAL(req->buf, 1);
5685 if (req->buflen < numtowrite + 3) {
5686 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5687 END_PROFILE(SMBsplwr);
5688 return;
5691 data = (const char *)req->buf + 3;
5693 if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
5694 reply_nterror(req, map_nt_error_from_unix(errno));
5695 END_PROFILE(SMBsplwr);
5696 return;
5699 DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
5701 END_PROFILE(SMBsplwr);
5702 return;
5705 /****************************************************************************
5706 Reply to a mkdir.
5707 ****************************************************************************/
5709 void reply_mkdir(struct smb_request *req)
5711 connection_struct *conn = req->conn;
5712 struct smb_filename *smb_dname = NULL;
5713 char *directory = NULL;
5714 NTSTATUS status;
5715 TALLOC_CTX *ctx = talloc_tos();
5717 START_PROFILE(SMBmkdir);
5719 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5720 STR_TERMINATE, &status);
5721 if (!NT_STATUS_IS_OK(status)) {
5722 reply_nterror(req, status);
5723 goto out;
5726 status = filename_convert(ctx, conn,
5727 req->flags2 & FLAGS2_DFS_PATHNAMES,
5728 directory,
5730 NULL,
5731 &smb_dname);
5732 if (!NT_STATUS_IS_OK(status)) {
5733 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5734 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5735 ERRSRV, ERRbadpath);
5736 goto out;
5738 reply_nterror(req, status);
5739 goto out;
5742 status = create_directory(conn, req, smb_dname);
5744 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
5746 if (!NT_STATUS_IS_OK(status)) {
5748 if (!use_nt_status()
5749 && NT_STATUS_EQUAL(status,
5750 NT_STATUS_OBJECT_NAME_COLLISION)) {
5752 * Yes, in the DOS error code case we get a
5753 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
5754 * samba4 torture test.
5756 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
5759 reply_nterror(req, status);
5760 goto out;
5763 reply_outbuf(req, 0, 0);
5765 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
5766 out:
5767 TALLOC_FREE(smb_dname);
5768 END_PROFILE(SMBmkdir);
5769 return;
5772 /****************************************************************************
5773 Reply to a rmdir.
5774 ****************************************************************************/
5776 void reply_rmdir(struct smb_request *req)
5778 connection_struct *conn = req->conn;
5779 struct smb_filename *smb_dname = NULL;
5780 char *directory = NULL;
5781 NTSTATUS status;
5782 TALLOC_CTX *ctx = talloc_tos();
5783 files_struct *fsp = NULL;
5784 int info = 0;
5785 struct smbd_server_connection *sconn = req->sconn;
5787 START_PROFILE(SMBrmdir);
5789 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5790 STR_TERMINATE, &status);
5791 if (!NT_STATUS_IS_OK(status)) {
5792 reply_nterror(req, status);
5793 goto out;
5796 status = filename_convert(ctx, conn,
5797 req->flags2 & FLAGS2_DFS_PATHNAMES,
5798 directory,
5800 NULL,
5801 &smb_dname);
5802 if (!NT_STATUS_IS_OK(status)) {
5803 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5804 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5805 ERRSRV, ERRbadpath);
5806 goto out;
5808 reply_nterror(req, status);
5809 goto out;
5812 if (is_ntfs_stream_smb_fname(smb_dname)) {
5813 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
5814 goto out;
5817 status = SMB_VFS_CREATE_FILE(
5818 conn, /* conn */
5819 req, /* req */
5820 0, /* root_dir_fid */
5821 smb_dname, /* fname */
5822 DELETE_ACCESS, /* access_mask */
5823 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5824 FILE_SHARE_DELETE),
5825 FILE_OPEN, /* create_disposition*/
5826 FILE_DIRECTORY_FILE, /* create_options */
5827 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
5828 0, /* oplock_request */
5829 0, /* allocation_size */
5830 0, /* private_flags */
5831 NULL, /* sd */
5832 NULL, /* ea_list */
5833 &fsp, /* result */
5834 &info); /* pinfo */
5836 if (!NT_STATUS_IS_OK(status)) {
5837 if (open_was_deferred(req->sconn, req->mid)) {
5838 /* We have re-scheduled this call. */
5839 goto out;
5841 reply_nterror(req, status);
5842 goto out;
5845 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
5846 if (!NT_STATUS_IS_OK(status)) {
5847 close_file(req, fsp, ERROR_CLOSE);
5848 reply_nterror(req, status);
5849 goto out;
5852 if (!set_delete_on_close(fsp, true,
5853 conn->session_info->security_token,
5854 conn->session_info->unix_token)) {
5855 close_file(req, fsp, ERROR_CLOSE);
5856 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5857 goto out;
5860 status = close_file(req, fsp, NORMAL_CLOSE);
5861 if (!NT_STATUS_IS_OK(status)) {
5862 reply_nterror(req, status);
5863 } else {
5864 reply_outbuf(req, 0, 0);
5867 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
5869 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
5870 out:
5871 TALLOC_FREE(smb_dname);
5872 END_PROFILE(SMBrmdir);
5873 return;
5876 /*******************************************************************
5877 Resolve wildcards in a filename rename.
5878 ********************************************************************/
5880 static bool resolve_wildcards(TALLOC_CTX *ctx,
5881 const char *name1,
5882 const char *name2,
5883 char **pp_newname)
5885 char *name2_copy = NULL;
5886 char *root1 = NULL;
5887 char *root2 = NULL;
5888 char *ext1 = NULL;
5889 char *ext2 = NULL;
5890 char *p,*p2, *pname1, *pname2;
5892 name2_copy = talloc_strdup(ctx, name2);
5893 if (!name2_copy) {
5894 return False;
5897 pname1 = strrchr_m(name1,'/');
5898 pname2 = strrchr_m(name2_copy,'/');
5900 if (!pname1 || !pname2) {
5901 return False;
5904 /* Truncate the copy of name2 at the last '/' */
5905 *pname2 = '\0';
5907 /* Now go past the '/' */
5908 pname1++;
5909 pname2++;
5911 root1 = talloc_strdup(ctx, pname1);
5912 root2 = talloc_strdup(ctx, pname2);
5914 if (!root1 || !root2) {
5915 return False;
5918 p = strrchr_m(root1,'.');
5919 if (p) {
5920 *p = 0;
5921 ext1 = talloc_strdup(ctx, p+1);
5922 } else {
5923 ext1 = talloc_strdup(ctx, "");
5925 p = strrchr_m(root2,'.');
5926 if (p) {
5927 *p = 0;
5928 ext2 = talloc_strdup(ctx, p+1);
5929 } else {
5930 ext2 = talloc_strdup(ctx, "");
5933 if (!ext1 || !ext2) {
5934 return False;
5937 p = root1;
5938 p2 = root2;
5939 while (*p2) {
5940 if (*p2 == '?') {
5941 /* Hmmm. Should this be mb-aware ? */
5942 *p2 = *p;
5943 p2++;
5944 } else if (*p2 == '*') {
5945 *p2 = '\0';
5946 root2 = talloc_asprintf(ctx, "%s%s",
5947 root2,
5949 if (!root2) {
5950 return False;
5952 break;
5953 } else {
5954 p2++;
5956 if (*p) {
5957 p++;
5961 p = ext1;
5962 p2 = ext2;
5963 while (*p2) {
5964 if (*p2 == '?') {
5965 /* Hmmm. Should this be mb-aware ? */
5966 *p2 = *p;
5967 p2++;
5968 } else if (*p2 == '*') {
5969 *p2 = '\0';
5970 ext2 = talloc_asprintf(ctx, "%s%s",
5971 ext2,
5973 if (!ext2) {
5974 return False;
5976 break;
5977 } else {
5978 p2++;
5980 if (*p) {
5981 p++;
5985 if (*ext2) {
5986 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
5987 name2_copy,
5988 root2,
5989 ext2);
5990 } else {
5991 *pp_newname = talloc_asprintf(ctx, "%s/%s",
5992 name2_copy,
5993 root2);
5996 if (!*pp_newname) {
5997 return False;
6000 return True;
6003 /****************************************************************************
6004 Ensure open files have their names updated. Updated to notify other smbd's
6005 asynchronously.
6006 ****************************************************************************/
6008 static void rename_open_files(connection_struct *conn,
6009 struct share_mode_lock *lck,
6010 uint32_t orig_name_hash,
6011 const struct smb_filename *smb_fname_dst)
6013 files_struct *fsp;
6014 bool did_rename = False;
6015 NTSTATUS status;
6016 uint32_t new_name_hash = 0;
6018 for(fsp = file_find_di_first(conn->sconn, lck->data->id); fsp;
6019 fsp = file_find_di_next(fsp)) {
6020 /* fsp_name is a relative path under the fsp. To change this for other
6021 sharepaths we need to manipulate relative paths. */
6022 /* TODO - create the absolute path and manipulate the newname
6023 relative to the sharepath. */
6024 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
6025 continue;
6027 if (fsp->name_hash != orig_name_hash) {
6028 continue;
6030 DEBUG(10, ("rename_open_files: renaming file %s "
6031 "(file_id %s) from %s -> %s\n", fsp_fnum_dbg(fsp),
6032 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
6033 smb_fname_str_dbg(smb_fname_dst)));
6035 status = fsp_set_smb_fname(fsp, smb_fname_dst);
6036 if (NT_STATUS_IS_OK(status)) {
6037 did_rename = True;
6038 new_name_hash = fsp->name_hash;
6042 if (!did_rename) {
6043 DEBUG(10, ("rename_open_files: no open files on file_id %s "
6044 "for %s\n", file_id_string_tos(&lck->data->id),
6045 smb_fname_str_dbg(smb_fname_dst)));
6048 /* Send messages to all smbd's (not ourself) that the name has changed. */
6049 rename_share_filename(conn->sconn->msg_ctx, lck, conn->connectpath,
6050 orig_name_hash, new_name_hash,
6051 smb_fname_dst);
6055 /****************************************************************************
6056 We need to check if the source path is a parent directory of the destination
6057 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
6058 refuse the rename with a sharing violation. Under UNIX the above call can
6059 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
6060 probably need to check that the client is a Windows one before disallowing
6061 this as a UNIX client (one with UNIX extensions) can know the source is a
6062 symlink and make this decision intelligently. Found by an excellent bug
6063 report from <AndyLiebman@aol.com>.
6064 ****************************************************************************/
6066 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
6067 const struct smb_filename *smb_fname_dst)
6069 const char *psrc = smb_fname_src->base_name;
6070 const char *pdst = smb_fname_dst->base_name;
6071 size_t slen;
6073 if (psrc[0] == '.' && psrc[1] == '/') {
6074 psrc += 2;
6076 if (pdst[0] == '.' && pdst[1] == '/') {
6077 pdst += 2;
6079 if ((slen = strlen(psrc)) > strlen(pdst)) {
6080 return False;
6082 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
6086 * Do the notify calls from a rename
6089 static void notify_rename(connection_struct *conn, bool is_dir,
6090 const struct smb_filename *smb_fname_src,
6091 const struct smb_filename *smb_fname_dst)
6093 char *parent_dir_src = NULL;
6094 char *parent_dir_dst = NULL;
6095 uint32 mask;
6097 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
6098 : FILE_NOTIFY_CHANGE_FILE_NAME;
6100 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
6101 &parent_dir_src, NULL) ||
6102 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
6103 &parent_dir_dst, NULL)) {
6104 goto out;
6107 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
6108 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
6109 smb_fname_src->base_name);
6110 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
6111 smb_fname_dst->base_name);
6113 else {
6114 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
6115 smb_fname_src->base_name);
6116 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
6117 smb_fname_dst->base_name);
6120 /* this is a strange one. w2k3 gives an additional event for
6121 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
6122 files, but not directories */
6123 if (!is_dir) {
6124 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6125 FILE_NOTIFY_CHANGE_ATTRIBUTES
6126 |FILE_NOTIFY_CHANGE_CREATION,
6127 smb_fname_dst->base_name);
6129 out:
6130 TALLOC_FREE(parent_dir_src);
6131 TALLOC_FREE(parent_dir_dst);
6134 /****************************************************************************
6135 Returns an error if the parent directory for a filename is open in an
6136 incompatible way.
6137 ****************************************************************************/
6139 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
6140 const struct smb_filename *smb_fname_dst_in)
6142 char *parent_dir = NULL;
6143 struct smb_filename smb_fname_parent;
6144 struct file_id id;
6145 files_struct *fsp = NULL;
6146 int ret;
6148 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
6149 &parent_dir, NULL)) {
6150 return NT_STATUS_NO_MEMORY;
6152 ZERO_STRUCT(smb_fname_parent);
6153 smb_fname_parent.base_name = parent_dir;
6155 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
6156 if (ret == -1) {
6157 return map_nt_error_from_unix(errno);
6161 * We're only checking on this smbd here, mostly good
6162 * enough.. and will pass tests.
6165 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
6166 for (fsp = file_find_di_first(conn->sconn, id); fsp;
6167 fsp = file_find_di_next(fsp)) {
6168 if (fsp->access_mask & DELETE_ACCESS) {
6169 return NT_STATUS_SHARING_VIOLATION;
6172 return NT_STATUS_OK;
6175 /****************************************************************************
6176 Rename an open file - given an fsp.
6177 ****************************************************************************/
6179 NTSTATUS rename_internals_fsp(connection_struct *conn,
6180 files_struct *fsp,
6181 const struct smb_filename *smb_fname_dst_in,
6182 uint32 attrs,
6183 bool replace_if_exists)
6185 TALLOC_CTX *ctx = talloc_tos();
6186 struct smb_filename *smb_fname_dst = NULL;
6187 NTSTATUS status = NT_STATUS_OK;
6188 struct share_mode_lock *lck = NULL;
6189 bool dst_exists, old_is_stream, new_is_stream;
6191 status = check_name(conn, smb_fname_dst_in->base_name);
6192 if (!NT_STATUS_IS_OK(status)) {
6193 return status;
6196 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
6197 if (!NT_STATUS_IS_OK(status)) {
6198 return status;
6201 /* Make a copy of the dst smb_fname structs */
6203 status = copy_smb_filename(ctx, smb_fname_dst_in, &smb_fname_dst);
6204 if (!NT_STATUS_IS_OK(status)) {
6205 goto out;
6209 * Check for special case with case preserving and not
6210 * case sensitive. If the old last component differs from the original
6211 * last component only by case, then we should allow
6212 * the rename (user is trying to change the case of the
6213 * filename).
6215 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
6216 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6217 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
6218 char *last_slash;
6219 char *fname_dst_lcomp_base_mod = NULL;
6220 struct smb_filename *smb_fname_orig_lcomp = NULL;
6223 * Get the last component of the destination name.
6225 last_slash = strrchr_m(smb_fname_dst->base_name, '/');
6226 if (last_slash) {
6227 fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1);
6228 } else {
6229 fname_dst_lcomp_base_mod = talloc_strdup(ctx, smb_fname_dst->base_name);
6231 if (!fname_dst_lcomp_base_mod) {
6232 status = NT_STATUS_NO_MEMORY;
6233 goto out;
6237 * Create an smb_filename struct using the original last
6238 * component of the destination.
6240 status = create_synthetic_smb_fname_split(ctx,
6241 smb_fname_dst->original_lcomp, NULL,
6242 &smb_fname_orig_lcomp);
6243 if (!NT_STATUS_IS_OK(status)) {
6244 TALLOC_FREE(fname_dst_lcomp_base_mod);
6245 goto out;
6248 /* If the base names only differ by case, use original. */
6249 if(!strcsequal(fname_dst_lcomp_base_mod,
6250 smb_fname_orig_lcomp->base_name)) {
6251 char *tmp;
6253 * Replace the modified last component with the
6254 * original.
6256 if (last_slash) {
6257 *last_slash = '\0'; /* Truncate at the '/' */
6258 tmp = talloc_asprintf(smb_fname_dst,
6259 "%s/%s",
6260 smb_fname_dst->base_name,
6261 smb_fname_orig_lcomp->base_name);
6262 } else {
6263 tmp = talloc_asprintf(smb_fname_dst,
6264 "%s",
6265 smb_fname_orig_lcomp->base_name);
6267 if (tmp == NULL) {
6268 status = NT_STATUS_NO_MEMORY;
6269 TALLOC_FREE(fname_dst_lcomp_base_mod);
6270 TALLOC_FREE(smb_fname_orig_lcomp);
6271 goto out;
6273 TALLOC_FREE(smb_fname_dst->base_name);
6274 smb_fname_dst->base_name = tmp;
6277 /* If the stream_names only differ by case, use original. */
6278 if(!strcsequal(smb_fname_dst->stream_name,
6279 smb_fname_orig_lcomp->stream_name)) {
6280 char *tmp = NULL;
6281 /* Use the original stream. */
6282 tmp = talloc_strdup(smb_fname_dst,
6283 smb_fname_orig_lcomp->stream_name);
6284 if (tmp == NULL) {
6285 status = NT_STATUS_NO_MEMORY;
6286 TALLOC_FREE(fname_dst_lcomp_base_mod);
6287 TALLOC_FREE(smb_fname_orig_lcomp);
6288 goto out;
6290 TALLOC_FREE(smb_fname_dst->stream_name);
6291 smb_fname_dst->stream_name = tmp;
6293 TALLOC_FREE(fname_dst_lcomp_base_mod);
6294 TALLOC_FREE(smb_fname_orig_lcomp);
6298 * If the src and dest names are identical - including case,
6299 * don't do the rename, just return success.
6302 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6303 strcsequal(fsp->fsp_name->stream_name,
6304 smb_fname_dst->stream_name)) {
6305 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6306 "- returning success\n",
6307 smb_fname_str_dbg(smb_fname_dst)));
6308 status = NT_STATUS_OK;
6309 goto out;
6312 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6313 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6315 /* Return the correct error code if both names aren't streams. */
6316 if (!old_is_stream && new_is_stream) {
6317 status = NT_STATUS_OBJECT_NAME_INVALID;
6318 goto out;
6321 if (old_is_stream && !new_is_stream) {
6322 status = NT_STATUS_INVALID_PARAMETER;
6323 goto out;
6326 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6328 if(!replace_if_exists && dst_exists) {
6329 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6330 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6331 smb_fname_str_dbg(smb_fname_dst)));
6332 status = NT_STATUS_OBJECT_NAME_COLLISION;
6333 goto out;
6336 if (dst_exists) {
6337 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6338 &smb_fname_dst->st);
6339 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6340 fileid);
6341 /* The file can be open when renaming a stream */
6342 if (dst_fsp && !new_is_stream) {
6343 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6344 status = NT_STATUS_ACCESS_DENIED;
6345 goto out;
6349 /* Ensure we have a valid stat struct for the source. */
6350 status = vfs_stat_fsp(fsp);
6351 if (!NT_STATUS_IS_OK(status)) {
6352 goto out;
6355 status = can_rename(conn, fsp, attrs);
6357 if (!NT_STATUS_IS_OK(status)) {
6358 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6359 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6360 smb_fname_str_dbg(smb_fname_dst)));
6361 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6362 status = NT_STATUS_ACCESS_DENIED;
6363 goto out;
6366 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6367 status = NT_STATUS_ACCESS_DENIED;
6370 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
6373 * We have the file open ourselves, so not being able to get the
6374 * corresponding share mode lock is a fatal error.
6377 SMB_ASSERT(lck != NULL);
6379 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6380 uint32 create_options = fsp->fh->private_options;
6382 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6383 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6384 smb_fname_str_dbg(smb_fname_dst)));
6386 if (!lp_posix_pathnames() &&
6387 (lp_map_archive(SNUM(conn)) ||
6388 lp_store_dos_attributes(SNUM(conn)))) {
6389 /* We must set the archive bit on the newly
6390 renamed file. */
6391 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6392 uint32_t old_dosmode = dos_mode(conn,
6393 smb_fname_dst);
6394 file_set_dosmode(conn,
6395 smb_fname_dst,
6396 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6397 NULL,
6398 true);
6402 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6403 smb_fname_dst);
6405 rename_open_files(conn, lck, fsp->name_hash, smb_fname_dst);
6408 * A rename acts as a new file create w.r.t. allowing an initial delete
6409 * on close, probably because in Windows there is a new handle to the
6410 * new file. If initial delete on close was requested but not
6411 * originally set, we need to set it here. This is probably not 100% correct,
6412 * but will work for the CIFSFS client which in non-posix mode
6413 * depends on these semantics. JRA.
6416 if (create_options & FILE_DELETE_ON_CLOSE) {
6417 status = can_set_delete_on_close(fsp, 0);
6419 if (NT_STATUS_IS_OK(status)) {
6420 /* Note that here we set the *inital* delete on close flag,
6421 * not the regular one. The magic gets handled in close. */
6422 fsp->initial_delete_on_close = True;
6425 TALLOC_FREE(lck);
6426 status = NT_STATUS_OK;
6427 goto out;
6430 TALLOC_FREE(lck);
6432 if (errno == ENOTDIR || errno == EISDIR) {
6433 status = NT_STATUS_OBJECT_NAME_COLLISION;
6434 } else {
6435 status = map_nt_error_from_unix(errno);
6438 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6439 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6440 smb_fname_str_dbg(smb_fname_dst)));
6442 out:
6443 TALLOC_FREE(smb_fname_dst);
6445 return status;
6448 /****************************************************************************
6449 The guts of the rename command, split out so it may be called by the NT SMB
6450 code.
6451 ****************************************************************************/
6453 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6454 connection_struct *conn,
6455 struct smb_request *req,
6456 struct smb_filename *smb_fname_src,
6457 struct smb_filename *smb_fname_dst,
6458 uint32 attrs,
6459 bool replace_if_exists,
6460 bool src_has_wild,
6461 bool dest_has_wild,
6462 uint32_t access_mask)
6464 char *fname_src_dir = NULL;
6465 char *fname_src_mask = NULL;
6466 int count=0;
6467 NTSTATUS status = NT_STATUS_OK;
6468 struct smb_Dir *dir_hnd = NULL;
6469 const char *dname = NULL;
6470 char *talloced = NULL;
6471 long offset = 0;
6472 int create_options = 0;
6473 bool posix_pathnames = lp_posix_pathnames();
6476 * Split the old name into directory and last component
6477 * strings. Note that unix_convert may have stripped off a
6478 * leading ./ from both name and newname if the rename is
6479 * at the root of the share. We need to make sure either both
6480 * name and newname contain a / character or neither of them do
6481 * as this is checked in resolve_wildcards().
6484 /* Split up the directory from the filename/mask. */
6485 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6486 &fname_src_dir, &fname_src_mask);
6487 if (!NT_STATUS_IS_OK(status)) {
6488 status = NT_STATUS_NO_MEMORY;
6489 goto out;
6493 * We should only check the mangled cache
6494 * here if unix_convert failed. This means
6495 * that the path in 'mask' doesn't exist
6496 * on the file system and so we need to look
6497 * for a possible mangle. This patch from
6498 * Tine Smukavec <valentin.smukavec@hermes.si>.
6501 if (!VALID_STAT(smb_fname_src->st) &&
6502 mangle_is_mangled(fname_src_mask, conn->params)) {
6503 char *new_mask = NULL;
6504 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6505 conn->params);
6506 if (new_mask) {
6507 TALLOC_FREE(fname_src_mask);
6508 fname_src_mask = new_mask;
6512 if (!src_has_wild) {
6513 files_struct *fsp;
6516 * Only one file needs to be renamed. Append the mask back
6517 * onto the directory.
6519 TALLOC_FREE(smb_fname_src->base_name);
6520 if (ISDOT(fname_src_dir)) {
6521 /* Ensure we use canonical names on open. */
6522 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6523 "%s",
6524 fname_src_mask);
6525 } else {
6526 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6527 "%s/%s",
6528 fname_src_dir,
6529 fname_src_mask);
6531 if (!smb_fname_src->base_name) {
6532 status = NT_STATUS_NO_MEMORY;
6533 goto out;
6536 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6537 "case_preserve = %d, short case preserve = %d, "
6538 "directory = %s, newname = %s, "
6539 "last_component_dest = %s\n",
6540 conn->case_sensitive, conn->case_preserve,
6541 conn->short_case_preserve,
6542 smb_fname_str_dbg(smb_fname_src),
6543 smb_fname_str_dbg(smb_fname_dst),
6544 smb_fname_dst->original_lcomp));
6546 /* The dest name still may have wildcards. */
6547 if (dest_has_wild) {
6548 char *fname_dst_mod = NULL;
6549 if (!resolve_wildcards(smb_fname_dst,
6550 smb_fname_src->base_name,
6551 smb_fname_dst->base_name,
6552 &fname_dst_mod)) {
6553 DEBUG(6, ("rename_internals: resolve_wildcards "
6554 "%s %s failed\n",
6555 smb_fname_src->base_name,
6556 smb_fname_dst->base_name));
6557 status = NT_STATUS_NO_MEMORY;
6558 goto out;
6560 TALLOC_FREE(smb_fname_dst->base_name);
6561 smb_fname_dst->base_name = fname_dst_mod;
6564 ZERO_STRUCT(smb_fname_src->st);
6565 if (posix_pathnames) {
6566 SMB_VFS_LSTAT(conn, smb_fname_src);
6567 } else {
6568 SMB_VFS_STAT(conn, smb_fname_src);
6571 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6572 create_options |= FILE_DIRECTORY_FILE;
6575 status = SMB_VFS_CREATE_FILE(
6576 conn, /* conn */
6577 req, /* req */
6578 0, /* root_dir_fid */
6579 smb_fname_src, /* fname */
6580 access_mask, /* access_mask */
6581 (FILE_SHARE_READ | /* share_access */
6582 FILE_SHARE_WRITE),
6583 FILE_OPEN, /* create_disposition*/
6584 create_options, /* create_options */
6585 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6586 0, /* oplock_request */
6587 0, /* allocation_size */
6588 0, /* private_flags */
6589 NULL, /* sd */
6590 NULL, /* ea_list */
6591 &fsp, /* result */
6592 NULL); /* pinfo */
6594 if (!NT_STATUS_IS_OK(status)) {
6595 DEBUG(3, ("Could not open rename source %s: %s\n",
6596 smb_fname_str_dbg(smb_fname_src),
6597 nt_errstr(status)));
6598 goto out;
6601 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6602 attrs, replace_if_exists);
6604 close_file(req, fsp, NORMAL_CLOSE);
6606 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
6607 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
6608 smb_fname_str_dbg(smb_fname_dst)));
6610 goto out;
6614 * Wildcards - process each file that matches.
6616 if (strequal(fname_src_mask, "????????.???")) {
6617 TALLOC_FREE(fname_src_mask);
6618 fname_src_mask = talloc_strdup(ctx, "*");
6619 if (!fname_src_mask) {
6620 status = NT_STATUS_NO_MEMORY;
6621 goto out;
6625 status = check_name(conn, fname_src_dir);
6626 if (!NT_STATUS_IS_OK(status)) {
6627 goto out;
6630 dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask,
6631 attrs);
6632 if (dir_hnd == NULL) {
6633 status = map_nt_error_from_unix(errno);
6634 goto out;
6637 status = NT_STATUS_NO_SUCH_FILE;
6639 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
6640 * - gentest fix. JRA
6643 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
6644 &talloced))) {
6645 files_struct *fsp = NULL;
6646 char *destname = NULL;
6647 bool sysdir_entry = False;
6649 /* Quick check for "." and ".." */
6650 if (ISDOT(dname) || ISDOTDOT(dname)) {
6651 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
6652 sysdir_entry = True;
6653 } else {
6654 TALLOC_FREE(talloced);
6655 continue;
6659 if (!is_visible_file(conn, fname_src_dir, dname,
6660 &smb_fname_src->st, false)) {
6661 TALLOC_FREE(talloced);
6662 continue;
6665 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
6666 TALLOC_FREE(talloced);
6667 continue;
6670 if (sysdir_entry) {
6671 status = NT_STATUS_OBJECT_NAME_INVALID;
6672 break;
6675 TALLOC_FREE(smb_fname_src->base_name);
6676 if (ISDOT(fname_src_dir)) {
6677 /* Ensure we use canonical names on open. */
6678 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6679 "%s",
6680 dname);
6681 } else {
6682 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6683 "%s/%s",
6684 fname_src_dir,
6685 dname);
6687 if (!smb_fname_src->base_name) {
6688 status = NT_STATUS_NO_MEMORY;
6689 goto out;
6692 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6693 smb_fname_dst->base_name,
6694 &destname)) {
6695 DEBUG(6, ("resolve_wildcards %s %s failed\n",
6696 smb_fname_src->base_name, destname));
6697 TALLOC_FREE(talloced);
6698 continue;
6700 if (!destname) {
6701 status = NT_STATUS_NO_MEMORY;
6702 goto out;
6705 TALLOC_FREE(smb_fname_dst->base_name);
6706 smb_fname_dst->base_name = destname;
6708 ZERO_STRUCT(smb_fname_src->st);
6709 if (posix_pathnames) {
6710 SMB_VFS_LSTAT(conn, smb_fname_src);
6711 } else {
6712 SMB_VFS_STAT(conn, smb_fname_src);
6715 create_options = 0;
6717 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6718 create_options |= FILE_DIRECTORY_FILE;
6721 status = SMB_VFS_CREATE_FILE(
6722 conn, /* conn */
6723 req, /* req */
6724 0, /* root_dir_fid */
6725 smb_fname_src, /* fname */
6726 access_mask, /* access_mask */
6727 (FILE_SHARE_READ | /* share_access */
6728 FILE_SHARE_WRITE),
6729 FILE_OPEN, /* create_disposition*/
6730 create_options, /* create_options */
6731 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6732 0, /* oplock_request */
6733 0, /* allocation_size */
6734 0, /* private_flags */
6735 NULL, /* sd */
6736 NULL, /* ea_list */
6737 &fsp, /* result */
6738 NULL); /* pinfo */
6740 if (!NT_STATUS_IS_OK(status)) {
6741 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
6742 "returned %s rename %s -> %s\n",
6743 nt_errstr(status),
6744 smb_fname_str_dbg(smb_fname_src),
6745 smb_fname_str_dbg(smb_fname_dst)));
6746 break;
6749 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6750 dname);
6751 if (!smb_fname_dst->original_lcomp) {
6752 status = NT_STATUS_NO_MEMORY;
6753 goto out;
6756 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6757 attrs, replace_if_exists);
6759 close_file(req, fsp, NORMAL_CLOSE);
6761 if (!NT_STATUS_IS_OK(status)) {
6762 DEBUG(3, ("rename_internals_fsp returned %s for "
6763 "rename %s -> %s\n", nt_errstr(status),
6764 smb_fname_str_dbg(smb_fname_src),
6765 smb_fname_str_dbg(smb_fname_dst)));
6766 break;
6769 count++;
6771 DEBUG(3,("rename_internals: doing rename on %s -> "
6772 "%s\n", smb_fname_str_dbg(smb_fname_src),
6773 smb_fname_str_dbg(smb_fname_src)));
6774 TALLOC_FREE(talloced);
6776 TALLOC_FREE(dir_hnd);
6778 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
6779 status = map_nt_error_from_unix(errno);
6782 out:
6783 TALLOC_FREE(talloced);
6784 TALLOC_FREE(fname_src_dir);
6785 TALLOC_FREE(fname_src_mask);
6786 return status;
6789 /****************************************************************************
6790 Reply to a mv.
6791 ****************************************************************************/
6793 void reply_mv(struct smb_request *req)
6795 connection_struct *conn = req->conn;
6796 char *name = NULL;
6797 char *newname = NULL;
6798 const char *p;
6799 uint32 attrs;
6800 NTSTATUS status;
6801 bool src_has_wcard = False;
6802 bool dest_has_wcard = False;
6803 TALLOC_CTX *ctx = talloc_tos();
6804 struct smb_filename *smb_fname_src = NULL;
6805 struct smb_filename *smb_fname_dst = NULL;
6806 uint32_t src_ucf_flags = lp_posix_pathnames() ? UCF_UNIX_NAME_LOOKUP : UCF_COND_ALLOW_WCARD_LCOMP;
6807 uint32_t dst_ucf_flags = UCF_SAVE_LCOMP | (lp_posix_pathnames() ? 0 : UCF_COND_ALLOW_WCARD_LCOMP);
6808 bool stream_rename = false;
6810 START_PROFILE(SMBmv);
6812 if (req->wct < 1) {
6813 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6814 goto out;
6817 attrs = SVAL(req->vwv+0, 0);
6819 p = (const char *)req->buf + 1;
6820 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
6821 &status, &src_has_wcard);
6822 if (!NT_STATUS_IS_OK(status)) {
6823 reply_nterror(req, status);
6824 goto out;
6826 p++;
6827 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
6828 &status, &dest_has_wcard);
6829 if (!NT_STATUS_IS_OK(status)) {
6830 reply_nterror(req, status);
6831 goto out;
6834 if (!lp_posix_pathnames()) {
6835 /* The newname must begin with a ':' if the
6836 name contains a ':'. */
6837 if (strchr_m(name, ':')) {
6838 if (newname[0] != ':') {
6839 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6840 goto out;
6842 stream_rename = true;
6846 status = filename_convert(ctx,
6847 conn,
6848 req->flags2 & FLAGS2_DFS_PATHNAMES,
6849 name,
6850 src_ucf_flags,
6851 &src_has_wcard,
6852 &smb_fname_src);
6854 if (!NT_STATUS_IS_OK(status)) {
6855 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6856 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6857 ERRSRV, ERRbadpath);
6858 goto out;
6860 reply_nterror(req, status);
6861 goto out;
6864 status = filename_convert(ctx,
6865 conn,
6866 req->flags2 & FLAGS2_DFS_PATHNAMES,
6867 newname,
6868 dst_ucf_flags,
6869 &dest_has_wcard,
6870 &smb_fname_dst);
6872 if (!NT_STATUS_IS_OK(status)) {
6873 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6874 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6875 ERRSRV, ERRbadpath);
6876 goto out;
6878 reply_nterror(req, status);
6879 goto out;
6882 if (stream_rename) {
6883 /* smb_fname_dst->base_name must be the same as
6884 smb_fname_src->base_name. */
6885 TALLOC_FREE(smb_fname_dst->base_name);
6886 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
6887 smb_fname_src->base_name);
6888 if (!smb_fname_dst->base_name) {
6889 reply_nterror(req, NT_STATUS_NO_MEMORY);
6890 goto out;
6894 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
6895 smb_fname_str_dbg(smb_fname_dst)));
6897 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
6898 attrs, False, src_has_wcard, dest_has_wcard,
6899 DELETE_ACCESS);
6900 if (!NT_STATUS_IS_OK(status)) {
6901 if (open_was_deferred(req->sconn, req->mid)) {
6902 /* We have re-scheduled this call. */
6903 goto out;
6905 reply_nterror(req, status);
6906 goto out;
6909 reply_outbuf(req, 0, 0);
6910 out:
6911 TALLOC_FREE(smb_fname_src);
6912 TALLOC_FREE(smb_fname_dst);
6913 END_PROFILE(SMBmv);
6914 return;
6917 /*******************************************************************
6918 Copy a file as part of a reply_copy.
6919 ******************************************************************/
6922 * TODO: check error codes on all callers
6925 NTSTATUS copy_file(TALLOC_CTX *ctx,
6926 connection_struct *conn,
6927 struct smb_filename *smb_fname_src,
6928 struct smb_filename *smb_fname_dst,
6929 int ofun,
6930 int count,
6931 bool target_is_directory)
6933 struct smb_filename *smb_fname_dst_tmp = NULL;
6934 off_t ret=-1;
6935 files_struct *fsp1,*fsp2;
6936 uint32 dosattrs;
6937 uint32 new_create_disposition;
6938 NTSTATUS status;
6941 status = copy_smb_filename(ctx, smb_fname_dst, &smb_fname_dst_tmp);
6942 if (!NT_STATUS_IS_OK(status)) {
6943 return status;
6947 * If the target is a directory, extract the last component from the
6948 * src filename and append it to the dst filename
6950 if (target_is_directory) {
6951 const char *p;
6953 /* dest/target can't be a stream if it's a directory. */
6954 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
6956 p = strrchr_m(smb_fname_src->base_name,'/');
6957 if (p) {
6958 p++;
6959 } else {
6960 p = smb_fname_src->base_name;
6962 smb_fname_dst_tmp->base_name =
6963 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
6965 if (!smb_fname_dst_tmp->base_name) {
6966 status = NT_STATUS_NO_MEMORY;
6967 goto out;
6971 status = vfs_file_exist(conn, smb_fname_src);
6972 if (!NT_STATUS_IS_OK(status)) {
6973 goto out;
6976 if (!target_is_directory && count) {
6977 new_create_disposition = FILE_OPEN;
6978 } else {
6979 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
6980 0, ofun,
6981 NULL, NULL,
6982 &new_create_disposition,
6983 NULL,
6984 NULL)) {
6985 status = NT_STATUS_INVALID_PARAMETER;
6986 goto out;
6990 /* Open the src file for reading. */
6991 status = SMB_VFS_CREATE_FILE(
6992 conn, /* conn */
6993 NULL, /* req */
6994 0, /* root_dir_fid */
6995 smb_fname_src, /* fname */
6996 FILE_GENERIC_READ, /* access_mask */
6997 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6998 FILE_OPEN, /* create_disposition*/
6999 0, /* create_options */
7000 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
7001 INTERNAL_OPEN_ONLY, /* oplock_request */
7002 0, /* allocation_size */
7003 0, /* private_flags */
7004 NULL, /* sd */
7005 NULL, /* ea_list */
7006 &fsp1, /* result */
7007 NULL); /* psbuf */
7009 if (!NT_STATUS_IS_OK(status)) {
7010 goto out;
7013 dosattrs = dos_mode(conn, smb_fname_src);
7015 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
7016 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
7019 /* Open the dst file for writing. */
7020 status = SMB_VFS_CREATE_FILE(
7021 conn, /* conn */
7022 NULL, /* req */
7023 0, /* root_dir_fid */
7024 smb_fname_dst, /* fname */
7025 FILE_GENERIC_WRITE, /* access_mask */
7026 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7027 new_create_disposition, /* create_disposition*/
7028 0, /* create_options */
7029 dosattrs, /* file_attributes */
7030 INTERNAL_OPEN_ONLY, /* oplock_request */
7031 0, /* allocation_size */
7032 0, /* private_flags */
7033 NULL, /* sd */
7034 NULL, /* ea_list */
7035 &fsp2, /* result */
7036 NULL); /* psbuf */
7038 if (!NT_STATUS_IS_OK(status)) {
7039 close_file(NULL, fsp1, ERROR_CLOSE);
7040 goto out;
7043 if (ofun & OPENX_FILE_EXISTS_OPEN) {
7044 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
7045 if (ret == -1) {
7046 DEBUG(0, ("error - vfs lseek returned error %s\n",
7047 strerror(errno)));
7048 status = map_nt_error_from_unix(errno);
7049 close_file(NULL, fsp1, ERROR_CLOSE);
7050 close_file(NULL, fsp2, ERROR_CLOSE);
7051 goto out;
7055 /* Do the actual copy. */
7056 if (smb_fname_src->st.st_ex_size) {
7057 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
7058 } else {
7059 ret = 0;
7062 close_file(NULL, fsp1, NORMAL_CLOSE);
7064 /* Ensure the modtime is set correctly on the destination file. */
7065 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
7068 * As we are opening fsp1 read-only we only expect
7069 * an error on close on fsp2 if we are out of space.
7070 * Thus we don't look at the error return from the
7071 * close of fsp1.
7073 status = close_file(NULL, fsp2, NORMAL_CLOSE);
7075 if (!NT_STATUS_IS_OK(status)) {
7076 goto out;
7079 if (ret != (off_t)smb_fname_src->st.st_ex_size) {
7080 status = NT_STATUS_DISK_FULL;
7081 goto out;
7084 status = NT_STATUS_OK;
7086 out:
7087 TALLOC_FREE(smb_fname_dst_tmp);
7088 return status;
7091 /****************************************************************************
7092 Reply to a file copy.
7093 ****************************************************************************/
7095 void reply_copy(struct smb_request *req)
7097 connection_struct *conn = req->conn;
7098 struct smb_filename *smb_fname_src = NULL;
7099 struct smb_filename *smb_fname_dst = NULL;
7100 char *fname_src = NULL;
7101 char *fname_dst = NULL;
7102 char *fname_src_mask = NULL;
7103 char *fname_src_dir = NULL;
7104 const char *p;
7105 int count=0;
7106 int error = ERRnoaccess;
7107 int tid2;
7108 int ofun;
7109 int flags;
7110 bool target_is_directory=False;
7111 bool source_has_wild = False;
7112 bool dest_has_wild = False;
7113 NTSTATUS status;
7114 TALLOC_CTX *ctx = talloc_tos();
7116 START_PROFILE(SMBcopy);
7118 if (req->wct < 3) {
7119 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7120 goto out;
7123 tid2 = SVAL(req->vwv+0, 0);
7124 ofun = SVAL(req->vwv+1, 0);
7125 flags = SVAL(req->vwv+2, 0);
7127 p = (const char *)req->buf;
7128 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
7129 &status, &source_has_wild);
7130 if (!NT_STATUS_IS_OK(status)) {
7131 reply_nterror(req, status);
7132 goto out;
7134 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
7135 &status, &dest_has_wild);
7136 if (!NT_STATUS_IS_OK(status)) {
7137 reply_nterror(req, status);
7138 goto out;
7141 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
7143 if (tid2 != conn->cnum) {
7144 /* can't currently handle inter share copies XXXX */
7145 DEBUG(3,("Rejecting inter-share copy\n"));
7146 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
7147 goto out;
7150 status = filename_convert(ctx, conn,
7151 req->flags2 & FLAGS2_DFS_PATHNAMES,
7152 fname_src,
7153 UCF_COND_ALLOW_WCARD_LCOMP,
7154 &source_has_wild,
7155 &smb_fname_src);
7156 if (!NT_STATUS_IS_OK(status)) {
7157 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7158 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7159 ERRSRV, ERRbadpath);
7160 goto out;
7162 reply_nterror(req, status);
7163 goto out;
7166 status = filename_convert(ctx, conn,
7167 req->flags2 & FLAGS2_DFS_PATHNAMES,
7168 fname_dst,
7169 UCF_COND_ALLOW_WCARD_LCOMP,
7170 &dest_has_wild,
7171 &smb_fname_dst);
7172 if (!NT_STATUS_IS_OK(status)) {
7173 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7174 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7175 ERRSRV, ERRbadpath);
7176 goto out;
7178 reply_nterror(req, status);
7179 goto out;
7182 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
7184 if ((flags&1) && target_is_directory) {
7185 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
7186 goto out;
7189 if ((flags&2) && !target_is_directory) {
7190 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
7191 goto out;
7194 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
7195 /* wants a tree copy! XXXX */
7196 DEBUG(3,("Rejecting tree copy\n"));
7197 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7198 goto out;
7201 /* Split up the directory from the filename/mask. */
7202 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7203 &fname_src_dir, &fname_src_mask);
7204 if (!NT_STATUS_IS_OK(status)) {
7205 reply_nterror(req, NT_STATUS_NO_MEMORY);
7206 goto out;
7210 * We should only check the mangled cache
7211 * here if unix_convert failed. This means
7212 * that the path in 'mask' doesn't exist
7213 * on the file system and so we need to look
7214 * for a possible mangle. This patch from
7215 * Tine Smukavec <valentin.smukavec@hermes.si>.
7217 if (!VALID_STAT(smb_fname_src->st) &&
7218 mangle_is_mangled(fname_src_mask, conn->params)) {
7219 char *new_mask = NULL;
7220 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
7221 &new_mask, conn->params);
7223 /* Use demangled name if one was successfully found. */
7224 if (new_mask) {
7225 TALLOC_FREE(fname_src_mask);
7226 fname_src_mask = new_mask;
7230 if (!source_has_wild) {
7233 * Only one file needs to be copied. Append the mask back onto
7234 * the directory.
7236 TALLOC_FREE(smb_fname_src->base_name);
7237 if (ISDOT(fname_src_dir)) {
7238 /* Ensure we use canonical names on open. */
7239 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7240 "%s",
7241 fname_src_mask);
7242 } else {
7243 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7244 "%s/%s",
7245 fname_src_dir,
7246 fname_src_mask);
7248 if (!smb_fname_src->base_name) {
7249 reply_nterror(req, NT_STATUS_NO_MEMORY);
7250 goto out;
7253 if (dest_has_wild) {
7254 char *fname_dst_mod = NULL;
7255 if (!resolve_wildcards(smb_fname_dst,
7256 smb_fname_src->base_name,
7257 smb_fname_dst->base_name,
7258 &fname_dst_mod)) {
7259 reply_nterror(req, NT_STATUS_NO_MEMORY);
7260 goto out;
7262 TALLOC_FREE(smb_fname_dst->base_name);
7263 smb_fname_dst->base_name = fname_dst_mod;
7266 status = check_name(conn, smb_fname_src->base_name);
7267 if (!NT_STATUS_IS_OK(status)) {
7268 reply_nterror(req, status);
7269 goto out;
7272 status = check_name(conn, smb_fname_dst->base_name);
7273 if (!NT_STATUS_IS_OK(status)) {
7274 reply_nterror(req, status);
7275 goto out;
7278 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7279 ofun, count, target_is_directory);
7281 if(!NT_STATUS_IS_OK(status)) {
7282 reply_nterror(req, status);
7283 goto out;
7284 } else {
7285 count++;
7287 } else {
7288 struct smb_Dir *dir_hnd = NULL;
7289 const char *dname = NULL;
7290 char *talloced = NULL;
7291 long offset = 0;
7294 * There is a wildcard that requires us to actually read the
7295 * src dir and copy each file matching the mask to the dst.
7296 * Right now streams won't be copied, but this could
7297 * presumably be added with a nested loop for reach dir entry.
7299 SMB_ASSERT(!smb_fname_src->stream_name);
7300 SMB_ASSERT(!smb_fname_dst->stream_name);
7302 smb_fname_src->stream_name = NULL;
7303 smb_fname_dst->stream_name = NULL;
7305 if (strequal(fname_src_mask,"????????.???")) {
7306 TALLOC_FREE(fname_src_mask);
7307 fname_src_mask = talloc_strdup(ctx, "*");
7308 if (!fname_src_mask) {
7309 reply_nterror(req, NT_STATUS_NO_MEMORY);
7310 goto out;
7314 status = check_name(conn, fname_src_dir);
7315 if (!NT_STATUS_IS_OK(status)) {
7316 reply_nterror(req, status);
7317 goto out;
7320 dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0);
7321 if (dir_hnd == NULL) {
7322 status = map_nt_error_from_unix(errno);
7323 reply_nterror(req, status);
7324 goto out;
7327 error = ERRbadfile;
7329 /* Iterate over the src dir copying each entry to the dst. */
7330 while ((dname = ReadDirName(dir_hnd, &offset,
7331 &smb_fname_src->st, &talloced))) {
7332 char *destname = NULL;
7334 if (ISDOT(dname) || ISDOTDOT(dname)) {
7335 TALLOC_FREE(talloced);
7336 continue;
7339 if (!is_visible_file(conn, fname_src_dir, dname,
7340 &smb_fname_src->st, false)) {
7341 TALLOC_FREE(talloced);
7342 continue;
7345 if(!mask_match(dname, fname_src_mask,
7346 conn->case_sensitive)) {
7347 TALLOC_FREE(talloced);
7348 continue;
7351 error = ERRnoaccess;
7353 /* Get the src smb_fname struct setup. */
7354 TALLOC_FREE(smb_fname_src->base_name);
7355 if (ISDOT(fname_src_dir)) {
7356 /* Ensure we use canonical names on open. */
7357 smb_fname_src->base_name =
7358 talloc_asprintf(smb_fname_src, "%s",
7359 dname);
7360 } else {
7361 smb_fname_src->base_name =
7362 talloc_asprintf(smb_fname_src, "%s/%s",
7363 fname_src_dir, dname);
7366 if (!smb_fname_src->base_name) {
7367 TALLOC_FREE(dir_hnd);
7368 TALLOC_FREE(talloced);
7369 reply_nterror(req, NT_STATUS_NO_MEMORY);
7370 goto out;
7373 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7374 smb_fname_dst->base_name,
7375 &destname)) {
7376 TALLOC_FREE(talloced);
7377 continue;
7379 if (!destname) {
7380 TALLOC_FREE(dir_hnd);
7381 TALLOC_FREE(talloced);
7382 reply_nterror(req, NT_STATUS_NO_MEMORY);
7383 goto out;
7386 TALLOC_FREE(smb_fname_dst->base_name);
7387 smb_fname_dst->base_name = destname;
7389 status = check_name(conn, smb_fname_src->base_name);
7390 if (!NT_STATUS_IS_OK(status)) {
7391 TALLOC_FREE(dir_hnd);
7392 TALLOC_FREE(talloced);
7393 reply_nterror(req, status);
7394 goto out;
7397 status = check_name(conn, smb_fname_dst->base_name);
7398 if (!NT_STATUS_IS_OK(status)) {
7399 TALLOC_FREE(dir_hnd);
7400 TALLOC_FREE(talloced);
7401 reply_nterror(req, status);
7402 goto out;
7405 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7406 smb_fname_src->base_name,
7407 smb_fname_dst->base_name));
7409 status = copy_file(ctx, conn, smb_fname_src,
7410 smb_fname_dst, ofun, count,
7411 target_is_directory);
7412 if (NT_STATUS_IS_OK(status)) {
7413 count++;
7416 TALLOC_FREE(talloced);
7418 TALLOC_FREE(dir_hnd);
7421 if (count == 0) {
7422 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7423 goto out;
7426 reply_outbuf(req, 1, 0);
7427 SSVAL(req->outbuf,smb_vwv0,count);
7428 out:
7429 TALLOC_FREE(smb_fname_src);
7430 TALLOC_FREE(smb_fname_dst);
7431 TALLOC_FREE(fname_src);
7432 TALLOC_FREE(fname_dst);
7433 TALLOC_FREE(fname_src_mask);
7434 TALLOC_FREE(fname_src_dir);
7436 END_PROFILE(SMBcopy);
7437 return;
7440 #undef DBGC_CLASS
7441 #define DBGC_CLASS DBGC_LOCKING
7443 /****************************************************************************
7444 Get a lock pid, dealing with large count requests.
7445 ****************************************************************************/
7447 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7448 bool large_file_format)
7450 if(!large_file_format)
7451 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7452 else
7453 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7456 /****************************************************************************
7457 Get a lock count, dealing with large count requests.
7458 ****************************************************************************/
7460 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7461 bool large_file_format)
7463 uint64_t count = 0;
7465 if(!large_file_format) {
7466 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7467 } else {
7469 #if defined(HAVE_LONGLONG)
7470 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7471 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7472 #else /* HAVE_LONGLONG */
7475 * NT4.x seems to be broken in that it sends large file (64 bit)
7476 * lockingX calls even if the CAP_LARGE_FILES was *not*
7477 * negotiated. For boxes without large unsigned ints truncate the
7478 * lock count by dropping the top 32 bits.
7481 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
7482 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
7483 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
7484 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
7485 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
7488 count = (uint64_t)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
7489 #endif /* HAVE_LONGLONG */
7492 return count;
7495 #if !defined(HAVE_LONGLONG)
7496 /****************************************************************************
7497 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
7498 ****************************************************************************/
7500 static uint32 map_lock_offset(uint32 high, uint32 low)
7502 unsigned int i;
7503 uint32 mask = 0;
7504 uint32 highcopy = high;
7507 * Try and find out how many significant bits there are in high.
7510 for(i = 0; highcopy; i++)
7511 highcopy >>= 1;
7514 * We use 31 bits not 32 here as POSIX
7515 * lock offsets may not be negative.
7518 mask = (~0) << (31 - i);
7520 if(low & mask)
7521 return 0; /* Fail. */
7523 high <<= (31 - i);
7525 return (high|low);
7527 #endif /* !defined(HAVE_LONGLONG) */
7529 /****************************************************************************
7530 Get a lock offset, dealing with large offset requests.
7531 ****************************************************************************/
7533 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7534 bool large_file_format, bool *err)
7536 uint64_t offset = 0;
7538 *err = False;
7540 if(!large_file_format) {
7541 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7542 } else {
7544 #if defined(HAVE_LONGLONG)
7545 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7546 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7547 #else /* HAVE_LONGLONG */
7550 * NT4.x seems to be broken in that it sends large file (64 bit)
7551 * lockingX calls even if the CAP_LARGE_FILES was *not*
7552 * negotiated. For boxes without large unsigned ints mangle the
7553 * lock offset by mapping the top 32 bits onto the lower 32.
7556 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
7557 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7558 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
7559 uint32 new_low = 0;
7561 if((new_low = map_lock_offset(high, low)) == 0) {
7562 *err = True;
7563 return (uint64_t)-1;
7566 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
7567 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
7568 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
7569 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
7572 offset = (uint64_t)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7573 #endif /* HAVE_LONGLONG */
7576 return offset;
7579 NTSTATUS smbd_do_locking(struct smb_request *req,
7580 files_struct *fsp,
7581 uint8_t type,
7582 int32_t timeout,
7583 uint16_t num_ulocks,
7584 struct smbd_lock_element *ulocks,
7585 uint16_t num_locks,
7586 struct smbd_lock_element *locks,
7587 bool *async)
7589 connection_struct *conn = req->conn;
7590 int i;
7591 NTSTATUS status = NT_STATUS_OK;
7593 *async = false;
7595 /* Data now points at the beginning of the list
7596 of smb_unlkrng structs */
7597 for(i = 0; i < (int)num_ulocks; i++) {
7598 struct smbd_lock_element *e = &ulocks[i];
7600 DEBUG(10,("smbd_do_locking: unlock start=%.0f, len=%.0f for "
7601 "pid %u, file %s\n",
7602 (double)e->offset,
7603 (double)e->count,
7604 (unsigned int)e->smblctx,
7605 fsp_str_dbg(fsp)));
7607 if (e->brltype != UNLOCK_LOCK) {
7608 /* this can only happen with SMB2 */
7609 return NT_STATUS_INVALID_PARAMETER;
7612 status = do_unlock(req->sconn->msg_ctx,
7613 fsp,
7614 e->smblctx,
7615 e->count,
7616 e->offset,
7617 WINDOWS_LOCK);
7619 DEBUG(10, ("smbd_do_locking: unlock returned %s\n",
7620 nt_errstr(status)));
7622 if (!NT_STATUS_IS_OK(status)) {
7623 return status;
7627 /* Setup the timeout in seconds. */
7629 if (!lp_blocking_locks(SNUM(conn))) {
7630 timeout = 0;
7633 /* Data now points at the beginning of the list
7634 of smb_lkrng structs */
7636 for(i = 0; i < (int)num_locks; i++) {
7637 struct smbd_lock_element *e = &locks[i];
7639 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
7640 "%llu, file %s timeout = %d\n",
7641 (double)e->offset,
7642 (double)e->count,
7643 (unsigned long long)e->smblctx,
7644 fsp_str_dbg(fsp),
7645 (int)timeout));
7647 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7648 struct blocking_lock_record *blr = NULL;
7650 if (num_locks > 1) {
7652 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
7653 * if the lock vector contains one entry. When given mutliple cancel
7654 * requests in a single PDU we expect the server to return an
7655 * error. Windows servers seem to accept the request but only
7656 * cancel the first lock.
7657 * JRA - Do what Windows does (tm) :-).
7660 #if 0
7661 /* MS-CIFS (2.2.4.32.1) behavior. */
7662 return NT_STATUS_DOS(ERRDOS,
7663 ERRcancelviolation);
7664 #else
7665 /* Windows behavior. */
7666 if (i != 0) {
7667 DEBUG(10,("smbd_do_locking: ignoring subsequent "
7668 "cancel request\n"));
7669 continue;
7671 #endif
7674 if (lp_blocking_locks(SNUM(conn))) {
7676 /* Schedule a message to ourselves to
7677 remove the blocking lock record and
7678 return the right error. */
7680 blr = blocking_lock_cancel_smb1(fsp,
7681 e->smblctx,
7682 e->offset,
7683 e->count,
7684 WINDOWS_LOCK,
7685 type,
7686 NT_STATUS_FILE_LOCK_CONFLICT);
7687 if (blr == NULL) {
7688 return NT_STATUS_DOS(
7689 ERRDOS,
7690 ERRcancelviolation);
7693 /* Remove a matching pending lock. */
7694 status = do_lock_cancel(fsp,
7695 e->smblctx,
7696 e->count,
7697 e->offset,
7698 WINDOWS_LOCK,
7699 blr);
7700 } else {
7701 bool blocking_lock = timeout ? true : false;
7702 bool defer_lock = false;
7703 struct byte_range_lock *br_lck;
7704 uint64_t block_smblctx;
7706 br_lck = do_lock(req->sconn->msg_ctx,
7707 fsp,
7708 e->smblctx,
7709 e->count,
7710 e->offset,
7711 e->brltype,
7712 WINDOWS_LOCK,
7713 blocking_lock,
7714 &status,
7715 &block_smblctx,
7716 NULL);
7718 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
7719 /* Windows internal resolution for blocking locks seems
7720 to be about 200ms... Don't wait for less than that. JRA. */
7721 if (timeout != -1 && timeout < lp_lock_spin_time()) {
7722 timeout = lp_lock_spin_time();
7724 defer_lock = true;
7727 /* If a lock sent with timeout of zero would fail, and
7728 * this lock has been requested multiple times,
7729 * according to brl_lock_failed() we convert this
7730 * request to a blocking lock with a timeout of between
7731 * 150 - 300 milliseconds.
7733 * If lp_lock_spin_time() has been set to 0, we skip
7734 * this blocking retry and fail immediately.
7736 * Replacement for do_lock_spin(). JRA. */
7738 if (!req->sconn->using_smb2 &&
7739 br_lck && lp_blocking_locks(SNUM(conn)) &&
7740 lp_lock_spin_time() && !blocking_lock &&
7741 NT_STATUS_EQUAL((status),
7742 NT_STATUS_FILE_LOCK_CONFLICT))
7744 defer_lock = true;
7745 timeout = lp_lock_spin_time();
7748 if (br_lck && defer_lock) {
7750 * A blocking lock was requested. Package up
7751 * this smb into a queued request and push it
7752 * onto the blocking lock queue.
7754 if(push_blocking_lock_request(br_lck,
7755 req,
7756 fsp,
7757 timeout,
7759 e->smblctx,
7760 e->brltype,
7761 WINDOWS_LOCK,
7762 e->offset,
7763 e->count,
7764 block_smblctx)) {
7765 TALLOC_FREE(br_lck);
7766 *async = true;
7767 return NT_STATUS_OK;
7771 TALLOC_FREE(br_lck);
7774 if (!NT_STATUS_IS_OK(status)) {
7775 break;
7779 /* If any of the above locks failed, then we must unlock
7780 all of the previous locks (X/Open spec). */
7782 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
7784 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7785 i = -1; /* we want to skip the for loop */
7789 * Ensure we don't do a remove on the lock that just failed,
7790 * as under POSIX rules, if we have a lock already there, we
7791 * will delete it (and we shouldn't) .....
7793 for(i--; i >= 0; i--) {
7794 struct smbd_lock_element *e = &locks[i];
7796 do_unlock(req->sconn->msg_ctx,
7797 fsp,
7798 e->smblctx,
7799 e->count,
7800 e->offset,
7801 WINDOWS_LOCK);
7803 return status;
7806 DEBUG(3, ("smbd_do_locking: %s type=%d num_locks=%d num_ulocks=%d\n",
7807 fsp_fnum_dbg(fsp), (unsigned int)type, num_locks, num_ulocks));
7809 return NT_STATUS_OK;
7812 /****************************************************************************
7813 Reply to a lockingX request.
7814 ****************************************************************************/
7816 void reply_lockingX(struct smb_request *req)
7818 connection_struct *conn = req->conn;
7819 files_struct *fsp;
7820 unsigned char locktype;
7821 unsigned char oplocklevel;
7822 uint16 num_ulocks;
7823 uint16 num_locks;
7824 int32 lock_timeout;
7825 int i;
7826 const uint8_t *data;
7827 bool large_file_format;
7828 bool err;
7829 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
7830 struct smbd_lock_element *ulocks;
7831 struct smbd_lock_element *locks;
7832 bool async = false;
7834 START_PROFILE(SMBlockingX);
7836 if (req->wct < 8) {
7837 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7838 END_PROFILE(SMBlockingX);
7839 return;
7842 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
7843 locktype = CVAL(req->vwv+3, 0);
7844 oplocklevel = CVAL(req->vwv+3, 1);
7845 num_ulocks = SVAL(req->vwv+6, 0);
7846 num_locks = SVAL(req->vwv+7, 0);
7847 lock_timeout = IVAL(req->vwv+4, 0);
7848 large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
7850 if (!check_fsp(conn, req, fsp)) {
7851 END_PROFILE(SMBlockingX);
7852 return;
7855 data = req->buf;
7857 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
7858 /* we don't support these - and CANCEL_LOCK makes w2k
7859 and XP reboot so I don't really want to be
7860 compatible! (tridge) */
7861 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
7862 END_PROFILE(SMBlockingX);
7863 return;
7866 /* Check if this is an oplock break on a file
7867 we have granted an oplock on.
7869 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
7870 /* Client can insist on breaking to none. */
7871 bool break_to_none = (oplocklevel == 0);
7872 bool result;
7874 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
7875 "for %s\n", (unsigned int)oplocklevel,
7876 fsp_fnum_dbg(fsp)));
7879 * Make sure we have granted an exclusive or batch oplock on
7880 * this file.
7883 if (fsp->oplock_type == 0) {
7885 /* The Samba4 nbench simulator doesn't understand
7886 the difference between break to level2 and break
7887 to none from level2 - it sends oplock break
7888 replies in both cases. Don't keep logging an error
7889 message here - just ignore it. JRA. */
7891 DEBUG(5,("reply_lockingX: Error : oplock break from "
7892 "client for %s (oplock=%d) and no "
7893 "oplock granted on this file (%s).\n",
7894 fsp_fnum_dbg(fsp), fsp->oplock_type,
7895 fsp_str_dbg(fsp)));
7897 /* if this is a pure oplock break request then don't
7898 * send a reply */
7899 if (num_locks == 0 && num_ulocks == 0) {
7900 END_PROFILE(SMBlockingX);
7901 return;
7902 } else {
7903 END_PROFILE(SMBlockingX);
7904 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
7905 return;
7909 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
7910 (break_to_none)) {
7911 result = remove_oplock(fsp);
7912 } else {
7913 result = downgrade_oplock(fsp);
7916 if (!result) {
7917 DEBUG(0, ("reply_lockingX: error in removing "
7918 "oplock on file %s\n", fsp_str_dbg(fsp)));
7919 /* Hmmm. Is this panic justified? */
7920 smb_panic("internal tdb error");
7923 reply_to_oplock_break_requests(fsp);
7925 /* if this is a pure oplock break request then don't send a
7926 * reply */
7927 if (num_locks == 0 && num_ulocks == 0) {
7928 /* Sanity check - ensure a pure oplock break is not a
7929 chained request. */
7930 if(CVAL(req->vwv+0, 0) != 0xff)
7931 DEBUG(0,("reply_lockingX: Error : pure oplock "
7932 "break is a chained %d request !\n",
7933 (unsigned int)CVAL(req->vwv+0, 0)));
7934 END_PROFILE(SMBlockingX);
7935 return;
7939 if (req->buflen <
7940 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
7941 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7942 END_PROFILE(SMBlockingX);
7943 return;
7946 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
7947 if (ulocks == NULL) {
7948 reply_nterror(req, NT_STATUS_NO_MEMORY);
7949 END_PROFILE(SMBlockingX);
7950 return;
7953 locks = talloc_array(req, struct smbd_lock_element, num_locks);
7954 if (locks == NULL) {
7955 reply_nterror(req, NT_STATUS_NO_MEMORY);
7956 END_PROFILE(SMBlockingX);
7957 return;
7960 /* Data now points at the beginning of the list
7961 of smb_unlkrng structs */
7962 for(i = 0; i < (int)num_ulocks; i++) {
7963 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
7964 ulocks[i].count = get_lock_count(data, i, large_file_format);
7965 ulocks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7966 ulocks[i].brltype = UNLOCK_LOCK;
7969 * There is no error code marked "stupid client bug".... :-).
7971 if(err) {
7972 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7973 END_PROFILE(SMBlockingX);
7974 return;
7978 /* Now do any requested locks */
7979 data += ((large_file_format ? 20 : 10)*num_ulocks);
7981 /* Data now points at the beginning of the list
7982 of smb_lkrng structs */
7984 for(i = 0; i < (int)num_locks; i++) {
7985 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
7986 locks[i].count = get_lock_count(data, i, large_file_format);
7987 locks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7989 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
7990 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7991 locks[i].brltype = PENDING_READ_LOCK;
7992 } else {
7993 locks[i].brltype = READ_LOCK;
7995 } else {
7996 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7997 locks[i].brltype = PENDING_WRITE_LOCK;
7998 } else {
7999 locks[i].brltype = WRITE_LOCK;
8004 * There is no error code marked "stupid client bug".... :-).
8006 if(err) {
8007 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8008 END_PROFILE(SMBlockingX);
8009 return;
8013 status = smbd_do_locking(req, fsp,
8014 locktype, lock_timeout,
8015 num_ulocks, ulocks,
8016 num_locks, locks,
8017 &async);
8018 if (!NT_STATUS_IS_OK(status)) {
8019 END_PROFILE(SMBlockingX);
8020 reply_nterror(req, status);
8021 return;
8023 if (async) {
8024 END_PROFILE(SMBlockingX);
8025 return;
8028 reply_outbuf(req, 2, 0);
8029 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
8030 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
8032 DEBUG(3, ("lockingX %s type=%d num_locks=%d num_ulocks=%d\n",
8033 fsp_fnum_dbg(fsp), (unsigned int)locktype, num_locks, num_ulocks));
8035 END_PROFILE(SMBlockingX);
8038 #undef DBGC_CLASS
8039 #define DBGC_CLASS DBGC_ALL
8041 /****************************************************************************
8042 Reply to a SMBreadbmpx (read block multiplex) request.
8043 Always reply with an error, if someone has a platform really needs this,
8044 please contact vl@samba.org
8045 ****************************************************************************/
8047 void reply_readbmpx(struct smb_request *req)
8049 START_PROFILE(SMBreadBmpx);
8050 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8051 END_PROFILE(SMBreadBmpx);
8052 return;
8055 /****************************************************************************
8056 Reply to a SMBreadbs (read block multiplex secondary) request.
8057 Always reply with an error, if someone has a platform really needs this,
8058 please contact vl@samba.org
8059 ****************************************************************************/
8061 void reply_readbs(struct smb_request *req)
8063 START_PROFILE(SMBreadBs);
8064 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8065 END_PROFILE(SMBreadBs);
8066 return;
8069 /****************************************************************************
8070 Reply to a SMBsetattrE.
8071 ****************************************************************************/
8073 void reply_setattrE(struct smb_request *req)
8075 connection_struct *conn = req->conn;
8076 struct smb_file_time ft;
8077 files_struct *fsp;
8078 NTSTATUS status;
8080 START_PROFILE(SMBsetattrE);
8081 ZERO_STRUCT(ft);
8083 if (req->wct < 7) {
8084 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8085 goto out;
8088 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8090 if(!fsp || (fsp->conn != conn)) {
8091 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8092 goto out;
8096 * Convert the DOS times into unix times.
8099 ft.atime = convert_time_t_to_timespec(
8100 srv_make_unix_date2(req->vwv+3));
8101 ft.mtime = convert_time_t_to_timespec(
8102 srv_make_unix_date2(req->vwv+5));
8103 ft.create_time = convert_time_t_to_timespec(
8104 srv_make_unix_date2(req->vwv+1));
8106 reply_outbuf(req, 0, 0);
8109 * Patch from Ray Frush <frush@engr.colostate.edu>
8110 * Sometimes times are sent as zero - ignore them.
8113 /* Ensure we have a valid stat struct for the source. */
8114 status = vfs_stat_fsp(fsp);
8115 if (!NT_STATUS_IS_OK(status)) {
8116 reply_nterror(req, status);
8117 goto out;
8120 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
8121 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8122 goto out;
8125 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
8126 if (!NT_STATUS_IS_OK(status)) {
8127 reply_nterror(req, status);
8128 goto out;
8131 DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
8132 " createtime=%u\n",
8133 fsp_fnum_dbg(fsp),
8134 (unsigned int)ft.atime.tv_sec,
8135 (unsigned int)ft.mtime.tv_sec,
8136 (unsigned int)ft.create_time.tv_sec
8138 out:
8139 END_PROFILE(SMBsetattrE);
8140 return;
8144 /* Back from the dead for OS/2..... JRA. */
8146 /****************************************************************************
8147 Reply to a SMBwritebmpx (write block multiplex primary) request.
8148 Always reply with an error, if someone has a platform really needs this,
8149 please contact vl@samba.org
8150 ****************************************************************************/
8152 void reply_writebmpx(struct smb_request *req)
8154 START_PROFILE(SMBwriteBmpx);
8155 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8156 END_PROFILE(SMBwriteBmpx);
8157 return;
8160 /****************************************************************************
8161 Reply to a SMBwritebs (write block multiplex secondary) request.
8162 Always reply with an error, if someone has a platform really needs this,
8163 please contact vl@samba.org
8164 ****************************************************************************/
8166 void reply_writebs(struct smb_request *req)
8168 START_PROFILE(SMBwriteBs);
8169 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8170 END_PROFILE(SMBwriteBs);
8171 return;
8174 /****************************************************************************
8175 Reply to a SMBgetattrE.
8176 ****************************************************************************/
8178 void reply_getattrE(struct smb_request *req)
8180 connection_struct *conn = req->conn;
8181 int mode;
8182 files_struct *fsp;
8183 struct timespec create_ts;
8185 START_PROFILE(SMBgetattrE);
8187 if (req->wct < 1) {
8188 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8189 END_PROFILE(SMBgetattrE);
8190 return;
8193 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8195 if(!fsp || (fsp->conn != conn)) {
8196 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8197 END_PROFILE(SMBgetattrE);
8198 return;
8201 /* Do an fstat on this file */
8202 if(fsp_stat(fsp)) {
8203 reply_nterror(req, map_nt_error_from_unix(errno));
8204 END_PROFILE(SMBgetattrE);
8205 return;
8208 mode = dos_mode(conn, fsp->fsp_name);
8211 * Convert the times into dos times. Set create
8212 * date to be last modify date as UNIX doesn't save
8213 * this.
8216 reply_outbuf(req, 11, 0);
8218 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
8219 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
8220 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
8221 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
8222 /* Should we check pending modtime here ? JRA */
8223 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
8224 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
8226 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
8227 SIVAL(req->outbuf, smb_vwv6, 0);
8228 SIVAL(req->outbuf, smb_vwv8, 0);
8229 } else {
8230 uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8231 SIVAL(req->outbuf, smb_vwv6, (uint32)fsp->fsp_name->st.st_ex_size);
8232 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8234 SSVAL(req->outbuf,smb_vwv10, mode);
8236 DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp)));
8238 END_PROFILE(SMBgetattrE);
8239 return;