smbd: fix creation of BUILTIN\{Administrators,Users} when "tdbsam:map builtin = false"
[Samba/wip.git] / source3 / smbd / reply.c
blobf737d7499afbf40a99cf15888f2cc9115722032e
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 ssize_t bufrem = smbreq_bufrem(req, src);
323 if (bufrem < 0) {
324 *err = NT_STATUS_INVALID_PARAMETER;
325 return 0;
328 return srvstr_get_path_wcard(mem_ctx, (const char *)req->inbuf,
329 req->flags2, pp_dest, src, bufrem, flags,
330 err, contains_wcard);
333 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
334 char **pp_dest, const char *src, int flags,
335 NTSTATUS *err)
337 bool ignore;
338 return srvstr_get_path_req_wcard(mem_ctx, req, pp_dest, src,
339 flags, err, &ignore);
343 * pull a string from the smb_buf part of a packet. In this case the
344 * string can either be null terminated or it can be terminated by the
345 * end of the smbbuf area
347 size_t srvstr_pull_req_talloc(TALLOC_CTX *ctx, struct smb_request *req,
348 char **dest, const uint8_t *src, int flags)
350 ssize_t bufrem = smbreq_bufrem(req, src);
352 if (bufrem < 0) {
353 return 0;
356 return pull_string_talloc(ctx, req->inbuf, req->flags2, dest, src,
357 bufrem, flags);
360 /****************************************************************************
361 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
362 ****************************************************************************/
364 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
365 files_struct *fsp)
367 if ((fsp == NULL) || (conn == NULL)) {
368 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
369 return False;
371 if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
372 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
373 return False;
375 return True;
378 /****************************************************************************
379 Check if we have a correct fsp pointing to a file.
380 ****************************************************************************/
382 bool check_fsp(connection_struct *conn, struct smb_request *req,
383 files_struct *fsp)
385 if (!check_fsp_open(conn, req, fsp)) {
386 return False;
388 if (fsp->is_directory) {
389 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
390 return False;
392 if (fsp->fh->fd == -1) {
393 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
394 return False;
396 fsp->num_smb_operations++;
397 return True;
400 /****************************************************************************
401 Check if we have a correct fsp pointing to a quota fake file. Replacement for
402 the CHECK_NTQUOTA_HANDLE_OK macro.
403 ****************************************************************************/
405 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
406 files_struct *fsp)
408 if (!check_fsp_open(conn, req, fsp)) {
409 return false;
412 if (fsp->is_directory) {
413 return false;
416 if (fsp->fake_file_handle == NULL) {
417 return false;
420 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
421 return false;
424 if (fsp->fake_file_handle->private_data == NULL) {
425 return false;
428 return true;
431 static bool netbios_session_retarget(struct smbd_server_connection *sconn,
432 const char *name, int name_type)
434 char *trim_name;
435 char *trim_name_type;
436 const char *retarget_parm;
437 char *retarget;
438 char *p;
439 int retarget_type = 0x20;
440 int retarget_port = NBT_SMB_PORT;
441 struct sockaddr_storage retarget_addr;
442 struct sockaddr_in *in_addr;
443 bool ret = false;
444 uint8_t outbuf[10];
446 if (get_socket_port(sconn->sock) != NBT_SMB_PORT) {
447 return false;
450 trim_name = talloc_strdup(talloc_tos(), name);
451 if (trim_name == NULL) {
452 goto fail;
454 trim_char(trim_name, ' ', ' ');
456 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
457 name_type);
458 if (trim_name_type == NULL) {
459 goto fail;
462 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
463 trim_name_type, NULL);
464 if (retarget_parm == NULL) {
465 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
466 trim_name, NULL);
468 if (retarget_parm == NULL) {
469 goto fail;
472 retarget = talloc_strdup(trim_name, retarget_parm);
473 if (retarget == NULL) {
474 goto fail;
477 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
479 p = strchr(retarget, ':');
480 if (p != NULL) {
481 *p++ = '\0';
482 retarget_port = atoi(p);
485 p = strchr_m(retarget, '#');
486 if (p != NULL) {
487 *p++ = '\0';
488 if (sscanf(p, "%x", &retarget_type) != 1) {
489 goto fail;
493 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
494 if (!ret) {
495 DEBUG(10, ("could not resolve %s\n", retarget));
496 goto fail;
499 if (retarget_addr.ss_family != AF_INET) {
500 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
501 goto fail;
504 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
506 _smb_setlen(outbuf, 6);
507 SCVAL(outbuf, 0, 0x84);
508 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
509 *(uint16_t *)(outbuf+8) = htons(retarget_port);
511 if (!srv_send_smb(sconn, (char *)outbuf, false, 0, false,
512 NULL)) {
513 exit_server_cleanly("netbios_session_retarget: srv_send_smb "
514 "failed.");
517 ret = true;
518 fail:
519 TALLOC_FREE(trim_name);
520 return ret;
523 static void reply_called_name_not_present(char *outbuf)
525 smb_setlen(outbuf, 1);
526 SCVAL(outbuf, 0, 0x83);
527 SCVAL(outbuf, 4, 0x82);
530 /****************************************************************************
531 Reply to a (netbios-level) special message.
532 ****************************************************************************/
534 void reply_special(struct smbd_server_connection *sconn, char *inbuf, size_t inbuf_size)
536 int msg_type = CVAL(inbuf,0);
537 int msg_flags = CVAL(inbuf,1);
539 * We only really use 4 bytes of the outbuf, but for the smb_setlen
540 * calculation & friends (srv_send_smb uses that) we need the full smb
541 * header.
543 char outbuf[smb_size];
545 memset(outbuf, '\0', sizeof(outbuf));
547 smb_setlen(outbuf,0);
549 switch (msg_type) {
550 case NBSSrequest: /* session request */
552 /* inbuf_size is guarenteed to be at least 4. */
553 fstring name1,name2;
554 int name_type1, name_type2;
555 int name_len1, name_len2;
557 *name1 = *name2 = 0;
559 if (sconn->nbt.got_session) {
560 exit_server_cleanly("multiple session request not permitted");
563 SCVAL(outbuf,0,NBSSpositive);
564 SCVAL(outbuf,3,0);
566 /* inbuf_size is guaranteed to be at least 4. */
567 name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
568 if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
569 DEBUG(0,("Invalid name length in session request\n"));
570 reply_called_name_not_present(outbuf);
571 break;
573 name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
574 if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
575 DEBUG(0,("Invalid name length in session request\n"));
576 reply_called_name_not_present(outbuf);
577 break;
580 name_type1 = name_extract((unsigned char *)inbuf,
581 inbuf_size,(unsigned int)4,name1);
582 name_type2 = name_extract((unsigned char *)inbuf,
583 inbuf_size,(unsigned int)(4 + name_len1),name2);
585 if (name_type1 == -1 || name_type2 == -1) {
586 DEBUG(0,("Invalid name type in session request\n"));
587 reply_called_name_not_present(outbuf);
588 break;
591 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
592 name1, name_type1, name2, name_type2));
594 if (netbios_session_retarget(sconn, name1, name_type1)) {
595 exit_server_cleanly("retargeted client");
599 * Windows NT/2k uses "*SMBSERVER" and XP uses
600 * "*SMBSERV" arrggg!!!
602 if (strequal(name1, "*SMBSERVER ")
603 || strequal(name1, "*SMBSERV ")) {
604 char *raddr;
606 raddr = tsocket_address_inet_addr_string(sconn->remote_address,
607 talloc_tos());
608 if (raddr == NULL) {
609 exit_server_cleanly("could not allocate raddr");
612 fstrcpy(name1, raddr);
615 set_local_machine_name(name1, True);
616 set_remote_machine_name(name2, True);
618 if (is_ipaddress(sconn->remote_hostname)) {
619 char *p = discard_const_p(char, sconn->remote_hostname);
621 talloc_free(p);
623 sconn->remote_hostname = talloc_strdup(sconn,
624 get_remote_machine_name());
625 if (sconn->remote_hostname == NULL) {
626 exit_server_cleanly("could not copy remote name");
628 sconn->conn->remote_hostname = sconn->remote_hostname;
631 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
632 get_local_machine_name(), get_remote_machine_name(),
633 name_type2));
635 if (name_type2 == 'R') {
636 /* We are being asked for a pathworks session ---
637 no thanks! */
638 reply_called_name_not_present(outbuf);
639 break;
642 reload_services(sconn, conn_snum_used, true);
643 reopen_logs();
645 sconn->nbt.got_session = true;
646 break;
649 case 0x89: /* session keepalive request
650 (some old clients produce this?) */
651 SCVAL(outbuf,0,NBSSkeepalive);
652 SCVAL(outbuf,3,0);
653 break;
655 case NBSSpositive: /* positive session response */
656 case NBSSnegative: /* negative session response */
657 case NBSSretarget: /* retarget session response */
658 DEBUG(0,("Unexpected session response\n"));
659 break;
661 case NBSSkeepalive: /* session keepalive */
662 default:
663 return;
666 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
667 msg_type, msg_flags));
669 srv_send_smb(sconn, outbuf, false, 0, false, NULL);
671 if (CVAL(outbuf, 0) != 0x82) {
672 exit_server_cleanly("invalid netbios session");
674 return;
677 /****************************************************************************
678 Reply to a tcon.
679 conn POINTER CAN BE NULL HERE !
680 ****************************************************************************/
682 void reply_tcon(struct smb_request *req)
684 connection_struct *conn = req->conn;
685 const char *service;
686 char *service_buf = NULL;
687 char *password = NULL;
688 char *dev = NULL;
689 int pwlen=0;
690 NTSTATUS nt_status;
691 const uint8_t *p;
692 const char *p2;
693 TALLOC_CTX *ctx = talloc_tos();
694 struct smbd_server_connection *sconn = req->sconn;
695 NTTIME now = timeval_to_nttime(&req->request_time);
697 START_PROFILE(SMBtcon);
699 if (req->buflen < 4) {
700 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
701 END_PROFILE(SMBtcon);
702 return;
705 p = req->buf + 1;
706 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
707 p += 1;
708 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
709 p += pwlen+1;
710 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
711 p += 1;
713 if (service_buf == NULL || password == NULL || dev == NULL) {
714 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
715 END_PROFILE(SMBtcon);
716 return;
718 p2 = strrchr_m(service_buf,'\\');
719 if (p2) {
720 service = p2+1;
721 } else {
722 service = service_buf;
725 conn = make_connection(sconn, now, service, dev,
726 req->vuid,&nt_status);
727 req->conn = conn;
729 if (!conn) {
730 reply_nterror(req, nt_status);
731 END_PROFILE(SMBtcon);
732 return;
735 reply_outbuf(req, 2, 0);
736 SSVAL(req->outbuf,smb_vwv0,sconn->smb1.negprot.max_recv);
737 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
738 SSVAL(req->outbuf,smb_tid,conn->cnum);
740 DEBUG(3,("tcon service=%s cnum=%d\n",
741 service, conn->cnum));
743 END_PROFILE(SMBtcon);
744 return;
747 /****************************************************************************
748 Reply to a tcon and X.
749 conn POINTER CAN BE NULL HERE !
750 ****************************************************************************/
752 void reply_tcon_and_X(struct smb_request *req)
754 connection_struct *conn = req->conn;
755 const char *service = NULL;
756 TALLOC_CTX *ctx = talloc_tos();
757 /* what the cleint thinks the device is */
758 char *client_devicetype = NULL;
759 /* what the server tells the client the share represents */
760 const char *server_devicetype;
761 NTSTATUS nt_status;
762 int passlen;
763 char *path = NULL;
764 const uint8_t *p;
765 const char *q;
766 uint16_t tcon_flags;
767 struct smbXsrv_session *session = NULL;
768 NTTIME now = timeval_to_nttime(&req->request_time);
769 bool session_key_updated = false;
770 uint16_t optional_support = 0;
771 struct smbd_server_connection *sconn = req->sconn;
773 START_PROFILE(SMBtconX);
775 if (req->wct < 4) {
776 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
777 END_PROFILE(SMBtconX);
778 return;
781 passlen = SVAL(req->vwv+3, 0);
782 tcon_flags = SVAL(req->vwv+2, 0);
784 /* we might have to close an old one */
785 if ((tcon_flags & TCONX_FLAG_DISCONNECT_TID) && conn) {
786 struct smbXsrv_tcon *tcon;
787 NTSTATUS status;
789 tcon = conn->tcon;
790 req->conn = NULL;
791 conn = NULL;
794 * TODO: cancel all outstanding requests on the tcon
796 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
797 if (!NT_STATUS_IS_OK(status)) {
798 DEBUG(0, ("reply_tcon_and_X: "
799 "smbXsrv_tcon_disconnect() failed: %s\n",
800 nt_errstr(status)));
802 * If we hit this case, there is something completely
803 * wrong, so we better disconnect the transport connection.
805 END_PROFILE(SMBtconX);
806 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
807 return;
810 TALLOC_FREE(tcon);
813 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
814 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
815 END_PROFILE(SMBtconX);
816 return;
819 if (sconn->smb1.negprot.encrypted_passwords) {
820 p = req->buf + passlen;
821 } else {
822 p = req->buf + passlen + 1;
825 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
827 if (path == NULL) {
828 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
829 END_PROFILE(SMBtconX);
830 return;
834 * the service name can be either: \\server\share
835 * or share directly like on the DELL PowerVault 705
837 if (*path=='\\') {
838 q = strchr_m(path+2,'\\');
839 if (!q) {
840 reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
841 END_PROFILE(SMBtconX);
842 return;
844 service = q+1;
845 } else {
846 service = path;
849 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
850 &client_devicetype, p,
851 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
853 if (client_devicetype == NULL) {
854 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
855 END_PROFILE(SMBtconX);
856 return;
859 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
861 nt_status = smb1srv_session_lookup(req->sconn->conn,
862 req->vuid, now, &session);
863 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_USER_SESSION_DELETED)) {
864 reply_force_doserror(req, ERRSRV, ERRbaduid);
865 END_PROFILE(SMBtconX);
866 return;
868 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
869 reply_nterror(req, nt_status);
870 END_PROFILE(SMBtconX);
871 return;
873 if (!NT_STATUS_IS_OK(nt_status)) {
874 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
875 END_PROFILE(SMBtconX);
876 return;
879 if (session->global->auth_session_info == NULL) {
880 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
881 END_PROFILE(SMBtconX);
882 return;
886 * If there is no application key defined yet
887 * we create one.
889 * This means we setup the application key on the
890 * first tcon that happens via the given session.
892 * Once the application key is defined, it does not
893 * change any more.
895 if (session->global->application_key.length == 0 &&
896 session->global->signing_key.length > 0)
898 struct smbXsrv_session *x = session;
899 struct auth_session_info *session_info =
900 session->global->auth_session_info;
901 uint8_t session_key[16];
903 ZERO_STRUCT(session_key);
904 memcpy(session_key, x->global->signing_key.data,
905 MIN(x->global->signing_key.length, sizeof(session_key)));
908 * The application key is truncated/padded to 16 bytes
910 x->global->application_key = data_blob_talloc(x->global,
911 session_key,
912 sizeof(session_key));
913 ZERO_STRUCT(session_key);
914 if (x->global->application_key.data == NULL) {
915 reply_nterror(req, NT_STATUS_NO_MEMORY);
916 END_PROFILE(SMBtconX);
917 return;
920 if (tcon_flags & TCONX_FLAG_EXTENDED_SIGNATURES) {
921 smb_key_derivation(x->global->application_key.data,
922 x->global->application_key.length,
923 x->global->application_key.data);
924 optional_support |= SMB_EXTENDED_SIGNATURES;
928 * Place the application key into the session_info
930 data_blob_clear_free(&session_info->session_key);
931 session_info->session_key = data_blob_dup_talloc(session_info,
932 x->global->application_key);
933 if (session_info->session_key.data == NULL) {
934 data_blob_clear_free(&x->global->application_key);
935 reply_nterror(req, NT_STATUS_NO_MEMORY);
936 END_PROFILE(SMBtconX);
937 return;
939 session_key_updated = true;
942 conn = make_connection(sconn, now, service, client_devicetype,
943 req->vuid, &nt_status);
944 req->conn =conn;
946 if (!conn) {
947 if (session_key_updated) {
948 struct smbXsrv_session *x = session;
949 struct auth_session_info *session_info =
950 session->global->auth_session_info;
951 data_blob_clear_free(&x->global->application_key);
952 data_blob_clear_free(&session_info->session_key);
954 reply_nterror(req, nt_status);
955 END_PROFILE(SMBtconX);
956 return;
959 if ( IS_IPC(conn) )
960 server_devicetype = "IPC";
961 else if ( IS_PRINT(conn) )
962 server_devicetype = "LPT1:";
963 else
964 server_devicetype = "A:";
966 if (get_Protocol() < PROTOCOL_NT1) {
967 reply_outbuf(req, 2, 0);
968 if (message_push_string(&req->outbuf, server_devicetype,
969 STR_TERMINATE|STR_ASCII) == -1) {
970 reply_nterror(req, NT_STATUS_NO_MEMORY);
971 END_PROFILE(SMBtconX);
972 return;
974 } else {
975 /* NT sets the fstype of IPC$ to the null string */
976 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
978 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
979 /* Return permissions. */
980 uint32 perm1 = 0;
981 uint32 perm2 = 0;
983 reply_outbuf(req, 7, 0);
985 if (IS_IPC(conn)) {
986 perm1 = FILE_ALL_ACCESS;
987 perm2 = FILE_ALL_ACCESS;
988 } else {
989 perm1 = conn->share_access;
992 SIVAL(req->outbuf, smb_vwv3, perm1);
993 SIVAL(req->outbuf, smb_vwv5, perm2);
994 } else {
995 reply_outbuf(req, 3, 0);
998 if ((message_push_string(&req->outbuf, server_devicetype,
999 STR_TERMINATE|STR_ASCII) == -1)
1000 || (message_push_string(&req->outbuf, fstype,
1001 STR_TERMINATE) == -1)) {
1002 reply_nterror(req, NT_STATUS_NO_MEMORY);
1003 END_PROFILE(SMBtconX);
1004 return;
1007 /* what does setting this bit do? It is set by NT4 and
1008 may affect the ability to autorun mounted cdroms */
1009 optional_support |= SMB_SUPPORT_SEARCH_BITS;
1010 optional_support |=
1011 (lp_csc_policy(SNUM(conn)) << SMB_CSC_POLICY_SHIFT);
1013 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
1014 DEBUG(2,("Serving %s as a Dfs root\n",
1015 lp_servicename(ctx, SNUM(conn)) ));
1016 optional_support |= SMB_SHARE_IN_DFS;
1019 SSVAL(req->outbuf, smb_vwv2, optional_support);
1022 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
1023 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
1025 DEBUG(3,("tconX service=%s \n",
1026 service));
1028 /* set the incoming and outgoing tid to the just created one */
1029 SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
1030 SSVAL(req->outbuf,smb_tid,conn->cnum);
1032 END_PROFILE(SMBtconX);
1034 req->tid = conn->cnum;
1037 /****************************************************************************
1038 Reply to an unknown type.
1039 ****************************************************************************/
1041 void reply_unknown_new(struct smb_request *req, uint8 type)
1043 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
1044 smb_fn_name(type), type, type));
1045 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
1046 return;
1049 /****************************************************************************
1050 Reply to an ioctl.
1051 conn POINTER CAN BE NULL HERE !
1052 ****************************************************************************/
1054 void reply_ioctl(struct smb_request *req)
1056 connection_struct *conn = req->conn;
1057 uint16 device;
1058 uint16 function;
1059 uint32 ioctl_code;
1060 int replysize;
1061 char *p;
1063 START_PROFILE(SMBioctl);
1065 if (req->wct < 3) {
1066 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1067 END_PROFILE(SMBioctl);
1068 return;
1071 device = SVAL(req->vwv+1, 0);
1072 function = SVAL(req->vwv+2, 0);
1073 ioctl_code = (device << 16) + function;
1075 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
1077 switch (ioctl_code) {
1078 case IOCTL_QUERY_JOB_INFO:
1079 replysize = 32;
1080 break;
1081 default:
1082 reply_force_doserror(req, ERRSRV, ERRnosupport);
1083 END_PROFILE(SMBioctl);
1084 return;
1087 reply_outbuf(req, 8, replysize+1);
1088 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
1089 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
1090 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
1091 p = smb_buf(req->outbuf);
1092 memset(p, '\0', replysize+1); /* valgrind-safe. */
1093 p += 1; /* Allow for alignment */
1095 switch (ioctl_code) {
1096 case IOCTL_QUERY_JOB_INFO:
1098 files_struct *fsp = file_fsp(
1099 req, SVAL(req->vwv+0, 0));
1100 if (!fsp) {
1101 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
1102 END_PROFILE(SMBioctl);
1103 return;
1105 /* Job number */
1106 SSVAL(p, 0, print_spool_rap_jobid(fsp->print_file));
1108 srvstr_push((char *)req->outbuf, req->flags2, p+2,
1109 lp_netbios_name(), 15,
1110 STR_TERMINATE|STR_ASCII);
1111 if (conn) {
1112 srvstr_push((char *)req->outbuf, req->flags2,
1113 p+18,
1114 lp_servicename(talloc_tos(),
1115 SNUM(conn)),
1116 13, STR_TERMINATE|STR_ASCII);
1117 } else {
1118 memset(p+18, 0, 13);
1120 break;
1124 END_PROFILE(SMBioctl);
1125 return;
1128 /****************************************************************************
1129 Strange checkpath NTSTATUS mapping.
1130 ****************************************************************************/
1132 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
1134 /* Strange DOS error code semantics only for checkpath... */
1135 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
1136 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
1137 /* We need to map to ERRbadpath */
1138 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1141 return status;
1144 /****************************************************************************
1145 Reply to a checkpath.
1146 ****************************************************************************/
1148 void reply_checkpath(struct smb_request *req)
1150 connection_struct *conn = req->conn;
1151 struct smb_filename *smb_fname = NULL;
1152 char *name = NULL;
1153 NTSTATUS status;
1154 TALLOC_CTX *ctx = talloc_tos();
1156 START_PROFILE(SMBcheckpath);
1158 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
1159 STR_TERMINATE, &status);
1161 if (!NT_STATUS_IS_OK(status)) {
1162 status = map_checkpath_error(req->flags2, status);
1163 reply_nterror(req, status);
1164 END_PROFILE(SMBcheckpath);
1165 return;
1168 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1170 status = filename_convert(ctx,
1171 conn,
1172 req->flags2 & FLAGS2_DFS_PATHNAMES,
1173 name,
1175 NULL,
1176 &smb_fname);
1178 if (!NT_STATUS_IS_OK(status)) {
1179 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1180 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1181 ERRSRV, ERRbadpath);
1182 END_PROFILE(SMBcheckpath);
1183 return;
1185 goto path_err;
1188 if (!VALID_STAT(smb_fname->st) &&
1189 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1190 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1191 smb_fname_str_dbg(smb_fname), strerror(errno)));
1192 status = map_nt_error_from_unix(errno);
1193 goto path_err;
1196 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1197 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1198 ERRDOS, ERRbadpath);
1199 goto out;
1202 reply_outbuf(req, 0, 0);
1204 path_err:
1205 /* We special case this - as when a Windows machine
1206 is parsing a path is steps through the components
1207 one at a time - if a component fails it expects
1208 ERRbadpath, not ERRbadfile.
1210 status = map_checkpath_error(req->flags2, status);
1211 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1213 * Windows returns different error codes if
1214 * the parent directory is valid but not the
1215 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1216 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1217 * if the path is invalid.
1219 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1220 ERRDOS, ERRbadpath);
1221 goto out;
1224 reply_nterror(req, status);
1226 out:
1227 TALLOC_FREE(smb_fname);
1228 END_PROFILE(SMBcheckpath);
1229 return;
1232 /****************************************************************************
1233 Reply to a getatr.
1234 ****************************************************************************/
1236 void reply_getatr(struct smb_request *req)
1238 connection_struct *conn = req->conn;
1239 struct smb_filename *smb_fname = NULL;
1240 char *fname = NULL;
1241 int mode=0;
1242 off_t size=0;
1243 time_t mtime=0;
1244 const char *p;
1245 NTSTATUS status;
1246 TALLOC_CTX *ctx = talloc_tos();
1247 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1249 START_PROFILE(SMBgetatr);
1251 p = (const char *)req->buf + 1;
1252 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1253 if (!NT_STATUS_IS_OK(status)) {
1254 reply_nterror(req, status);
1255 goto out;
1258 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1259 under WfWg - weird! */
1260 if (*fname == '\0') {
1261 mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1262 if (!CAN_WRITE(conn)) {
1263 mode |= FILE_ATTRIBUTE_READONLY;
1265 size = 0;
1266 mtime = 0;
1267 } else {
1268 status = filename_convert(ctx,
1269 conn,
1270 req->flags2 & FLAGS2_DFS_PATHNAMES,
1271 fname,
1273 NULL,
1274 &smb_fname);
1275 if (!NT_STATUS_IS_OK(status)) {
1276 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1277 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1278 ERRSRV, ERRbadpath);
1279 goto out;
1281 reply_nterror(req, status);
1282 goto out;
1284 if (!VALID_STAT(smb_fname->st) &&
1285 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1286 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1287 smb_fname_str_dbg(smb_fname),
1288 strerror(errno)));
1289 reply_nterror(req, map_nt_error_from_unix(errno));
1290 goto out;
1293 mode = dos_mode(conn, smb_fname);
1294 size = smb_fname->st.st_ex_size;
1296 if (ask_sharemode) {
1297 struct timespec write_time_ts;
1298 struct file_id fileid;
1300 ZERO_STRUCT(write_time_ts);
1301 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1302 get_file_infos(fileid, 0, NULL, &write_time_ts);
1303 if (!null_timespec(write_time_ts)) {
1304 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1308 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1309 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1310 size = 0;
1314 reply_outbuf(req, 10, 0);
1316 SSVAL(req->outbuf,smb_vwv0,mode);
1317 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1318 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1319 } else {
1320 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1322 SIVAL(req->outbuf,smb_vwv3,(uint32)size);
1324 if (get_Protocol() >= PROTOCOL_NT1) {
1325 SSVAL(req->outbuf, smb_flg2,
1326 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1329 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1330 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1332 out:
1333 TALLOC_FREE(smb_fname);
1334 TALLOC_FREE(fname);
1335 END_PROFILE(SMBgetatr);
1336 return;
1339 /****************************************************************************
1340 Reply to a setatr.
1341 ****************************************************************************/
1343 void reply_setatr(struct smb_request *req)
1345 struct smb_file_time ft;
1346 connection_struct *conn = req->conn;
1347 struct smb_filename *smb_fname = NULL;
1348 char *fname = NULL;
1349 int mode;
1350 time_t mtime;
1351 const char *p;
1352 NTSTATUS status;
1353 TALLOC_CTX *ctx = talloc_tos();
1355 START_PROFILE(SMBsetatr);
1357 ZERO_STRUCT(ft);
1359 if (req->wct < 2) {
1360 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1361 goto out;
1364 p = (const char *)req->buf + 1;
1365 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1366 if (!NT_STATUS_IS_OK(status)) {
1367 reply_nterror(req, status);
1368 goto out;
1371 status = filename_convert(ctx,
1372 conn,
1373 req->flags2 & FLAGS2_DFS_PATHNAMES,
1374 fname,
1376 NULL,
1377 &smb_fname);
1378 if (!NT_STATUS_IS_OK(status)) {
1379 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1380 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1381 ERRSRV, ERRbadpath);
1382 goto out;
1384 reply_nterror(req, status);
1385 goto out;
1388 if (smb_fname->base_name[0] == '.' &&
1389 smb_fname->base_name[1] == '\0') {
1391 * Not sure here is the right place to catch this
1392 * condition. Might be moved to somewhere else later -- vl
1394 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1395 goto out;
1398 mode = SVAL(req->vwv+0, 0);
1399 mtime = srv_make_unix_date3(req->vwv+1);
1401 if (mode != FILE_ATTRIBUTE_NORMAL) {
1402 if (VALID_STAT_OF_DIR(smb_fname->st))
1403 mode |= FILE_ATTRIBUTE_DIRECTORY;
1404 else
1405 mode &= ~FILE_ATTRIBUTE_DIRECTORY;
1407 status = check_access(conn, NULL, smb_fname,
1408 FILE_WRITE_ATTRIBUTES);
1409 if (!NT_STATUS_IS_OK(status)) {
1410 reply_nterror(req, status);
1411 goto out;
1414 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1415 false) != 0) {
1416 reply_nterror(req, map_nt_error_from_unix(errno));
1417 goto out;
1421 ft.mtime = convert_time_t_to_timespec(mtime);
1422 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1423 if (!NT_STATUS_IS_OK(status)) {
1424 reply_nterror(req, status);
1425 goto out;
1428 reply_outbuf(req, 0, 0);
1430 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1431 mode));
1432 out:
1433 TALLOC_FREE(smb_fname);
1434 END_PROFILE(SMBsetatr);
1435 return;
1438 /****************************************************************************
1439 Reply to a dskattr.
1440 ****************************************************************************/
1442 void reply_dskattr(struct smb_request *req)
1444 connection_struct *conn = req->conn;
1445 uint64_t dfree,dsize,bsize;
1446 START_PROFILE(SMBdskattr);
1448 if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (uint64_t)-1) {
1449 reply_nterror(req, map_nt_error_from_unix(errno));
1450 END_PROFILE(SMBdskattr);
1451 return;
1454 reply_outbuf(req, 5, 0);
1456 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1457 double total_space, free_space;
1458 /* we need to scale this to a number that DOS6 can handle. We
1459 use floating point so we can handle large drives on systems
1460 that don't have 64 bit integers
1462 we end up displaying a maximum of 2G to DOS systems
1464 total_space = dsize * (double)bsize;
1465 free_space = dfree * (double)bsize;
1467 dsize = (uint64_t)((total_space+63*512) / (64*512));
1468 dfree = (uint64_t)((free_space+63*512) / (64*512));
1470 if (dsize > 0xFFFF) dsize = 0xFFFF;
1471 if (dfree > 0xFFFF) dfree = 0xFFFF;
1473 SSVAL(req->outbuf,smb_vwv0,dsize);
1474 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1475 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1476 SSVAL(req->outbuf,smb_vwv3,dfree);
1477 } else {
1478 SSVAL(req->outbuf,smb_vwv0,dsize);
1479 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1480 SSVAL(req->outbuf,smb_vwv2,512);
1481 SSVAL(req->outbuf,smb_vwv3,dfree);
1484 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1486 END_PROFILE(SMBdskattr);
1487 return;
1491 * Utility function to split the filename from the directory.
1493 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1494 char **fname_dir_out,
1495 char **fname_mask_out)
1497 const char *p = NULL;
1498 char *fname_dir = NULL;
1499 char *fname_mask = NULL;
1501 p = strrchr_m(fname_in, '/');
1502 if (!p) {
1503 fname_dir = talloc_strdup(ctx, ".");
1504 fname_mask = talloc_strdup(ctx, fname_in);
1505 } else {
1506 fname_dir = talloc_strndup(ctx, fname_in,
1507 PTR_DIFF(p, fname_in));
1508 fname_mask = talloc_strdup(ctx, p+1);
1511 if (!fname_dir || !fname_mask) {
1512 TALLOC_FREE(fname_dir);
1513 TALLOC_FREE(fname_mask);
1514 return NT_STATUS_NO_MEMORY;
1517 *fname_dir_out = fname_dir;
1518 *fname_mask_out = fname_mask;
1519 return NT_STATUS_OK;
1522 /****************************************************************************
1523 Reply to a search.
1524 Can be called from SMBsearch, SMBffirst or SMBfunique.
1525 ****************************************************************************/
1527 void reply_search(struct smb_request *req)
1529 connection_struct *conn = req->conn;
1530 char *path = NULL;
1531 const char *mask = NULL;
1532 char *directory = NULL;
1533 struct smb_filename *smb_fname = NULL;
1534 char *fname = NULL;
1535 off_t size;
1536 uint32 mode;
1537 struct timespec date;
1538 uint32 dirtype;
1539 unsigned int numentries = 0;
1540 unsigned int maxentries = 0;
1541 bool finished = False;
1542 const char *p;
1543 int status_len;
1544 char status[21];
1545 int dptr_num= -1;
1546 bool check_descend = False;
1547 bool expect_close = False;
1548 NTSTATUS nt_status;
1549 bool mask_contains_wcard = False;
1550 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1551 TALLOC_CTX *ctx = talloc_tos();
1552 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1553 struct dptr_struct *dirptr = NULL;
1554 struct smbd_server_connection *sconn = req->sconn;
1556 START_PROFILE(SMBsearch);
1558 if (req->wct < 2) {
1559 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1560 goto out;
1563 if (lp_posix_pathnames()) {
1564 reply_unknown_new(req, req->cmd);
1565 goto out;
1568 /* If we were called as SMBffirst then we must expect close. */
1569 if(req->cmd == SMBffirst) {
1570 expect_close = True;
1573 reply_outbuf(req, 1, 3);
1574 maxentries = SVAL(req->vwv+0, 0);
1575 dirtype = SVAL(req->vwv+1, 0);
1576 p = (const char *)req->buf + 1;
1577 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1578 &nt_status, &mask_contains_wcard);
1579 if (!NT_STATUS_IS_OK(nt_status)) {
1580 reply_nterror(req, nt_status);
1581 goto out;
1584 p++;
1585 status_len = SVAL(p, 0);
1586 p += 2;
1588 /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1590 if (status_len == 0) {
1591 nt_status = filename_convert(ctx, conn,
1592 req->flags2 & FLAGS2_DFS_PATHNAMES,
1593 path,
1594 UCF_ALWAYS_ALLOW_WCARD_LCOMP,
1595 &mask_contains_wcard,
1596 &smb_fname);
1597 if (!NT_STATUS_IS_OK(nt_status)) {
1598 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1599 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1600 ERRSRV, ERRbadpath);
1601 goto out;
1603 reply_nterror(req, nt_status);
1604 goto out;
1607 directory = smb_fname->base_name;
1609 p = strrchr_m(directory,'/');
1610 if ((p != NULL) && (*directory != '/')) {
1611 mask = p + 1;
1612 directory = talloc_strndup(ctx, directory,
1613 PTR_DIFF(p, directory));
1614 } else {
1615 mask = directory;
1616 directory = talloc_strdup(ctx,".");
1619 if (!directory) {
1620 reply_nterror(req, NT_STATUS_NO_MEMORY);
1621 goto out;
1624 memset((char *)status,'\0',21);
1625 SCVAL(status,0,(dirtype & 0x1F));
1627 nt_status = dptr_create(conn,
1628 NULL, /* req */
1629 NULL, /* fsp */
1630 directory,
1631 True,
1632 expect_close,
1633 req->smbpid,
1634 mask,
1635 mask_contains_wcard,
1636 dirtype,
1637 &dirptr);
1638 if (!NT_STATUS_IS_OK(nt_status)) {
1639 reply_nterror(req, nt_status);
1640 goto out;
1642 dptr_num = dptr_dnum(dirptr);
1643 } else {
1644 int status_dirtype;
1645 const char *dirpath;
1647 memcpy(status,p,21);
1648 status_dirtype = CVAL(status,0) & 0x1F;
1649 if (status_dirtype != (dirtype & 0x1F)) {
1650 dirtype = status_dirtype;
1653 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1654 if (!dirptr) {
1655 goto SearchEmpty;
1657 dirpath = dptr_path(sconn, dptr_num);
1658 directory = talloc_strdup(ctx, dirpath);
1659 if (!directory) {
1660 reply_nterror(req, NT_STATUS_NO_MEMORY);
1661 goto out;
1664 mask = dptr_wcard(sconn, dptr_num);
1665 if (!mask) {
1666 goto SearchEmpty;
1669 * For a 'continue' search we have no string. So
1670 * check from the initial saved string.
1672 mask_contains_wcard = ms_has_wild(mask);
1673 dirtype = dptr_attr(sconn, dptr_num);
1676 DEBUG(4,("dptr_num is %d\n",dptr_num));
1678 /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
1679 dptr_init_search_op(dirptr);
1681 if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1682 char buf[DIR_STRUCT_SIZE];
1683 memcpy(buf,status,21);
1684 if (!make_dir_struct(ctx,buf,"???????????",volume_label(ctx, SNUM(conn)),
1685 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1686 reply_nterror(req, NT_STATUS_NO_MEMORY);
1687 goto out;
1689 dptr_fill(sconn, buf+12,dptr_num);
1690 if (dptr_zero(buf+12) && (status_len==0)) {
1691 numentries = 1;
1692 } else {
1693 numentries = 0;
1695 if (message_push_blob(&req->outbuf,
1696 data_blob_const(buf, sizeof(buf)))
1697 == -1) {
1698 reply_nterror(req, NT_STATUS_NO_MEMORY);
1699 goto out;
1701 } else {
1702 unsigned int i;
1703 size_t hdr_size = ((uint8_t *)smb_buf(req->outbuf) + 3 - req->outbuf);
1704 size_t available_space = sconn->smb1.sessions.max_send - hdr_size;
1706 maxentries = MIN(maxentries, available_space/DIR_STRUCT_SIZE);
1708 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1709 directory,lp_dont_descend(ctx, SNUM(conn))));
1710 if (in_list(directory, lp_dont_descend(ctx, SNUM(conn)),True)) {
1711 check_descend = True;
1714 for (i=numentries;(i<maxentries) && !finished;i++) {
1715 finished = !get_dir_entry(ctx,
1716 dirptr,
1717 mask,
1718 dirtype,
1719 &fname,
1720 &size,
1721 &mode,
1722 &date,
1723 check_descend,
1724 ask_sharemode);
1725 if (!finished) {
1726 char buf[DIR_STRUCT_SIZE];
1727 memcpy(buf,status,21);
1728 if (!make_dir_struct(ctx,
1729 buf,
1730 mask,
1731 fname,
1732 size,
1733 mode,
1734 convert_timespec_to_time_t(date),
1735 !allow_long_path_components)) {
1736 reply_nterror(req, NT_STATUS_NO_MEMORY);
1737 goto out;
1739 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1740 break;
1742 if (message_push_blob(&req->outbuf,
1743 data_blob_const(buf, sizeof(buf)))
1744 == -1) {
1745 reply_nterror(req, NT_STATUS_NO_MEMORY);
1746 goto out;
1748 numentries++;
1753 SearchEmpty:
1755 /* If we were called as SMBffirst with smb_search_id == NULL
1756 and no entries were found then return error and close dirptr
1757 (X/Open spec) */
1759 if (numentries == 0) {
1760 dptr_close(sconn, &dptr_num);
1761 } else if(expect_close && status_len == 0) {
1762 /* Close the dptr - we know it's gone */
1763 dptr_close(sconn, &dptr_num);
1766 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1767 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1768 dptr_close(sconn, &dptr_num);
1771 if ((numentries == 0) && !mask_contains_wcard) {
1772 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1773 goto out;
1776 SSVAL(req->outbuf,smb_vwv0,numentries);
1777 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1778 SCVAL(smb_buf(req->outbuf),0,5);
1779 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1781 /* The replies here are never long name. */
1782 SSVAL(req->outbuf, smb_flg2,
1783 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1784 if (!allow_long_path_components) {
1785 SSVAL(req->outbuf, smb_flg2,
1786 SVAL(req->outbuf, smb_flg2)
1787 & (~FLAGS2_LONG_PATH_COMPONENTS));
1790 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
1791 SSVAL(req->outbuf, smb_flg2,
1792 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
1794 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
1795 smb_fn_name(req->cmd),
1796 mask,
1797 directory,
1798 dirtype,
1799 numentries,
1800 maxentries ));
1801 out:
1802 TALLOC_FREE(directory);
1803 TALLOC_FREE(smb_fname);
1804 END_PROFILE(SMBsearch);
1805 return;
1808 /****************************************************************************
1809 Reply to a fclose (stop directory search).
1810 ****************************************************************************/
1812 void reply_fclose(struct smb_request *req)
1814 int status_len;
1815 char status[21];
1816 int dptr_num= -2;
1817 const char *p;
1818 char *path = NULL;
1819 NTSTATUS err;
1820 bool path_contains_wcard = False;
1821 TALLOC_CTX *ctx = talloc_tos();
1822 struct smbd_server_connection *sconn = req->sconn;
1824 START_PROFILE(SMBfclose);
1826 if (lp_posix_pathnames()) {
1827 reply_unknown_new(req, req->cmd);
1828 END_PROFILE(SMBfclose);
1829 return;
1832 p = (const char *)req->buf + 1;
1833 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1834 &err, &path_contains_wcard);
1835 if (!NT_STATUS_IS_OK(err)) {
1836 reply_nterror(req, err);
1837 END_PROFILE(SMBfclose);
1838 return;
1840 p++;
1841 status_len = SVAL(p,0);
1842 p += 2;
1844 if (status_len == 0) {
1845 reply_force_doserror(req, ERRSRV, ERRsrverror);
1846 END_PROFILE(SMBfclose);
1847 return;
1850 memcpy(status,p,21);
1852 if(dptr_fetch(sconn, status+12,&dptr_num)) {
1853 /* Close the dptr - we know it's gone */
1854 dptr_close(sconn, &dptr_num);
1857 reply_outbuf(req, 1, 0);
1858 SSVAL(req->outbuf,smb_vwv0,0);
1860 DEBUG(3,("search close\n"));
1862 END_PROFILE(SMBfclose);
1863 return;
1866 /****************************************************************************
1867 Reply to an open.
1868 ****************************************************************************/
1870 void reply_open(struct smb_request *req)
1872 connection_struct *conn = req->conn;
1873 struct smb_filename *smb_fname = NULL;
1874 char *fname = NULL;
1875 uint32 fattr=0;
1876 off_t size = 0;
1877 time_t mtime=0;
1878 int info;
1879 files_struct *fsp;
1880 int oplock_request;
1881 int deny_mode;
1882 uint32 dos_attr;
1883 uint32 access_mask;
1884 uint32 share_mode;
1885 uint32 create_disposition;
1886 uint32 create_options = 0;
1887 uint32_t private_flags = 0;
1888 NTSTATUS status;
1889 TALLOC_CTX *ctx = talloc_tos();
1891 START_PROFILE(SMBopen);
1893 if (req->wct < 2) {
1894 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1895 goto out;
1898 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1899 deny_mode = SVAL(req->vwv+0, 0);
1900 dos_attr = SVAL(req->vwv+1, 0);
1902 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
1903 STR_TERMINATE, &status);
1904 if (!NT_STATUS_IS_OK(status)) {
1905 reply_nterror(req, status);
1906 goto out;
1909 if (!map_open_params_to_ntcreate(fname, deny_mode,
1910 OPENX_FILE_EXISTS_OPEN, &access_mask,
1911 &share_mode, &create_disposition,
1912 &create_options, &private_flags)) {
1913 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1914 goto out;
1917 status = filename_convert(ctx,
1918 conn,
1919 req->flags2 & FLAGS2_DFS_PATHNAMES,
1920 fname,
1921 UCF_PREP_CREATEFILE,
1922 NULL,
1923 &smb_fname);
1924 if (!NT_STATUS_IS_OK(status)) {
1925 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1926 reply_botherror(req,
1927 NT_STATUS_PATH_NOT_COVERED,
1928 ERRSRV, ERRbadpath);
1929 goto out;
1931 reply_nterror(req, status);
1932 goto out;
1935 status = SMB_VFS_CREATE_FILE(
1936 conn, /* conn */
1937 req, /* req */
1938 0, /* root_dir_fid */
1939 smb_fname, /* fname */
1940 access_mask, /* access_mask */
1941 share_mode, /* share_access */
1942 create_disposition, /* create_disposition*/
1943 create_options, /* create_options */
1944 dos_attr, /* file_attributes */
1945 oplock_request, /* oplock_request */
1946 0, /* allocation_size */
1947 private_flags,
1948 NULL, /* sd */
1949 NULL, /* ea_list */
1950 &fsp, /* result */
1951 &info); /* pinfo */
1953 if (!NT_STATUS_IS_OK(status)) {
1954 if (open_was_deferred(req->sconn, req->mid)) {
1955 /* We have re-scheduled this call. */
1956 goto out;
1958 reply_openerror(req, status);
1959 goto out;
1962 /* Ensure we're pointing at the correct stat struct. */
1963 TALLOC_FREE(smb_fname);
1964 smb_fname = fsp->fsp_name;
1966 size = smb_fname->st.st_ex_size;
1967 fattr = dos_mode(conn, smb_fname);
1969 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1971 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
1972 DEBUG(3,("attempt to open a directory %s\n",
1973 fsp_str_dbg(fsp)));
1974 close_file(req, fsp, ERROR_CLOSE);
1975 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
1976 ERRDOS, ERRnoaccess);
1977 goto out;
1980 reply_outbuf(req, 7, 0);
1981 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
1982 SSVAL(req->outbuf,smb_vwv1,fattr);
1983 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1984 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
1985 } else {
1986 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
1988 SIVAL(req->outbuf,smb_vwv4,(uint32)size);
1989 SSVAL(req->outbuf,smb_vwv6,deny_mode);
1991 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1992 SCVAL(req->outbuf,smb_flg,
1993 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1996 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1997 SCVAL(req->outbuf,smb_flg,
1998 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2000 out:
2001 END_PROFILE(SMBopen);
2002 return;
2005 /****************************************************************************
2006 Reply to an open and X.
2007 ****************************************************************************/
2009 void reply_open_and_X(struct smb_request *req)
2011 connection_struct *conn = req->conn;
2012 struct smb_filename *smb_fname = NULL;
2013 char *fname = NULL;
2014 uint16 open_flags;
2015 int deny_mode;
2016 uint32 smb_attr;
2017 /* Breakout the oplock request bits so we can set the
2018 reply bits separately. */
2019 int ex_oplock_request;
2020 int core_oplock_request;
2021 int oplock_request;
2022 #if 0
2023 int smb_sattr = SVAL(req->vwv+4, 0);
2024 uint32 smb_time = make_unix_date3(req->vwv+6);
2025 #endif
2026 int smb_ofun;
2027 uint32 fattr=0;
2028 int mtime=0;
2029 int smb_action = 0;
2030 files_struct *fsp;
2031 NTSTATUS status;
2032 uint64_t allocation_size;
2033 ssize_t retval = -1;
2034 uint32 access_mask;
2035 uint32 share_mode;
2036 uint32 create_disposition;
2037 uint32 create_options = 0;
2038 uint32_t private_flags = 0;
2039 TALLOC_CTX *ctx = talloc_tos();
2041 START_PROFILE(SMBopenX);
2043 if (req->wct < 15) {
2044 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2045 goto out;
2048 open_flags = SVAL(req->vwv+2, 0);
2049 deny_mode = SVAL(req->vwv+3, 0);
2050 smb_attr = SVAL(req->vwv+5, 0);
2051 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
2052 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2053 oplock_request = ex_oplock_request | core_oplock_request;
2054 smb_ofun = SVAL(req->vwv+8, 0);
2055 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
2057 /* If it's an IPC, pass off the pipe handler. */
2058 if (IS_IPC(conn)) {
2059 if (lp_nt_pipe_support()) {
2060 reply_open_pipe_and_X(conn, req);
2061 } else {
2062 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
2064 goto out;
2067 /* XXXX we need to handle passed times, sattr and flags */
2068 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
2069 STR_TERMINATE, &status);
2070 if (!NT_STATUS_IS_OK(status)) {
2071 reply_nterror(req, status);
2072 goto out;
2075 if (!map_open_params_to_ntcreate(fname, deny_mode,
2076 smb_ofun,
2077 &access_mask, &share_mode,
2078 &create_disposition,
2079 &create_options,
2080 &private_flags)) {
2081 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2082 goto out;
2085 status = filename_convert(ctx,
2086 conn,
2087 req->flags2 & FLAGS2_DFS_PATHNAMES,
2088 fname,
2089 UCF_PREP_CREATEFILE,
2090 NULL,
2091 &smb_fname);
2092 if (!NT_STATUS_IS_OK(status)) {
2093 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2094 reply_botherror(req,
2095 NT_STATUS_PATH_NOT_COVERED,
2096 ERRSRV, ERRbadpath);
2097 goto out;
2099 reply_nterror(req, status);
2100 goto out;
2103 status = SMB_VFS_CREATE_FILE(
2104 conn, /* conn */
2105 req, /* req */
2106 0, /* root_dir_fid */
2107 smb_fname, /* fname */
2108 access_mask, /* access_mask */
2109 share_mode, /* share_access */
2110 create_disposition, /* create_disposition*/
2111 create_options, /* create_options */
2112 smb_attr, /* file_attributes */
2113 oplock_request, /* oplock_request */
2114 0, /* allocation_size */
2115 private_flags,
2116 NULL, /* sd */
2117 NULL, /* ea_list */
2118 &fsp, /* result */
2119 &smb_action); /* pinfo */
2121 if (!NT_STATUS_IS_OK(status)) {
2122 if (open_was_deferred(req->sconn, req->mid)) {
2123 /* We have re-scheduled this call. */
2124 goto out;
2126 reply_openerror(req, status);
2127 goto out;
2130 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2131 if the file is truncated or created. */
2132 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2133 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2134 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2135 close_file(req, fsp, ERROR_CLOSE);
2136 reply_nterror(req, NT_STATUS_DISK_FULL);
2137 goto out;
2139 retval = vfs_set_filelen(fsp, (off_t)allocation_size);
2140 if (retval < 0) {
2141 close_file(req, fsp, ERROR_CLOSE);
2142 reply_nterror(req, NT_STATUS_DISK_FULL);
2143 goto out;
2145 status = vfs_stat_fsp(fsp);
2146 if (!NT_STATUS_IS_OK(status)) {
2147 close_file(req, fsp, ERROR_CLOSE);
2148 reply_nterror(req, status);
2149 goto out;
2153 fattr = dos_mode(conn, fsp->fsp_name);
2154 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2155 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2156 close_file(req, fsp, ERROR_CLOSE);
2157 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2158 goto out;
2161 /* If the caller set the extended oplock request bit
2162 and we granted one (by whatever means) - set the
2163 correct bit for extended oplock reply.
2166 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2167 smb_action |= EXTENDED_OPLOCK_GRANTED;
2170 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2171 smb_action |= EXTENDED_OPLOCK_GRANTED;
2174 /* If the caller set the core oplock request bit
2175 and we granted one (by whatever means) - set the
2176 correct bit for core oplock reply.
2179 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2180 reply_outbuf(req, 19, 0);
2181 } else {
2182 reply_outbuf(req, 15, 0);
2185 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2186 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2188 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2189 SCVAL(req->outbuf, smb_flg,
2190 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2193 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2194 SCVAL(req->outbuf, smb_flg,
2195 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2198 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2199 SSVAL(req->outbuf,smb_vwv3,fattr);
2200 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2201 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2202 } else {
2203 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2205 SIVAL(req->outbuf,smb_vwv6,(uint32)fsp->fsp_name->st.st_ex_size);
2206 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2207 SSVAL(req->outbuf,smb_vwv11,smb_action);
2209 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2210 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2213 out:
2214 TALLOC_FREE(smb_fname);
2215 END_PROFILE(SMBopenX);
2216 return;
2219 /****************************************************************************
2220 Reply to a SMBulogoffX.
2221 ****************************************************************************/
2223 void reply_ulogoffX(struct smb_request *req)
2225 struct smbd_server_connection *sconn = req->sconn;
2226 struct user_struct *vuser;
2227 struct smbXsrv_session *session = NULL;
2228 NTSTATUS status;
2230 START_PROFILE(SMBulogoffX);
2232 vuser = get_valid_user_struct(sconn, req->vuid);
2234 if(vuser == NULL) {
2235 DEBUG(3,("ulogoff, vuser id %llu does not map to user.\n",
2236 (unsigned long long)req->vuid));
2238 req->vuid = UID_FIELD_INVALID;
2239 reply_force_doserror(req, ERRSRV, ERRbaduid);
2240 END_PROFILE(SMBulogoffX);
2241 return;
2244 session = vuser->session;
2245 vuser = NULL;
2248 * TODO: cancel all outstanding requests on the session
2250 status = smbXsrv_session_logoff(session);
2251 if (!NT_STATUS_IS_OK(status)) {
2252 DEBUG(0, ("reply_ulogoff: "
2253 "smbXsrv_session_logoff() failed: %s\n",
2254 nt_errstr(status)));
2256 * If we hit this case, there is something completely
2257 * wrong, so we better disconnect the transport connection.
2259 END_PROFILE(SMBulogoffX);
2260 exit_server(__location__ ": smbXsrv_session_logoff failed");
2261 return;
2264 TALLOC_FREE(session);
2266 reply_outbuf(req, 2, 0);
2267 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2268 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2270 DEBUG(3, ("ulogoffX vuid=%llu\n",
2271 (unsigned long long)req->vuid));
2273 END_PROFILE(SMBulogoffX);
2274 req->vuid = UID_FIELD_INVALID;
2277 /****************************************************************************
2278 Reply to a mknew or a create.
2279 ****************************************************************************/
2281 void reply_mknew(struct smb_request *req)
2283 connection_struct *conn = req->conn;
2284 struct smb_filename *smb_fname = NULL;
2285 char *fname = NULL;
2286 uint32 fattr = 0;
2287 struct smb_file_time ft;
2288 files_struct *fsp;
2289 int oplock_request = 0;
2290 NTSTATUS status;
2291 uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2292 uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2293 uint32 create_disposition;
2294 uint32 create_options = 0;
2295 TALLOC_CTX *ctx = talloc_tos();
2297 START_PROFILE(SMBcreate);
2298 ZERO_STRUCT(ft);
2300 if (req->wct < 3) {
2301 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2302 goto out;
2305 fattr = SVAL(req->vwv+0, 0);
2306 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2308 /* mtime. */
2309 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2311 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2312 STR_TERMINATE, &status);
2313 if (!NT_STATUS_IS_OK(status)) {
2314 reply_nterror(req, status);
2315 goto out;
2318 status = filename_convert(ctx,
2319 conn,
2320 req->flags2 & FLAGS2_DFS_PATHNAMES,
2321 fname,
2322 UCF_PREP_CREATEFILE,
2323 NULL,
2324 &smb_fname);
2325 if (!NT_STATUS_IS_OK(status)) {
2326 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2327 reply_botherror(req,
2328 NT_STATUS_PATH_NOT_COVERED,
2329 ERRSRV, ERRbadpath);
2330 goto out;
2332 reply_nterror(req, status);
2333 goto out;
2336 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2337 DEBUG(0,("Attempt to create file (%s) with volid set - "
2338 "please report this\n",
2339 smb_fname_str_dbg(smb_fname)));
2342 if(req->cmd == SMBmknew) {
2343 /* We should fail if file exists. */
2344 create_disposition = FILE_CREATE;
2345 } else {
2346 /* Create if file doesn't exist, truncate if it does. */
2347 create_disposition = FILE_OVERWRITE_IF;
2350 status = SMB_VFS_CREATE_FILE(
2351 conn, /* conn */
2352 req, /* req */
2353 0, /* root_dir_fid */
2354 smb_fname, /* fname */
2355 access_mask, /* access_mask */
2356 share_mode, /* share_access */
2357 create_disposition, /* create_disposition*/
2358 create_options, /* create_options */
2359 fattr, /* file_attributes */
2360 oplock_request, /* oplock_request */
2361 0, /* allocation_size */
2362 0, /* private_flags */
2363 NULL, /* sd */
2364 NULL, /* ea_list */
2365 &fsp, /* result */
2366 NULL); /* pinfo */
2368 if (!NT_STATUS_IS_OK(status)) {
2369 if (open_was_deferred(req->sconn, req->mid)) {
2370 /* We have re-scheduled this call. */
2371 goto out;
2373 reply_openerror(req, status);
2374 goto out;
2377 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2378 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2379 if (!NT_STATUS_IS_OK(status)) {
2380 END_PROFILE(SMBcreate);
2381 goto out;
2384 reply_outbuf(req, 1, 0);
2385 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2387 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2388 SCVAL(req->outbuf,smb_flg,
2389 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2392 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2393 SCVAL(req->outbuf,smb_flg,
2394 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2397 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2398 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2399 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2400 (unsigned int)fattr));
2402 out:
2403 TALLOC_FREE(smb_fname);
2404 END_PROFILE(SMBcreate);
2405 return;
2408 /****************************************************************************
2409 Reply to a create temporary file.
2410 ****************************************************************************/
2412 void reply_ctemp(struct smb_request *req)
2414 connection_struct *conn = req->conn;
2415 struct smb_filename *smb_fname = NULL;
2416 char *wire_name = NULL;
2417 char *fname = NULL;
2418 uint32 fattr;
2419 files_struct *fsp;
2420 int oplock_request;
2421 char *s;
2422 NTSTATUS status;
2423 int i;
2424 TALLOC_CTX *ctx = talloc_tos();
2426 START_PROFILE(SMBctemp);
2428 if (req->wct < 3) {
2429 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2430 goto out;
2433 fattr = SVAL(req->vwv+0, 0);
2434 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2436 srvstr_get_path_req(ctx, req, &wire_name, (const char *)req->buf+1,
2437 STR_TERMINATE, &status);
2438 if (!NT_STATUS_IS_OK(status)) {
2439 reply_nterror(req, status);
2440 goto out;
2443 for (i = 0; i < 10; i++) {
2444 if (*wire_name) {
2445 fname = talloc_asprintf(ctx,
2446 "%s/TMP%s",
2447 wire_name,
2448 generate_random_str_list(ctx, 5, "0123456789"));
2449 } else {
2450 fname = talloc_asprintf(ctx,
2451 "TMP%s",
2452 generate_random_str_list(ctx, 5, "0123456789"));
2455 if (!fname) {
2456 reply_nterror(req, NT_STATUS_NO_MEMORY);
2457 goto out;
2460 status = filename_convert(ctx, conn,
2461 req->flags2 & FLAGS2_DFS_PATHNAMES,
2462 fname,
2463 UCF_PREP_CREATEFILE,
2464 NULL,
2465 &smb_fname);
2466 if (!NT_STATUS_IS_OK(status)) {
2467 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2468 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2469 ERRSRV, ERRbadpath);
2470 goto out;
2472 reply_nterror(req, status);
2473 goto out;
2476 /* Create the file. */
2477 status = SMB_VFS_CREATE_FILE(
2478 conn, /* conn */
2479 req, /* req */
2480 0, /* root_dir_fid */
2481 smb_fname, /* fname */
2482 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2483 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2484 FILE_CREATE, /* create_disposition*/
2485 0, /* create_options */
2486 fattr, /* file_attributes */
2487 oplock_request, /* oplock_request */
2488 0, /* allocation_size */
2489 0, /* private_flags */
2490 NULL, /* sd */
2491 NULL, /* ea_list */
2492 &fsp, /* result */
2493 NULL); /* pinfo */
2495 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2496 TALLOC_FREE(fname);
2497 TALLOC_FREE(smb_fname);
2498 continue;
2501 if (!NT_STATUS_IS_OK(status)) {
2502 if (open_was_deferred(req->sconn, req->mid)) {
2503 /* We have re-scheduled this call. */
2504 goto out;
2506 reply_openerror(req, status);
2507 goto out;
2510 break;
2513 if (i == 10) {
2514 /* Collision after 10 times... */
2515 reply_nterror(req, status);
2516 goto out;
2519 reply_outbuf(req, 1, 0);
2520 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2522 /* the returned filename is relative to the directory */
2523 s = strrchr_m(fsp->fsp_name->base_name, '/');
2524 if (!s) {
2525 s = fsp->fsp_name->base_name;
2526 } else {
2527 s++;
2530 #if 0
2531 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2532 thing in the byte section. JRA */
2533 SSVALS(p, 0, -1); /* what is this? not in spec */
2534 #endif
2535 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2536 == -1) {
2537 reply_nterror(req, NT_STATUS_NO_MEMORY);
2538 goto out;
2541 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2542 SCVAL(req->outbuf, smb_flg,
2543 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2546 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2547 SCVAL(req->outbuf, smb_flg,
2548 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2551 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2552 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2553 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2554 out:
2555 TALLOC_FREE(smb_fname);
2556 TALLOC_FREE(wire_name);
2557 END_PROFILE(SMBctemp);
2558 return;
2561 /*******************************************************************
2562 Check if a user is allowed to rename a file.
2563 ********************************************************************/
2565 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2566 uint16 dirtype)
2568 if (!CAN_WRITE(conn)) {
2569 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2572 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
2573 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2574 /* Only bother to read the DOS attribute if we might deny the
2575 rename on the grounds of attribute missmatch. */
2576 uint32_t fmode = dos_mode(conn, fsp->fsp_name);
2577 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2578 return NT_STATUS_NO_SUCH_FILE;
2582 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2583 if (fsp->posix_open) {
2584 return NT_STATUS_OK;
2587 /* If no pathnames are open below this
2588 directory, allow the rename. */
2590 if (file_find_subpath(fsp)) {
2591 return NT_STATUS_ACCESS_DENIED;
2593 return NT_STATUS_OK;
2596 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2597 return NT_STATUS_OK;
2600 return NT_STATUS_ACCESS_DENIED;
2603 /*******************************************************************
2604 * unlink a file with all relevant access checks
2605 *******************************************************************/
2607 static NTSTATUS do_unlink(connection_struct *conn,
2608 struct smb_request *req,
2609 struct smb_filename *smb_fname,
2610 uint32 dirtype)
2612 uint32 fattr;
2613 files_struct *fsp;
2614 uint32 dirtype_orig = dirtype;
2615 NTSTATUS status;
2616 int ret;
2617 bool posix_paths = lp_posix_pathnames();
2619 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2620 smb_fname_str_dbg(smb_fname),
2621 dirtype));
2623 if (!CAN_WRITE(conn)) {
2624 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2627 if (posix_paths) {
2628 ret = SMB_VFS_LSTAT(conn, smb_fname);
2629 } else {
2630 ret = SMB_VFS_STAT(conn, smb_fname);
2632 if (ret != 0) {
2633 return map_nt_error_from_unix(errno);
2636 fattr = dos_mode(conn, smb_fname);
2638 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2639 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
2642 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
2643 if (!dirtype) {
2644 return NT_STATUS_NO_SUCH_FILE;
2647 if (!dir_check_ftype(fattr, dirtype)) {
2648 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2649 return NT_STATUS_FILE_IS_A_DIRECTORY;
2651 return NT_STATUS_NO_SUCH_FILE;
2654 if (dirtype_orig & 0x8000) {
2655 /* These will never be set for POSIX. */
2656 return NT_STATUS_NO_SUCH_FILE;
2659 #if 0
2660 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2661 return NT_STATUS_FILE_IS_A_DIRECTORY;
2664 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2665 return NT_STATUS_NO_SUCH_FILE;
2668 if (dirtype & 0xFF00) {
2669 /* These will never be set for POSIX. */
2670 return NT_STATUS_NO_SUCH_FILE;
2673 dirtype &= 0xFF;
2674 if (!dirtype) {
2675 return NT_STATUS_NO_SUCH_FILE;
2678 /* Can't delete a directory. */
2679 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2680 return NT_STATUS_FILE_IS_A_DIRECTORY;
2682 #endif
2684 #if 0 /* JRATEST */
2685 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
2686 return NT_STATUS_OBJECT_NAME_INVALID;
2687 #endif /* JRATEST */
2689 /* On open checks the open itself will check the share mode, so
2690 don't do it here as we'll get it wrong. */
2692 status = SMB_VFS_CREATE_FILE
2693 (conn, /* conn */
2694 req, /* req */
2695 0, /* root_dir_fid */
2696 smb_fname, /* fname */
2697 DELETE_ACCESS, /* access_mask */
2698 FILE_SHARE_NONE, /* share_access */
2699 FILE_OPEN, /* create_disposition*/
2700 FILE_NON_DIRECTORY_FILE, /* create_options */
2701 /* file_attributes */
2702 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2703 FILE_ATTRIBUTE_NORMAL,
2704 0, /* oplock_request */
2705 0, /* allocation_size */
2706 0, /* private_flags */
2707 NULL, /* sd */
2708 NULL, /* ea_list */
2709 &fsp, /* result */
2710 NULL); /* pinfo */
2712 if (!NT_STATUS_IS_OK(status)) {
2713 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2714 nt_errstr(status)));
2715 return status;
2718 status = can_set_delete_on_close(fsp, fattr);
2719 if (!NT_STATUS_IS_OK(status)) {
2720 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2721 "(%s)\n",
2722 smb_fname_str_dbg(smb_fname),
2723 nt_errstr(status)));
2724 close_file(req, fsp, NORMAL_CLOSE);
2725 return status;
2728 /* The set is across all open files on this dev/inode pair. */
2729 if (!set_delete_on_close(fsp, True,
2730 conn->session_info->security_token,
2731 conn->session_info->unix_token)) {
2732 close_file(req, fsp, NORMAL_CLOSE);
2733 return NT_STATUS_ACCESS_DENIED;
2736 return close_file(req, fsp, NORMAL_CLOSE);
2739 /****************************************************************************
2740 The guts of the unlink command, split out so it may be called by the NT SMB
2741 code.
2742 ****************************************************************************/
2744 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2745 uint32 dirtype, struct smb_filename *smb_fname,
2746 bool has_wild)
2748 char *fname_dir = NULL;
2749 char *fname_mask = NULL;
2750 int count=0;
2751 NTSTATUS status = NT_STATUS_OK;
2752 TALLOC_CTX *ctx = talloc_tos();
2754 /* Split up the directory from the filename/mask. */
2755 status = split_fname_dir_mask(ctx, smb_fname->base_name,
2756 &fname_dir, &fname_mask);
2757 if (!NT_STATUS_IS_OK(status)) {
2758 goto out;
2762 * We should only check the mangled cache
2763 * here if unix_convert failed. This means
2764 * that the path in 'mask' doesn't exist
2765 * on the file system and so we need to look
2766 * for a possible mangle. This patch from
2767 * Tine Smukavec <valentin.smukavec@hermes.si>.
2770 if (!VALID_STAT(smb_fname->st) &&
2771 mangle_is_mangled(fname_mask, conn->params)) {
2772 char *new_mask = NULL;
2773 mangle_lookup_name_from_8_3(ctx, fname_mask,
2774 &new_mask, conn->params);
2775 if (new_mask) {
2776 TALLOC_FREE(fname_mask);
2777 fname_mask = new_mask;
2781 if (!has_wild) {
2784 * Only one file needs to be unlinked. Append the mask back
2785 * onto the directory.
2787 TALLOC_FREE(smb_fname->base_name);
2788 if (ISDOT(fname_dir)) {
2789 /* Ensure we use canonical names on open. */
2790 smb_fname->base_name = talloc_asprintf(smb_fname,
2791 "%s",
2792 fname_mask);
2793 } else {
2794 smb_fname->base_name = talloc_asprintf(smb_fname,
2795 "%s/%s",
2796 fname_dir,
2797 fname_mask);
2799 if (!smb_fname->base_name) {
2800 status = NT_STATUS_NO_MEMORY;
2801 goto out;
2803 if (dirtype == 0) {
2804 dirtype = FILE_ATTRIBUTE_NORMAL;
2807 status = check_name(conn, smb_fname->base_name);
2808 if (!NT_STATUS_IS_OK(status)) {
2809 goto out;
2812 status = do_unlink(conn, req, smb_fname, dirtype);
2813 if (!NT_STATUS_IS_OK(status)) {
2814 goto out;
2817 count++;
2818 } else {
2819 struct smb_Dir *dir_hnd = NULL;
2820 long offset = 0;
2821 const char *dname = NULL;
2822 char *talloced = NULL;
2824 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
2825 status = NT_STATUS_OBJECT_NAME_INVALID;
2826 goto out;
2829 if (strequal(fname_mask,"????????.???")) {
2830 TALLOC_FREE(fname_mask);
2831 fname_mask = talloc_strdup(ctx, "*");
2832 if (!fname_mask) {
2833 status = NT_STATUS_NO_MEMORY;
2834 goto out;
2838 status = check_name(conn, fname_dir);
2839 if (!NT_STATUS_IS_OK(status)) {
2840 goto out;
2843 dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask,
2844 dirtype);
2845 if (dir_hnd == NULL) {
2846 status = map_nt_error_from_unix(errno);
2847 goto out;
2850 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2851 the pattern matches against the long name, otherwise the short name
2852 We don't implement this yet XXXX
2855 status = NT_STATUS_NO_SUCH_FILE;
2857 while ((dname = ReadDirName(dir_hnd, &offset,
2858 &smb_fname->st, &talloced))) {
2859 TALLOC_CTX *frame = talloc_stackframe();
2861 if (!is_visible_file(conn, fname_dir, dname,
2862 &smb_fname->st, true)) {
2863 TALLOC_FREE(frame);
2864 TALLOC_FREE(talloced);
2865 continue;
2868 /* Quick check for "." and ".." */
2869 if (ISDOT(dname) || ISDOTDOT(dname)) {
2870 TALLOC_FREE(frame);
2871 TALLOC_FREE(talloced);
2872 continue;
2875 if(!mask_match(dname, fname_mask,
2876 conn->case_sensitive)) {
2877 TALLOC_FREE(frame);
2878 TALLOC_FREE(talloced);
2879 continue;
2882 TALLOC_FREE(smb_fname->base_name);
2883 if (ISDOT(fname_dir)) {
2884 /* Ensure we use canonical names on open. */
2885 smb_fname->base_name =
2886 talloc_asprintf(smb_fname, "%s",
2887 dname);
2888 } else {
2889 smb_fname->base_name =
2890 talloc_asprintf(smb_fname, "%s/%s",
2891 fname_dir, dname);
2894 if (!smb_fname->base_name) {
2895 TALLOC_FREE(dir_hnd);
2896 status = NT_STATUS_NO_MEMORY;
2897 TALLOC_FREE(frame);
2898 TALLOC_FREE(talloced);
2899 goto out;
2902 status = check_name(conn, smb_fname->base_name);
2903 if (!NT_STATUS_IS_OK(status)) {
2904 TALLOC_FREE(dir_hnd);
2905 TALLOC_FREE(frame);
2906 TALLOC_FREE(talloced);
2907 goto out;
2910 status = do_unlink(conn, req, smb_fname, dirtype);
2911 if (!NT_STATUS_IS_OK(status)) {
2912 TALLOC_FREE(dir_hnd);
2913 TALLOC_FREE(frame);
2914 TALLOC_FREE(talloced);
2915 goto out;
2918 count++;
2919 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
2920 smb_fname->base_name));
2922 TALLOC_FREE(frame);
2923 TALLOC_FREE(talloced);
2925 TALLOC_FREE(dir_hnd);
2928 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
2929 status = map_nt_error_from_unix(errno);
2932 out:
2933 TALLOC_FREE(fname_dir);
2934 TALLOC_FREE(fname_mask);
2935 return status;
2938 /****************************************************************************
2939 Reply to a unlink
2940 ****************************************************************************/
2942 void reply_unlink(struct smb_request *req)
2944 connection_struct *conn = req->conn;
2945 char *name = NULL;
2946 struct smb_filename *smb_fname = NULL;
2947 uint32 dirtype;
2948 NTSTATUS status;
2949 bool path_contains_wcard = False;
2950 TALLOC_CTX *ctx = talloc_tos();
2952 START_PROFILE(SMBunlink);
2954 if (req->wct < 1) {
2955 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2956 goto out;
2959 dirtype = SVAL(req->vwv+0, 0);
2961 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
2962 STR_TERMINATE, &status,
2963 &path_contains_wcard);
2964 if (!NT_STATUS_IS_OK(status)) {
2965 reply_nterror(req, status);
2966 goto out;
2969 status = filename_convert(ctx, conn,
2970 req->flags2 & FLAGS2_DFS_PATHNAMES,
2971 name,
2972 UCF_COND_ALLOW_WCARD_LCOMP,
2973 &path_contains_wcard,
2974 &smb_fname);
2975 if (!NT_STATUS_IS_OK(status)) {
2976 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2977 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2978 ERRSRV, ERRbadpath);
2979 goto out;
2981 reply_nterror(req, status);
2982 goto out;
2985 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
2987 status = unlink_internals(conn, req, dirtype, smb_fname,
2988 path_contains_wcard);
2989 if (!NT_STATUS_IS_OK(status)) {
2990 if (open_was_deferred(req->sconn, req->mid)) {
2991 /* We have re-scheduled this call. */
2992 goto out;
2994 reply_nterror(req, status);
2995 goto out;
2998 reply_outbuf(req, 0, 0);
2999 out:
3000 TALLOC_FREE(smb_fname);
3001 END_PROFILE(SMBunlink);
3002 return;
3005 /****************************************************************************
3006 Fail for readbraw.
3007 ****************************************************************************/
3009 static void fail_readraw(void)
3011 const char *errstr = talloc_asprintf(talloc_tos(),
3012 "FAIL ! reply_readbraw: socket write fail (%s)",
3013 strerror(errno));
3014 if (!errstr) {
3015 errstr = "";
3017 exit_server_cleanly(errstr);
3020 /****************************************************************************
3021 Fake (read/write) sendfile. Returns -1 on read or write fail.
3022 ****************************************************************************/
3024 ssize_t fake_sendfile(files_struct *fsp, off_t startpos, size_t nread)
3026 size_t bufsize;
3027 size_t tosend = nread;
3028 char *buf;
3030 if (nread == 0) {
3031 return 0;
3034 bufsize = MIN(nread, 65536);
3036 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
3037 return -1;
3040 while (tosend > 0) {
3041 ssize_t ret;
3042 size_t cur_read;
3044 if (tosend > bufsize) {
3045 cur_read = bufsize;
3046 } else {
3047 cur_read = tosend;
3049 ret = read_file(fsp,buf,startpos,cur_read);
3050 if (ret == -1) {
3051 SAFE_FREE(buf);
3052 return -1;
3055 /* If we had a short read, fill with zeros. */
3056 if (ret < cur_read) {
3057 memset(buf + ret, '\0', cur_read - ret);
3060 if (write_data(fsp->conn->sconn->sock, buf, cur_read)
3061 != cur_read) {
3062 char addr[INET6_ADDRSTRLEN];
3064 * Try and give an error message saying what
3065 * client failed.
3067 DEBUG(0, ("write_data failed for client %s. "
3068 "Error %s\n",
3069 get_peer_addr(fsp->conn->sconn->sock, addr,
3070 sizeof(addr)),
3071 strerror(errno)));
3072 SAFE_FREE(buf);
3073 return -1;
3075 tosend -= cur_read;
3076 startpos += cur_read;
3079 SAFE_FREE(buf);
3080 return (ssize_t)nread;
3083 /****************************************************************************
3084 Deal with the case of sendfile reading less bytes from the file than
3085 requested. Fill with zeros (all we can do).
3086 ****************************************************************************/
3088 void sendfile_short_send(files_struct *fsp,
3089 ssize_t nread,
3090 size_t headersize,
3091 size_t smb_maxcnt)
3093 #define SHORT_SEND_BUFSIZE 1024
3094 if (nread < headersize) {
3095 DEBUG(0,("sendfile_short_send: sendfile failed to send "
3096 "header for file %s (%s). Terminating\n",
3097 fsp_str_dbg(fsp), strerror(errno)));
3098 exit_server_cleanly("sendfile_short_send failed");
3101 nread -= headersize;
3103 if (nread < smb_maxcnt) {
3104 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
3105 if (!buf) {
3106 exit_server_cleanly("sendfile_short_send: "
3107 "malloc failed");
3110 DEBUG(0,("sendfile_short_send: filling truncated file %s "
3111 "with zeros !\n", fsp_str_dbg(fsp)));
3113 while (nread < smb_maxcnt) {
3115 * We asked for the real file size and told sendfile
3116 * to not go beyond the end of the file. But it can
3117 * happen that in between our fstat call and the
3118 * sendfile call the file was truncated. This is very
3119 * bad because we have already announced the larger
3120 * number of bytes to the client.
3122 * The best we can do now is to send 0-bytes, just as
3123 * a read from a hole in a sparse file would do.
3125 * This should happen rarely enough that I don't care
3126 * about efficiency here :-)
3128 size_t to_write;
3130 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
3131 if (write_data(fsp->conn->sconn->sock, buf, to_write)
3132 != to_write) {
3133 char addr[INET6_ADDRSTRLEN];
3135 * Try and give an error message saying what
3136 * client failed.
3138 DEBUG(0, ("write_data failed for client %s. "
3139 "Error %s\n",
3140 get_peer_addr(
3141 fsp->conn->sconn->sock, addr,
3142 sizeof(addr)),
3143 strerror(errno)));
3144 exit_server_cleanly("sendfile_short_send: "
3145 "write_data failed");
3147 nread += to_write;
3149 SAFE_FREE(buf);
3153 /****************************************************************************
3154 Return a readbraw error (4 bytes of zero).
3155 ****************************************************************************/
3157 static void reply_readbraw_error(struct smbd_server_connection *sconn)
3159 char header[4];
3161 SIVAL(header,0,0);
3163 smbd_lock_socket(sconn);
3164 if (write_data(sconn->sock,header,4) != 4) {
3165 char addr[INET6_ADDRSTRLEN];
3167 * Try and give an error message saying what
3168 * client failed.
3170 DEBUG(0, ("write_data failed for client %s. "
3171 "Error %s\n",
3172 get_peer_addr(sconn->sock, addr, sizeof(addr)),
3173 strerror(errno)));
3175 fail_readraw();
3177 smbd_unlock_socket(sconn);
3180 /****************************************************************************
3181 Use sendfile in readbraw.
3182 ****************************************************************************/
3184 static void send_file_readbraw(connection_struct *conn,
3185 struct smb_request *req,
3186 files_struct *fsp,
3187 off_t startpos,
3188 size_t nread,
3189 ssize_t mincount)
3191 struct smbd_server_connection *sconn = req->sconn;
3192 char *outbuf = NULL;
3193 ssize_t ret=0;
3196 * We can only use sendfile on a non-chained packet
3197 * but we can use on a non-oplocked file. tridge proved this
3198 * on a train in Germany :-). JRA.
3199 * reply_readbraw has already checked the length.
3202 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3203 (fsp->wcp == NULL) &&
3204 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3205 ssize_t sendfile_read = -1;
3206 char header[4];
3207 DATA_BLOB header_blob;
3209 _smb_setlen(header,nread);
3210 header_blob = data_blob_const(header, 4);
3212 sendfile_read = SMB_VFS_SENDFILE(sconn->sock, fsp,
3213 &header_blob, startpos,
3214 nread);
3215 if (sendfile_read == -1) {
3216 /* Returning ENOSYS means no data at all was sent.
3217 * Do this as a normal read. */
3218 if (errno == ENOSYS) {
3219 goto normal_readbraw;
3223 * Special hack for broken Linux with no working sendfile. If we
3224 * return EINTR we sent the header but not the rest of the data.
3225 * Fake this up by doing read/write calls.
3227 if (errno == EINTR) {
3228 /* Ensure we don't do this again. */
3229 set_use_sendfile(SNUM(conn), False);
3230 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3232 if (fake_sendfile(fsp, startpos, nread) == -1) {
3233 DEBUG(0,("send_file_readbraw: "
3234 "fake_sendfile failed for "
3235 "file %s (%s).\n",
3236 fsp_str_dbg(fsp),
3237 strerror(errno)));
3238 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3240 return;
3243 DEBUG(0,("send_file_readbraw: sendfile failed for "
3244 "file %s (%s). Terminating\n",
3245 fsp_str_dbg(fsp), strerror(errno)));
3246 exit_server_cleanly("send_file_readbraw sendfile failed");
3247 } else if (sendfile_read == 0) {
3249 * Some sendfile implementations return 0 to indicate
3250 * that there was a short read, but nothing was
3251 * actually written to the socket. In this case,
3252 * fallback to the normal read path so the header gets
3253 * the correct byte count.
3255 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3256 "bytes falling back to the normal read: "
3257 "%s\n", fsp_str_dbg(fsp)));
3258 goto normal_readbraw;
3261 /* Deal with possible short send. */
3262 if (sendfile_read != 4+nread) {
3263 sendfile_short_send(fsp, sendfile_read, 4, nread);
3265 return;
3268 normal_readbraw:
3270 outbuf = talloc_array(NULL, char, nread+4);
3271 if (!outbuf) {
3272 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3273 (unsigned)(nread+4)));
3274 reply_readbraw_error(sconn);
3275 return;
3278 if (nread > 0) {
3279 ret = read_file(fsp,outbuf+4,startpos,nread);
3280 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3281 if (ret < mincount)
3282 ret = 0;
3283 #else
3284 if (ret < nread)
3285 ret = 0;
3286 #endif
3289 _smb_setlen(outbuf,ret);
3290 if (write_data(sconn->sock, outbuf, 4+ret) != 4+ret) {
3291 char addr[INET6_ADDRSTRLEN];
3293 * Try and give an error message saying what
3294 * client failed.
3296 DEBUG(0, ("write_data failed for client %s. "
3297 "Error %s\n",
3298 get_peer_addr(fsp->conn->sconn->sock, addr,
3299 sizeof(addr)),
3300 strerror(errno)));
3302 fail_readraw();
3305 TALLOC_FREE(outbuf);
3308 /****************************************************************************
3309 Reply to a readbraw (core+ protocol).
3310 ****************************************************************************/
3312 void reply_readbraw(struct smb_request *req)
3314 connection_struct *conn = req->conn;
3315 struct smbd_server_connection *sconn = req->sconn;
3316 ssize_t maxcount,mincount;
3317 size_t nread = 0;
3318 off_t startpos;
3319 files_struct *fsp;
3320 struct lock_struct lock;
3321 off_t size = 0;
3323 START_PROFILE(SMBreadbraw);
3325 if (srv_is_signing_active(sconn) || req->encrypted) {
3326 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3327 "raw reads/writes are disallowed.");
3330 if (req->wct < 8) {
3331 reply_readbraw_error(sconn);
3332 END_PROFILE(SMBreadbraw);
3333 return;
3336 if (sconn->smb1.echo_handler.trusted_fde) {
3337 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3338 "'async smb echo handler = yes'\n"));
3339 reply_readbraw_error(sconn);
3340 END_PROFILE(SMBreadbraw);
3341 return;
3345 * Special check if an oplock break has been issued
3346 * and the readraw request croses on the wire, we must
3347 * return a zero length response here.
3350 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3353 * We have to do a check_fsp by hand here, as
3354 * we must always return 4 zero bytes on error,
3355 * not a NTSTATUS.
3358 if (!fsp || !conn || conn != fsp->conn ||
3359 req->vuid != fsp->vuid ||
3360 fsp->is_directory || fsp->fh->fd == -1) {
3362 * fsp could be NULL here so use the value from the packet. JRA.
3364 DEBUG(3,("reply_readbraw: fnum %d not valid "
3365 "- cache prime?\n",
3366 (int)SVAL(req->vwv+0, 0)));
3367 reply_readbraw_error(sconn);
3368 END_PROFILE(SMBreadbraw);
3369 return;
3372 /* Do a "by hand" version of CHECK_READ. */
3373 if (!(fsp->can_read ||
3374 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3375 (fsp->access_mask & FILE_EXECUTE)))) {
3376 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3377 (int)SVAL(req->vwv+0, 0)));
3378 reply_readbraw_error(sconn);
3379 END_PROFILE(SMBreadbraw);
3380 return;
3383 flush_write_cache(fsp, SAMBA_READRAW_FLUSH);
3385 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3386 if(req->wct == 10) {
3388 * This is a large offset (64 bit) read.
3391 startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32);
3393 if(startpos < 0) {
3394 DEBUG(0,("reply_readbraw: negative 64 bit "
3395 "readraw offset (%.0f) !\n",
3396 (double)startpos ));
3397 reply_readbraw_error(sconn);
3398 END_PROFILE(SMBreadbraw);
3399 return;
3403 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3404 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3406 /* ensure we don't overrun the packet size */
3407 maxcount = MIN(65535,maxcount);
3409 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3410 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3411 &lock);
3413 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3414 reply_readbraw_error(sconn);
3415 END_PROFILE(SMBreadbraw);
3416 return;
3419 if (fsp_stat(fsp) == 0) {
3420 size = fsp->fsp_name->st.st_ex_size;
3423 if (startpos >= size) {
3424 nread = 0;
3425 } else {
3426 nread = MIN(maxcount,(size - startpos));
3429 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3430 if (nread < mincount)
3431 nread = 0;
3432 #endif
3434 DEBUG( 3, ( "reply_readbraw: %s start=%.0f max=%lu "
3435 "min=%lu nread=%lu\n",
3436 fsp_fnum_dbg(fsp), (double)startpos,
3437 (unsigned long)maxcount,
3438 (unsigned long)mincount,
3439 (unsigned long)nread ) );
3441 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3443 DEBUG(5,("reply_readbraw finished\n"));
3445 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3447 END_PROFILE(SMBreadbraw);
3448 return;
3451 #undef DBGC_CLASS
3452 #define DBGC_CLASS DBGC_LOCKING
3454 /****************************************************************************
3455 Reply to a lockread (core+ protocol).
3456 ****************************************************************************/
3458 void reply_lockread(struct smb_request *req)
3460 connection_struct *conn = req->conn;
3461 ssize_t nread = -1;
3462 char *data;
3463 off_t startpos;
3464 size_t numtoread;
3465 size_t maxtoread;
3466 NTSTATUS status;
3467 files_struct *fsp;
3468 struct byte_range_lock *br_lck = NULL;
3469 char *p = NULL;
3470 struct smbd_server_connection *sconn = req->sconn;
3472 START_PROFILE(SMBlockread);
3474 if (req->wct < 5) {
3475 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3476 END_PROFILE(SMBlockread);
3477 return;
3480 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3482 if (!check_fsp(conn, req, fsp)) {
3483 END_PROFILE(SMBlockread);
3484 return;
3487 if (!CHECK_READ(fsp,req)) {
3488 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3489 END_PROFILE(SMBlockread);
3490 return;
3493 numtoread = SVAL(req->vwv+1, 0);
3494 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3497 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3498 * protocol request that predates the read/write lock concept.
3499 * Thus instead of asking for a read lock here we need to ask
3500 * for a write lock. JRA.
3501 * Note that the requested lock size is unaffected by max_send.
3504 br_lck = do_lock(req->sconn->msg_ctx,
3505 fsp,
3506 (uint64_t)req->smbpid,
3507 (uint64_t)numtoread,
3508 (uint64_t)startpos,
3509 WRITE_LOCK,
3510 WINDOWS_LOCK,
3511 False, /* Non-blocking lock. */
3512 &status,
3513 NULL,
3514 NULL);
3515 TALLOC_FREE(br_lck);
3517 if (NT_STATUS_V(status)) {
3518 reply_nterror(req, status);
3519 END_PROFILE(SMBlockread);
3520 return;
3524 * However the requested READ size IS affected by max_send. Insanity.... JRA.
3526 maxtoread = sconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
3528 if (numtoread > maxtoread) {
3529 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u/%u). \
3530 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3531 (unsigned int)numtoread, (unsigned int)maxtoread,
3532 (unsigned int)sconn->smb1.sessions.max_send));
3533 numtoread = maxtoread;
3536 reply_outbuf(req, 5, numtoread + 3);
3538 data = smb_buf(req->outbuf) + 3;
3540 nread = read_file(fsp,data,startpos,numtoread);
3542 if (nread < 0) {
3543 reply_nterror(req, map_nt_error_from_unix(errno));
3544 END_PROFILE(SMBlockread);
3545 return;
3548 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3550 SSVAL(req->outbuf,smb_vwv0,nread);
3551 SSVAL(req->outbuf,smb_vwv5,nread+3);
3552 p = smb_buf(req->outbuf);
3553 SCVAL(p,0,0); /* pad byte. */
3554 SSVAL(p,1,nread);
3556 DEBUG(3,("lockread %s num=%d nread=%d\n",
3557 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3559 END_PROFILE(SMBlockread);
3560 return;
3563 #undef DBGC_CLASS
3564 #define DBGC_CLASS DBGC_ALL
3566 /****************************************************************************
3567 Reply to a read.
3568 ****************************************************************************/
3570 void reply_read(struct smb_request *req)
3572 connection_struct *conn = req->conn;
3573 size_t numtoread;
3574 size_t maxtoread;
3575 ssize_t nread = 0;
3576 char *data;
3577 off_t startpos;
3578 files_struct *fsp;
3579 struct lock_struct lock;
3580 struct smbd_server_connection *sconn = req->sconn;
3582 START_PROFILE(SMBread);
3584 if (req->wct < 3) {
3585 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3586 END_PROFILE(SMBread);
3587 return;
3590 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3592 if (!check_fsp(conn, req, fsp)) {
3593 END_PROFILE(SMBread);
3594 return;
3597 if (!CHECK_READ(fsp,req)) {
3598 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3599 END_PROFILE(SMBread);
3600 return;
3603 numtoread = SVAL(req->vwv+1, 0);
3604 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3607 * The requested read size cannot be greater than max_send. JRA.
3609 maxtoread = sconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
3611 if (numtoread > maxtoread) {
3612 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u/%u). \
3613 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3614 (unsigned int)numtoread, (unsigned int)maxtoread,
3615 (unsigned int)sconn->smb1.sessions.max_send));
3616 numtoread = maxtoread;
3619 reply_outbuf(req, 5, numtoread+3);
3621 data = smb_buf(req->outbuf) + 3;
3623 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3624 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3625 &lock);
3627 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3628 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3629 END_PROFILE(SMBread);
3630 return;
3633 if (numtoread > 0)
3634 nread = read_file(fsp,data,startpos,numtoread);
3636 if (nread < 0) {
3637 reply_nterror(req, map_nt_error_from_unix(errno));
3638 goto strict_unlock;
3641 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3643 SSVAL(req->outbuf,smb_vwv0,nread);
3644 SSVAL(req->outbuf,smb_vwv5,nread+3);
3645 SCVAL(smb_buf(req->outbuf),0,1);
3646 SSVAL(smb_buf(req->outbuf),1,nread);
3648 DEBUG(3, ("read %s num=%d nread=%d\n",
3649 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3651 strict_unlock:
3652 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3654 END_PROFILE(SMBread);
3655 return;
3658 /****************************************************************************
3659 Setup readX header.
3660 ****************************************************************************/
3662 static int setup_readX_header(struct smb_request *req, char *outbuf,
3663 size_t smb_maxcnt)
3665 int outsize;
3667 outsize = srv_set_message(outbuf,12,smb_maxcnt,False);
3669 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3671 SCVAL(outbuf,smb_vwv0,0xFF);
3672 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3673 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3674 SSVAL(outbuf,smb_vwv6,
3675 (smb_wct - 4) /* offset from smb header to wct */
3676 + 1 /* the wct field */
3677 + 12 * sizeof(uint16_t) /* vwv */
3678 + 2); /* the buflen field */
3679 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3680 SSVAL(outbuf,smb_vwv11,smb_maxcnt);
3681 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3682 _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
3683 return outsize;
3686 /****************************************************************************
3687 Reply to a read and X - possibly using sendfile.
3688 ****************************************************************************/
3690 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3691 files_struct *fsp, off_t startpos,
3692 size_t smb_maxcnt)
3694 ssize_t nread = -1;
3695 struct lock_struct lock;
3696 int saved_errno = 0;
3698 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3699 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3700 &lock);
3702 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3703 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3704 return;
3708 * We can only use sendfile on a non-chained packet
3709 * but we can use on a non-oplocked file. tridge proved this
3710 * on a train in Germany :-). JRA.
3713 if (!req_is_in_chain(req) &&
3714 !req->encrypted &&
3715 (fsp->base_fsp == NULL) &&
3716 (fsp->wcp == NULL) &&
3717 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3718 uint8 headerbuf[smb_size + 12 * 2];
3719 DATA_BLOB header;
3721 if(fsp_stat(fsp) == -1) {
3722 reply_nterror(req, map_nt_error_from_unix(errno));
3723 goto strict_unlock;
3726 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3727 (startpos > fsp->fsp_name->st.st_ex_size) ||
3728 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3730 * We already know that we would do a short read, so don't
3731 * try the sendfile() path.
3733 goto nosendfile_read;
3737 * Set up the packet header before send. We
3738 * assume here the sendfile will work (get the
3739 * correct amount of data).
3742 header = data_blob_const(headerbuf, sizeof(headerbuf));
3744 construct_reply_common_req(req, (char *)headerbuf);
3745 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3747 nread = SMB_VFS_SENDFILE(req->sconn->sock, fsp, &header,
3748 startpos, smb_maxcnt);
3749 if (nread == -1) {
3750 /* Returning ENOSYS means no data at all was sent.
3751 Do this as a normal read. */
3752 if (errno == ENOSYS) {
3753 goto normal_read;
3757 * Special hack for broken Linux with no working sendfile. If we
3758 * return EINTR we sent the header but not the rest of the data.
3759 * Fake this up by doing read/write calls.
3762 if (errno == EINTR) {
3763 /* Ensure we don't do this again. */
3764 set_use_sendfile(SNUM(conn), False);
3765 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3766 nread = fake_sendfile(fsp, startpos,
3767 smb_maxcnt);
3768 if (nread == -1) {
3769 DEBUG(0,("send_file_readX: "
3770 "fake_sendfile failed for "
3771 "file %s (%s).\n",
3772 fsp_str_dbg(fsp),
3773 strerror(errno)));
3774 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3776 DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
3777 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3778 /* No outbuf here means successful sendfile. */
3779 goto strict_unlock;
3782 DEBUG(0,("send_file_readX: sendfile failed for file "
3783 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3784 strerror(errno)));
3785 exit_server_cleanly("send_file_readX sendfile failed");
3786 } else if (nread == 0) {
3788 * Some sendfile implementations return 0 to indicate
3789 * that there was a short read, but nothing was
3790 * actually written to the socket. In this case,
3791 * fallback to the normal read path so the header gets
3792 * the correct byte count.
3794 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
3795 "falling back to the normal read: %s\n",
3796 fsp_str_dbg(fsp)));
3797 goto normal_read;
3800 DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n",
3801 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3803 /* Deal with possible short send. */
3804 if (nread != smb_maxcnt + sizeof(headerbuf)) {
3805 sendfile_short_send(fsp, nread, sizeof(headerbuf), smb_maxcnt);
3807 /* No outbuf here means successful sendfile. */
3808 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
3809 SMB_PERFCOUNT_END(&req->pcd);
3810 goto strict_unlock;
3813 normal_read:
3815 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3816 uint8 headerbuf[smb_size + 2*12];
3818 construct_reply_common_req(req, (char *)headerbuf);
3819 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3821 /* Send out the header. */
3822 if (write_data(req->sconn->sock, (char *)headerbuf,
3823 sizeof(headerbuf)) != sizeof(headerbuf)) {
3825 char addr[INET6_ADDRSTRLEN];
3827 * Try and give an error message saying what
3828 * client failed.
3830 DEBUG(0, ("write_data failed for client %s. "
3831 "Error %s\n",
3832 get_peer_addr(req->sconn->sock, addr,
3833 sizeof(addr)),
3834 strerror(errno)));
3836 DEBUG(0,("send_file_readX: write_data failed for file "
3837 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3838 strerror(errno)));
3839 exit_server_cleanly("send_file_readX sendfile failed");
3841 nread = fake_sendfile(fsp, startpos, smb_maxcnt);
3842 if (nread == -1) {
3843 DEBUG(0,("send_file_readX: fake_sendfile failed for "
3844 "file %s (%s).\n", fsp_str_dbg(fsp),
3845 strerror(errno)));
3846 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3848 goto strict_unlock;
3851 nosendfile_read:
3853 reply_outbuf(req, 12, smb_maxcnt);
3854 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
3855 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
3857 nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt);
3858 saved_errno = errno;
3860 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3862 if (nread < 0) {
3863 reply_nterror(req, map_nt_error_from_unix(saved_errno));
3864 return;
3867 setup_readX_header(req, (char *)req->outbuf, nread);
3869 DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
3870 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3871 return;
3873 strict_unlock:
3874 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3875 TALLOC_FREE(req->outbuf);
3876 return;
3879 /****************************************************************************
3880 Work out how much space we have for a read return.
3881 ****************************************************************************/
3883 static size_t calc_max_read_pdu(const struct smb_request *req)
3885 if (req->sconn->conn->protocol < PROTOCOL_NT1) {
3886 return req->sconn->smb1.sessions.max_send;
3889 if (!lp_large_readwrite()) {
3890 return req->sconn->smb1.sessions.max_send;
3893 if (req_is_in_chain(req)) {
3894 return req->sconn->smb1.sessions.max_send;
3897 if (req->encrypted) {
3899 * Don't take encrypted traffic up to the
3900 * limit. There are padding considerations
3901 * that make that tricky.
3903 return req->sconn->smb1.sessions.max_send;
3906 if (srv_is_signing_active(req->sconn)) {
3907 return 0x1FFFF;
3910 if (!lp_unix_extensions()) {
3911 return 0x1FFFF;
3915 * We can do ultra-large POSIX reads.
3917 return 0xFFFFFF;
3920 /****************************************************************************
3921 Calculate how big a read can be. Copes with all clients. It's always
3922 safe to return a short read - Windows does this.
3923 ****************************************************************************/
3925 static size_t calc_read_size(const struct smb_request *req,
3926 size_t upper_size,
3927 size_t lower_size)
3929 size_t max_pdu = calc_max_read_pdu(req);
3930 size_t total_size = 0;
3931 size_t hdr_len = MIN_SMB_SIZE + VWV(12);
3932 size_t max_len = max_pdu - hdr_len;
3935 * Windows explicitly ignores upper size of 0xFFFF.
3936 * See [MS-SMB].pdf <26> Section 2.2.4.2.1:
3937 * We must do the same as these will never fit even in
3938 * an extended size NetBIOS packet.
3940 if (upper_size == 0xFFFF) {
3941 upper_size = 0;
3944 if (req->sconn->conn->protocol < PROTOCOL_NT1) {
3945 upper_size = 0;
3948 total_size = ((upper_size<<16) | lower_size);
3951 * LARGE_READX test shows it's always safe to return
3952 * a short read. Windows does so.
3954 return MIN(total_size, max_len);
3957 /****************************************************************************
3958 Reply to a read and X.
3959 ****************************************************************************/
3961 void reply_read_and_X(struct smb_request *req)
3963 connection_struct *conn = req->conn;
3964 files_struct *fsp;
3965 off_t startpos;
3966 size_t smb_maxcnt;
3967 size_t upper_size;
3968 bool big_readX = False;
3969 #if 0
3970 size_t smb_mincnt = SVAL(req->vwv+6, 0);
3971 #endif
3973 START_PROFILE(SMBreadX);
3975 if ((req->wct != 10) && (req->wct != 12)) {
3976 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3977 return;
3980 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
3981 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3982 smb_maxcnt = SVAL(req->vwv+5, 0);
3984 /* If it's an IPC, pass off the pipe handler. */
3985 if (IS_IPC(conn)) {
3986 reply_pipe_read_and_X(req);
3987 END_PROFILE(SMBreadX);
3988 return;
3991 if (!check_fsp(conn, req, fsp)) {
3992 END_PROFILE(SMBreadX);
3993 return;
3996 if (!CHECK_READ(fsp,req)) {
3997 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3998 END_PROFILE(SMBreadX);
3999 return;
4002 upper_size = SVAL(req->vwv+7, 0);
4003 smb_maxcnt = calc_read_size(req, upper_size, smb_maxcnt);
4004 if (smb_maxcnt > (0x1FFFF - (MIN_SMB_SIZE + VWV(12)))) {
4006 * This is a heuristic to avoid keeping large
4007 * outgoing buffers around over long-lived aio
4008 * requests.
4010 big_readX = True;
4013 if (req->wct == 12) {
4015 * This is a large offset (64 bit) read.
4017 startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
4021 if (!big_readX) {
4022 NTSTATUS status = schedule_aio_read_and_X(conn,
4023 req,
4024 fsp,
4025 startpos,
4026 smb_maxcnt);
4027 if (NT_STATUS_IS_OK(status)) {
4028 /* Read scheduled - we're done. */
4029 goto out;
4031 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4032 /* Real error - report to client. */
4033 END_PROFILE(SMBreadX);
4034 reply_nterror(req, status);
4035 return;
4037 /* NT_STATUS_RETRY - fall back to sync read. */
4040 smbd_lock_socket(req->sconn);
4041 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
4042 smbd_unlock_socket(req->sconn);
4044 out:
4045 END_PROFILE(SMBreadX);
4046 return;
4049 /****************************************************************************
4050 Error replies to writebraw must have smb_wct == 1. Fix this up.
4051 ****************************************************************************/
4053 void error_to_writebrawerr(struct smb_request *req)
4055 uint8 *old_outbuf = req->outbuf;
4057 reply_outbuf(req, 1, 0);
4059 memcpy(req->outbuf, old_outbuf, smb_size);
4060 TALLOC_FREE(old_outbuf);
4063 /****************************************************************************
4064 Read 4 bytes of a smb packet and return the smb length of the packet.
4065 Store the result in the buffer. This version of the function will
4066 never return a session keepalive (length of zero).
4067 Timeout is in milliseconds.
4068 ****************************************************************************/
4070 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
4071 size_t *len)
4073 uint8_t msgtype = NBSSkeepalive;
4075 while (msgtype == NBSSkeepalive) {
4076 NTSTATUS status;
4078 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
4079 len);
4080 if (!NT_STATUS_IS_OK(status)) {
4081 char addr[INET6_ADDRSTRLEN];
4082 /* Try and give an error message
4083 * saying what client failed. */
4084 DEBUG(0, ("read_fd_with_timeout failed for "
4085 "client %s read error = %s.\n",
4086 get_peer_addr(fd,addr,sizeof(addr)),
4087 nt_errstr(status)));
4088 return status;
4091 msgtype = CVAL(inbuf, 0);
4094 DEBUG(10,("read_smb_length: got smb length of %lu\n",
4095 (unsigned long)len));
4097 return NT_STATUS_OK;
4100 /****************************************************************************
4101 Reply to a writebraw (core+ or LANMAN1.0 protocol).
4102 ****************************************************************************/
4104 void reply_writebraw(struct smb_request *req)
4106 connection_struct *conn = req->conn;
4107 char *buf = NULL;
4108 ssize_t nwritten=0;
4109 ssize_t total_written=0;
4110 size_t numtowrite=0;
4111 size_t tcount;
4112 off_t startpos;
4113 const char *data=NULL;
4114 bool write_through;
4115 files_struct *fsp;
4116 struct lock_struct lock;
4117 NTSTATUS status;
4119 START_PROFILE(SMBwritebraw);
4122 * If we ever reply with an error, it must have the SMB command
4123 * type of SMBwritec, not SMBwriteBraw, as this tells the client
4124 * we're finished.
4126 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
4128 if (srv_is_signing_active(req->sconn)) {
4129 END_PROFILE(SMBwritebraw);
4130 exit_server_cleanly("reply_writebraw: SMB signing is active - "
4131 "raw reads/writes are disallowed.");
4134 if (req->wct < 12) {
4135 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4136 error_to_writebrawerr(req);
4137 END_PROFILE(SMBwritebraw);
4138 return;
4141 if (req->sconn->smb1.echo_handler.trusted_fde) {
4142 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
4143 "'async smb echo handler = yes'\n"));
4144 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
4145 error_to_writebrawerr(req);
4146 END_PROFILE(SMBwritebraw);
4147 return;
4150 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4151 if (!check_fsp(conn, req, fsp)) {
4152 error_to_writebrawerr(req);
4153 END_PROFILE(SMBwritebraw);
4154 return;
4157 if (!CHECK_WRITE(fsp)) {
4158 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4159 error_to_writebrawerr(req);
4160 END_PROFILE(SMBwritebraw);
4161 return;
4164 tcount = IVAL(req->vwv+1, 0);
4165 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4166 write_through = BITSETW(req->vwv+7,0);
4168 /* We have to deal with slightly different formats depending
4169 on whether we are using the core+ or lanman1.0 protocol */
4171 if(get_Protocol() <= PROTOCOL_COREPLUS) {
4172 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
4173 data = smb_buf_const(req->inbuf);
4174 } else {
4175 numtowrite = SVAL(req->vwv+10, 0);
4176 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
4179 /* Ensure we don't write bytes past the end of this packet. */
4180 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
4181 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4182 error_to_writebrawerr(req);
4183 END_PROFILE(SMBwritebraw);
4184 return;
4187 if (!fsp->print_file) {
4188 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4189 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4190 &lock);
4192 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4193 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4194 error_to_writebrawerr(req);
4195 END_PROFILE(SMBwritebraw);
4196 return;
4200 if (numtowrite>0) {
4201 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4204 DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d "
4205 "wrote=%d sync=%d\n",
4206 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4207 (int)nwritten, (int)write_through));
4209 if (nwritten < (ssize_t)numtowrite) {
4210 reply_nterror(req, NT_STATUS_DISK_FULL);
4211 error_to_writebrawerr(req);
4212 goto strict_unlock;
4215 total_written = nwritten;
4217 /* Allocate a buffer of 64k + length. */
4218 buf = talloc_array(NULL, char, 65540);
4219 if (!buf) {
4220 reply_nterror(req, NT_STATUS_NO_MEMORY);
4221 error_to_writebrawerr(req);
4222 goto strict_unlock;
4225 /* Return a SMBwritebraw message to the redirector to tell
4226 * it to send more bytes */
4228 memcpy(buf, req->inbuf, smb_size);
4229 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4230 SCVAL(buf,smb_com,SMBwritebraw);
4231 SSVALS(buf,smb_vwv0,0xFFFF);
4232 show_msg(buf);
4233 if (!srv_send_smb(req->sconn,
4234 buf,
4235 false, 0, /* no signing */
4236 IS_CONN_ENCRYPTED(conn),
4237 &req->pcd)) {
4238 exit_server_cleanly("reply_writebraw: srv_send_smb "
4239 "failed.");
4242 /* Now read the raw data into the buffer and write it */
4243 status = read_smb_length(req->sconn->sock, buf, SMB_SECONDARY_WAIT,
4244 &numtowrite);
4245 if (!NT_STATUS_IS_OK(status)) {
4246 exit_server_cleanly("secondary writebraw failed");
4249 /* Set up outbuf to return the correct size */
4250 reply_outbuf(req, 1, 0);
4252 if (numtowrite != 0) {
4254 if (numtowrite > 0xFFFF) {
4255 DEBUG(0,("reply_writebraw: Oversize secondary write "
4256 "raw requested (%u). Terminating\n",
4257 (unsigned int)numtowrite ));
4258 exit_server_cleanly("secondary writebraw failed");
4261 if (tcount > nwritten+numtowrite) {
4262 DEBUG(3,("reply_writebraw: Client overestimated the "
4263 "write %d %d %d\n",
4264 (int)tcount,(int)nwritten,(int)numtowrite));
4267 status = read_data(req->sconn->sock, buf+4, numtowrite);
4269 if (!NT_STATUS_IS_OK(status)) {
4270 char addr[INET6_ADDRSTRLEN];
4271 /* Try and give an error message
4272 * saying what client failed. */
4273 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4274 "raw read failed (%s) for client %s. "
4275 "Terminating\n", nt_errstr(status),
4276 get_peer_addr(req->sconn->sock, addr,
4277 sizeof(addr))));
4278 exit_server_cleanly("secondary writebraw failed");
4281 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4282 if (nwritten == -1) {
4283 TALLOC_FREE(buf);
4284 reply_nterror(req, map_nt_error_from_unix(errno));
4285 error_to_writebrawerr(req);
4286 goto strict_unlock;
4289 if (nwritten < (ssize_t)numtowrite) {
4290 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4291 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4294 if (nwritten > 0) {
4295 total_written += nwritten;
4299 TALLOC_FREE(buf);
4300 SSVAL(req->outbuf,smb_vwv0,total_written);
4302 status = sync_file(conn, fsp, write_through);
4303 if (!NT_STATUS_IS_OK(status)) {
4304 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4305 fsp_str_dbg(fsp), nt_errstr(status)));
4306 reply_nterror(req, status);
4307 error_to_writebrawerr(req);
4308 goto strict_unlock;
4311 DEBUG(3,("reply_writebraw: secondart write %s start=%.0f num=%d "
4312 "wrote=%d\n",
4313 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4314 (int)total_written));
4316 if (!fsp->print_file) {
4317 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4320 /* We won't return a status if write through is not selected - this
4321 * follows what WfWg does */
4322 END_PROFILE(SMBwritebraw);
4324 if (!write_through && total_written==tcount) {
4326 #if RABBIT_PELLET_FIX
4328 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4329 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4330 * JRA.
4332 if (!send_keepalive(req->sconn->sock)) {
4333 exit_server_cleanly("reply_writebraw: send of "
4334 "keepalive failed");
4336 #endif
4337 TALLOC_FREE(req->outbuf);
4339 return;
4341 strict_unlock:
4342 if (!fsp->print_file) {
4343 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4346 END_PROFILE(SMBwritebraw);
4347 return;
4350 #undef DBGC_CLASS
4351 #define DBGC_CLASS DBGC_LOCKING
4353 /****************************************************************************
4354 Reply to a writeunlock (core+).
4355 ****************************************************************************/
4357 void reply_writeunlock(struct smb_request *req)
4359 connection_struct *conn = req->conn;
4360 ssize_t nwritten = -1;
4361 size_t numtowrite;
4362 off_t startpos;
4363 const char *data;
4364 NTSTATUS status = NT_STATUS_OK;
4365 files_struct *fsp;
4366 struct lock_struct lock;
4367 int saved_errno = 0;
4369 START_PROFILE(SMBwriteunlock);
4371 if (req->wct < 5) {
4372 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4373 END_PROFILE(SMBwriteunlock);
4374 return;
4377 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4379 if (!check_fsp(conn, req, fsp)) {
4380 END_PROFILE(SMBwriteunlock);
4381 return;
4384 if (!CHECK_WRITE(fsp)) {
4385 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4386 END_PROFILE(SMBwriteunlock);
4387 return;
4390 numtowrite = SVAL(req->vwv+1, 0);
4391 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4392 data = (const char *)req->buf + 3;
4394 if (!fsp->print_file && numtowrite > 0) {
4395 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4396 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4397 &lock);
4399 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4400 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4401 END_PROFILE(SMBwriteunlock);
4402 return;
4406 /* The special X/Open SMB protocol handling of
4407 zero length writes is *NOT* done for
4408 this call */
4409 if(numtowrite == 0) {
4410 nwritten = 0;
4411 } else {
4412 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4413 saved_errno = errno;
4416 status = sync_file(conn, fsp, False /* write through */);
4417 if (!NT_STATUS_IS_OK(status)) {
4418 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4419 fsp_str_dbg(fsp), nt_errstr(status)));
4420 reply_nterror(req, status);
4421 goto strict_unlock;
4424 if(nwritten < 0) {
4425 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4426 goto strict_unlock;
4429 if((nwritten < numtowrite) && (numtowrite != 0)) {
4430 reply_nterror(req, NT_STATUS_DISK_FULL);
4431 goto strict_unlock;
4434 if (numtowrite && !fsp->print_file) {
4435 status = do_unlock(req->sconn->msg_ctx,
4436 fsp,
4437 (uint64_t)req->smbpid,
4438 (uint64_t)numtowrite,
4439 (uint64_t)startpos,
4440 WINDOWS_LOCK);
4442 if (NT_STATUS_V(status)) {
4443 reply_nterror(req, status);
4444 goto strict_unlock;
4448 reply_outbuf(req, 1, 0);
4450 SSVAL(req->outbuf,smb_vwv0,nwritten);
4452 DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
4453 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4455 strict_unlock:
4456 if (numtowrite && !fsp->print_file) {
4457 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4460 END_PROFILE(SMBwriteunlock);
4461 return;
4464 #undef DBGC_CLASS
4465 #define DBGC_CLASS DBGC_ALL
4467 /****************************************************************************
4468 Reply to a write.
4469 ****************************************************************************/
4471 void reply_write(struct smb_request *req)
4473 connection_struct *conn = req->conn;
4474 size_t numtowrite;
4475 ssize_t nwritten = -1;
4476 off_t startpos;
4477 const char *data;
4478 files_struct *fsp;
4479 struct lock_struct lock;
4480 NTSTATUS status;
4481 int saved_errno = 0;
4483 START_PROFILE(SMBwrite);
4485 if (req->wct < 5) {
4486 END_PROFILE(SMBwrite);
4487 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4488 return;
4491 /* If it's an IPC, pass off the pipe handler. */
4492 if (IS_IPC(conn)) {
4493 reply_pipe_write(req);
4494 END_PROFILE(SMBwrite);
4495 return;
4498 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4500 if (!check_fsp(conn, req, fsp)) {
4501 END_PROFILE(SMBwrite);
4502 return;
4505 if (!CHECK_WRITE(fsp)) {
4506 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4507 END_PROFILE(SMBwrite);
4508 return;
4511 numtowrite = SVAL(req->vwv+1, 0);
4512 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4513 data = (const char *)req->buf + 3;
4515 if (!fsp->print_file) {
4516 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4517 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4518 &lock);
4520 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4521 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4522 END_PROFILE(SMBwrite);
4523 return;
4528 * X/Open SMB protocol says that if smb_vwv1 is
4529 * zero then the file size should be extended or
4530 * truncated to the size given in smb_vwv[2-3].
4533 if(numtowrite == 0) {
4535 * This is actually an allocate call, and set EOF. JRA.
4537 nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
4538 if (nwritten < 0) {
4539 reply_nterror(req, NT_STATUS_DISK_FULL);
4540 goto strict_unlock;
4542 nwritten = vfs_set_filelen(fsp, (off_t)startpos);
4543 if (nwritten < 0) {
4544 reply_nterror(req, NT_STATUS_DISK_FULL);
4545 goto strict_unlock;
4547 trigger_write_time_update_immediate(fsp);
4548 } else {
4549 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4552 status = sync_file(conn, fsp, False);
4553 if (!NT_STATUS_IS_OK(status)) {
4554 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4555 fsp_str_dbg(fsp), nt_errstr(status)));
4556 reply_nterror(req, status);
4557 goto strict_unlock;
4560 if(nwritten < 0) {
4561 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4562 goto strict_unlock;
4565 if((nwritten == 0) && (numtowrite != 0)) {
4566 reply_nterror(req, NT_STATUS_DISK_FULL);
4567 goto strict_unlock;
4570 reply_outbuf(req, 1, 0);
4572 SSVAL(req->outbuf,smb_vwv0,nwritten);
4574 if (nwritten < (ssize_t)numtowrite) {
4575 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4576 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4579 DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4581 strict_unlock:
4582 if (!fsp->print_file) {
4583 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4586 END_PROFILE(SMBwrite);
4587 return;
4590 /****************************************************************************
4591 Ensure a buffer is a valid writeX for recvfile purposes.
4592 ****************************************************************************/
4594 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4595 (2*14) + /* word count (including bcc) */ \
4596 1 /* pad byte */)
4598 bool is_valid_writeX_buffer(struct smbd_server_connection *sconn,
4599 const uint8_t *inbuf)
4601 size_t numtowrite;
4602 unsigned int doff = 0;
4603 size_t len = smb_len_large(inbuf);
4604 uint16_t fnum;
4605 struct smbXsrv_open *op = NULL;
4606 struct files_struct *fsp = NULL;
4607 NTSTATUS status;
4609 if (is_encrypted_packet(sconn, inbuf)) {
4610 /* Can't do this on encrypted
4611 * connections. */
4612 return false;
4615 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4616 return false;
4619 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4620 CVAL(inbuf,smb_wct) != 14) {
4621 DEBUG(10,("is_valid_writeX_buffer: chained or "
4622 "invalid word length.\n"));
4623 return false;
4626 fnum = SVAL(inbuf, smb_vwv2);
4627 status = smb1srv_open_lookup(sconn->conn,
4628 fnum,
4629 0, /* now */
4630 &op);
4631 if (!NT_STATUS_IS_OK(status)) {
4632 DEBUG(10,("is_valid_writeX_buffer: bad fnum\n"));
4633 return false;
4635 fsp = op->compat;
4636 if (fsp == NULL) {
4637 DEBUG(10,("is_valid_writeX_buffer: bad fsp\n"));
4638 return false;
4640 if (fsp->conn == NULL) {
4641 DEBUG(10,("is_valid_writeX_buffer: bad fsp->conn\n"));
4642 return false;
4645 if (IS_IPC(fsp->conn)) {
4646 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4647 return false;
4649 if (IS_PRINT(fsp->conn)) {
4650 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4651 return false;
4653 doff = SVAL(inbuf,smb_vwv11);
4655 numtowrite = SVAL(inbuf,smb_vwv10);
4657 if (len > doff && len - doff > 0xFFFF) {
4658 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4661 if (numtowrite == 0) {
4662 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4663 return false;
4666 /* Ensure the sizes match up. */
4667 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4668 /* no pad byte...old smbclient :-( */
4669 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4670 (unsigned int)doff,
4671 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4672 return false;
4675 if (len - doff != numtowrite) {
4676 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4677 "len = %u, doff = %u, numtowrite = %u\n",
4678 (unsigned int)len,
4679 (unsigned int)doff,
4680 (unsigned int)numtowrite ));
4681 return false;
4684 DEBUG(10,("is_valid_writeX_buffer: true "
4685 "len = %u, doff = %u, numtowrite = %u\n",
4686 (unsigned int)len,
4687 (unsigned int)doff,
4688 (unsigned int)numtowrite ));
4690 return true;
4693 /****************************************************************************
4694 Reply to a write and X.
4695 ****************************************************************************/
4697 void reply_write_and_X(struct smb_request *req)
4699 connection_struct *conn = req->conn;
4700 files_struct *fsp;
4701 struct lock_struct lock;
4702 off_t startpos;
4703 size_t numtowrite;
4704 bool write_through;
4705 ssize_t nwritten;
4706 unsigned int smb_doff;
4707 unsigned int smblen;
4708 const char *data;
4709 NTSTATUS status;
4710 int saved_errno = 0;
4712 START_PROFILE(SMBwriteX);
4714 if ((req->wct != 12) && (req->wct != 14)) {
4715 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4716 goto out;
4719 numtowrite = SVAL(req->vwv+10, 0);
4720 smb_doff = SVAL(req->vwv+11, 0);
4721 smblen = smb_len(req->inbuf);
4723 if (req->unread_bytes > 0xFFFF ||
4724 (smblen > smb_doff &&
4725 smblen - smb_doff > 0xFFFF)) {
4726 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
4729 if (req->unread_bytes) {
4730 /* Can't do a recvfile write on IPC$ */
4731 if (IS_IPC(conn)) {
4732 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4733 goto out;
4735 if (numtowrite != req->unread_bytes) {
4736 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4737 goto out;
4739 } else {
4740 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4741 smb_doff + numtowrite > smblen) {
4742 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4743 goto out;
4747 /* If it's an IPC, pass off the pipe handler. */
4748 if (IS_IPC(conn)) {
4749 if (req->unread_bytes) {
4750 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4751 goto out;
4753 reply_pipe_write_and_X(req);
4754 goto out;
4757 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4758 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4759 write_through = BITSETW(req->vwv+7,0);
4761 if (!check_fsp(conn, req, fsp)) {
4762 goto out;
4765 if (!CHECK_WRITE(fsp)) {
4766 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4767 goto out;
4770 data = smb_base(req->inbuf) + smb_doff;
4772 if(req->wct == 14) {
4774 * This is a large offset (64 bit) write.
4776 startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
4780 /* X/Open SMB protocol says that, unlike SMBwrite
4781 if the length is zero then NO truncation is
4782 done, just a write of zero. To truncate a file,
4783 use SMBwrite. */
4785 if(numtowrite == 0) {
4786 nwritten = 0;
4787 } else {
4788 if (req->unread_bytes == 0) {
4789 status = schedule_aio_write_and_X(conn,
4790 req,
4791 fsp,
4792 data,
4793 startpos,
4794 numtowrite);
4796 if (NT_STATUS_IS_OK(status)) {
4797 /* write scheduled - we're done. */
4798 goto out;
4800 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4801 /* Real error - report to client. */
4802 reply_nterror(req, status);
4803 goto out;
4805 /* NT_STATUS_RETRY - fall through to sync write. */
4808 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4809 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4810 &lock);
4812 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4813 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4814 goto out;
4817 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4818 saved_errno = errno;
4820 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4823 if(nwritten < 0) {
4824 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4825 goto out;
4828 if((nwritten == 0) && (numtowrite != 0)) {
4829 reply_nterror(req, NT_STATUS_DISK_FULL);
4830 goto out;
4833 reply_outbuf(req, 6, 0);
4834 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
4835 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
4836 SSVAL(req->outbuf,smb_vwv2,nwritten);
4837 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4839 DEBUG(3,("writeX %s num=%d wrote=%d\n",
4840 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4842 status = sync_file(conn, fsp, write_through);
4843 if (!NT_STATUS_IS_OK(status)) {
4844 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4845 fsp_str_dbg(fsp), nt_errstr(status)));
4846 reply_nterror(req, status);
4847 goto out;
4850 END_PROFILE(SMBwriteX);
4851 return;
4853 out:
4854 if (req->unread_bytes) {
4855 /* writeX failed. drain socket. */
4856 if (drain_socket(req->sconn->sock, req->unread_bytes) !=
4857 req->unread_bytes) {
4858 smb_panic("failed to drain pending bytes");
4860 req->unread_bytes = 0;
4863 END_PROFILE(SMBwriteX);
4864 return;
4867 /****************************************************************************
4868 Reply to a lseek.
4869 ****************************************************************************/
4871 void reply_lseek(struct smb_request *req)
4873 connection_struct *conn = req->conn;
4874 off_t startpos;
4875 off_t res= -1;
4876 int mode,umode;
4877 files_struct *fsp;
4879 START_PROFILE(SMBlseek);
4881 if (req->wct < 4) {
4882 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4883 END_PROFILE(SMBlseek);
4884 return;
4887 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4889 if (!check_fsp(conn, req, fsp)) {
4890 return;
4893 flush_write_cache(fsp, SAMBA_SEEK_FLUSH);
4895 mode = SVAL(req->vwv+1, 0) & 3;
4896 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4897 startpos = (off_t)IVALS(req->vwv+2, 0);
4899 switch (mode) {
4900 case 0:
4901 umode = SEEK_SET;
4902 res = startpos;
4903 break;
4904 case 1:
4905 umode = SEEK_CUR;
4906 res = fsp->fh->pos + startpos;
4907 break;
4908 case 2:
4909 umode = SEEK_END;
4910 break;
4911 default:
4912 umode = SEEK_SET;
4913 res = startpos;
4914 break;
4917 if (umode == SEEK_END) {
4918 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
4919 if(errno == EINVAL) {
4920 off_t current_pos = startpos;
4922 if(fsp_stat(fsp) == -1) {
4923 reply_nterror(req,
4924 map_nt_error_from_unix(errno));
4925 END_PROFILE(SMBlseek);
4926 return;
4929 current_pos += fsp->fsp_name->st.st_ex_size;
4930 if(current_pos < 0)
4931 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
4935 if(res == -1) {
4936 reply_nterror(req, map_nt_error_from_unix(errno));
4937 END_PROFILE(SMBlseek);
4938 return;
4942 fsp->fh->pos = res;
4944 reply_outbuf(req, 2, 0);
4945 SIVAL(req->outbuf,smb_vwv0,res);
4947 DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n",
4948 fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode));
4950 END_PROFILE(SMBlseek);
4951 return;
4954 /****************************************************************************
4955 Reply to a flush.
4956 ****************************************************************************/
4958 void reply_flush(struct smb_request *req)
4960 connection_struct *conn = req->conn;
4961 uint16 fnum;
4962 files_struct *fsp;
4964 START_PROFILE(SMBflush);
4966 if (req->wct < 1) {
4967 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4968 return;
4971 fnum = SVAL(req->vwv+0, 0);
4972 fsp = file_fsp(req, fnum);
4974 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
4975 return;
4978 if (!fsp) {
4979 file_sync_all(conn);
4980 } else {
4981 NTSTATUS status = sync_file(conn, fsp, True);
4982 if (!NT_STATUS_IS_OK(status)) {
4983 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
4984 fsp_str_dbg(fsp), nt_errstr(status)));
4985 reply_nterror(req, status);
4986 END_PROFILE(SMBflush);
4987 return;
4991 reply_outbuf(req, 0, 0);
4993 DEBUG(3,("flush\n"));
4994 END_PROFILE(SMBflush);
4995 return;
4998 /****************************************************************************
4999 Reply to a exit.
5000 conn POINTER CAN BE NULL HERE !
5001 ****************************************************************************/
5003 void reply_exit(struct smb_request *req)
5005 START_PROFILE(SMBexit);
5007 file_close_pid(req->sconn, req->smbpid, req->vuid);
5009 reply_outbuf(req, 0, 0);
5011 DEBUG(3,("exit\n"));
5013 END_PROFILE(SMBexit);
5014 return;
5017 struct reply_close_state {
5018 files_struct *fsp;
5019 struct smb_request *smbreq;
5022 static void do_smb1_close(struct tevent_req *req);
5024 void reply_close(struct smb_request *req)
5026 connection_struct *conn = req->conn;
5027 NTSTATUS status = NT_STATUS_OK;
5028 files_struct *fsp = NULL;
5029 START_PROFILE(SMBclose);
5031 if (req->wct < 3) {
5032 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5033 END_PROFILE(SMBclose);
5034 return;
5037 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5040 * We can only use check_fsp if we know it's not a directory.
5043 if (!check_fsp_open(conn, req, fsp)) {
5044 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
5045 END_PROFILE(SMBclose);
5046 return;
5049 DEBUG(3, ("Close %s fd=%d %s (numopen=%d)\n",
5050 fsp->is_directory ? "directory" : "file",
5051 fsp->fh->fd, fsp_fnum_dbg(fsp),
5052 conn->num_files_open));
5054 if (!fsp->is_directory) {
5055 time_t t;
5058 * Take care of any time sent in the close.
5061 t = srv_make_unix_date3(req->vwv+1);
5062 set_close_write_time(fsp, convert_time_t_to_timespec(t));
5065 if (fsp->num_aio_requests != 0) {
5067 struct reply_close_state *state;
5069 DEBUG(10, ("closing with aio %u requests pending\n",
5070 fsp->num_aio_requests));
5073 * We depend on the aio_extra destructor to take care of this
5074 * close request once fsp->num_aio_request drops to 0.
5077 fsp->deferred_close = tevent_wait_send(
5078 fsp, fsp->conn->sconn->ev_ctx);
5079 if (fsp->deferred_close == NULL) {
5080 status = NT_STATUS_NO_MEMORY;
5081 goto done;
5084 state = talloc(fsp, struct reply_close_state);
5085 if (state == NULL) {
5086 TALLOC_FREE(fsp->deferred_close);
5087 status = NT_STATUS_NO_MEMORY;
5088 goto done;
5090 state->fsp = fsp;
5091 state->smbreq = talloc_move(fsp, &req);
5092 tevent_req_set_callback(fsp->deferred_close, do_smb1_close,
5093 state);
5094 END_PROFILE(SMBclose);
5095 return;
5099 * close_file() returns the unix errno if an error was detected on
5100 * close - normally this is due to a disk full error. If not then it
5101 * was probably an I/O error.
5104 status = close_file(req, fsp, NORMAL_CLOSE);
5105 done:
5106 if (!NT_STATUS_IS_OK(status)) {
5107 reply_nterror(req, status);
5108 END_PROFILE(SMBclose);
5109 return;
5112 reply_outbuf(req, 0, 0);
5113 END_PROFILE(SMBclose);
5114 return;
5117 static void do_smb1_close(struct tevent_req *req)
5119 struct reply_close_state *state = tevent_req_callback_data(
5120 req, struct reply_close_state);
5121 struct smb_request *smbreq;
5122 NTSTATUS status;
5123 int ret;
5125 ret = tevent_wait_recv(req);
5126 TALLOC_FREE(req);
5127 if (ret != 0) {
5128 DEBUG(10, ("tevent_wait_recv returned %s\n",
5129 strerror(ret)));
5131 * Continue anyway, this should never happen
5136 * fsp->smb2_close_request right now is a talloc grandchild of
5137 * fsp. When we close_file(fsp), it would go with it. No chance to
5138 * reply...
5140 smbreq = talloc_move(talloc_tos(), &state->smbreq);
5142 status = close_file(smbreq, state->fsp, NORMAL_CLOSE);
5143 if (NT_STATUS_IS_OK(status)) {
5144 reply_outbuf(smbreq, 0, 0);
5145 } else {
5146 reply_nterror(smbreq, status);
5148 if (!srv_send_smb(smbreq->sconn,
5149 (char *)smbreq->outbuf,
5150 true,
5151 smbreq->seqnum+1,
5152 IS_CONN_ENCRYPTED(smbreq->conn)||smbreq->encrypted,
5153 NULL)) {
5154 exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
5155 "failed.");
5157 TALLOC_FREE(smbreq);
5160 /****************************************************************************
5161 Reply to a writeclose (Core+ protocol).
5162 ****************************************************************************/
5164 void reply_writeclose(struct smb_request *req)
5166 connection_struct *conn = req->conn;
5167 size_t numtowrite;
5168 ssize_t nwritten = -1;
5169 NTSTATUS close_status = NT_STATUS_OK;
5170 off_t startpos;
5171 const char *data;
5172 struct timespec mtime;
5173 files_struct *fsp;
5174 struct lock_struct lock;
5176 START_PROFILE(SMBwriteclose);
5178 if (req->wct < 6) {
5179 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5180 END_PROFILE(SMBwriteclose);
5181 return;
5184 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5186 if (!check_fsp(conn, req, fsp)) {
5187 END_PROFILE(SMBwriteclose);
5188 return;
5190 if (!CHECK_WRITE(fsp)) {
5191 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5192 END_PROFILE(SMBwriteclose);
5193 return;
5196 numtowrite = SVAL(req->vwv+1, 0);
5197 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5198 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
5199 data = (const char *)req->buf + 1;
5201 if (fsp->print_file == NULL) {
5202 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5203 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5204 &lock);
5206 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
5207 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5208 END_PROFILE(SMBwriteclose);
5209 return;
5213 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5215 if (fsp->print_file == NULL) {
5216 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
5219 set_close_write_time(fsp, mtime);
5222 * More insanity. W2K only closes the file if writelen > 0.
5223 * JRA.
5226 DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
5227 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
5228 (numtowrite) ? conn->num_files_open - 1 : conn->num_files_open));
5230 if (numtowrite) {
5231 DEBUG(3,("reply_writeclose: zero length write doesn't close "
5232 "file %s\n", fsp_str_dbg(fsp)));
5233 close_status = close_file(req, fsp, NORMAL_CLOSE);
5234 fsp = NULL;
5237 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
5238 reply_nterror(req, NT_STATUS_DISK_FULL);
5239 goto out;
5242 if(!NT_STATUS_IS_OK(close_status)) {
5243 reply_nterror(req, close_status);
5244 goto out;
5247 reply_outbuf(req, 1, 0);
5249 SSVAL(req->outbuf,smb_vwv0,nwritten);
5251 out:
5253 END_PROFILE(SMBwriteclose);
5254 return;
5257 #undef DBGC_CLASS
5258 #define DBGC_CLASS DBGC_LOCKING
5260 /****************************************************************************
5261 Reply to a lock.
5262 ****************************************************************************/
5264 void reply_lock(struct smb_request *req)
5266 connection_struct *conn = req->conn;
5267 uint64_t count,offset;
5268 NTSTATUS status;
5269 files_struct *fsp;
5270 struct byte_range_lock *br_lck = NULL;
5272 START_PROFILE(SMBlock);
5274 if (req->wct < 5) {
5275 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5276 END_PROFILE(SMBlock);
5277 return;
5280 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5282 if (!check_fsp(conn, req, fsp)) {
5283 END_PROFILE(SMBlock);
5284 return;
5287 count = (uint64_t)IVAL(req->vwv+1, 0);
5288 offset = (uint64_t)IVAL(req->vwv+3, 0);
5290 DEBUG(3,("lock fd=%d %s offset=%.0f count=%.0f\n",
5291 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count));
5293 br_lck = do_lock(req->sconn->msg_ctx,
5294 fsp,
5295 (uint64_t)req->smbpid,
5296 count,
5297 offset,
5298 WRITE_LOCK,
5299 WINDOWS_LOCK,
5300 False, /* Non-blocking lock. */
5301 &status,
5302 NULL,
5303 NULL);
5305 TALLOC_FREE(br_lck);
5307 if (NT_STATUS_V(status)) {
5308 reply_nterror(req, status);
5309 END_PROFILE(SMBlock);
5310 return;
5313 reply_outbuf(req, 0, 0);
5315 END_PROFILE(SMBlock);
5316 return;
5319 /****************************************************************************
5320 Reply to a unlock.
5321 ****************************************************************************/
5323 void reply_unlock(struct smb_request *req)
5325 connection_struct *conn = req->conn;
5326 uint64_t count,offset;
5327 NTSTATUS status;
5328 files_struct *fsp;
5330 START_PROFILE(SMBunlock);
5332 if (req->wct < 5) {
5333 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5334 END_PROFILE(SMBunlock);
5335 return;
5338 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5340 if (!check_fsp(conn, req, fsp)) {
5341 END_PROFILE(SMBunlock);
5342 return;
5345 count = (uint64_t)IVAL(req->vwv+1, 0);
5346 offset = (uint64_t)IVAL(req->vwv+3, 0);
5348 status = do_unlock(req->sconn->msg_ctx,
5349 fsp,
5350 (uint64_t)req->smbpid,
5351 count,
5352 offset,
5353 WINDOWS_LOCK);
5355 if (NT_STATUS_V(status)) {
5356 reply_nterror(req, status);
5357 END_PROFILE(SMBunlock);
5358 return;
5361 DEBUG( 3, ( "unlock fd=%d %s offset=%.0f count=%.0f\n",
5362 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count ) );
5364 reply_outbuf(req, 0, 0);
5366 END_PROFILE(SMBunlock);
5367 return;
5370 #undef DBGC_CLASS
5371 #define DBGC_CLASS DBGC_ALL
5373 /****************************************************************************
5374 Reply to a tdis.
5375 conn POINTER CAN BE NULL HERE !
5376 ****************************************************************************/
5378 void reply_tdis(struct smb_request *req)
5380 NTSTATUS status;
5381 connection_struct *conn = req->conn;
5382 struct smbXsrv_tcon *tcon;
5384 START_PROFILE(SMBtdis);
5386 if (!conn) {
5387 DEBUG(4,("Invalid connection in tdis\n"));
5388 reply_force_doserror(req, ERRSRV, ERRinvnid);
5389 END_PROFILE(SMBtdis);
5390 return;
5393 tcon = conn->tcon;
5394 req->conn = NULL;
5397 * TODO: cancel all outstanding requests on the tcon
5399 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
5400 if (!NT_STATUS_IS_OK(status)) {
5401 DEBUG(0, ("reply_tdis: "
5402 "smbXsrv_tcon_disconnect() failed: %s\n",
5403 nt_errstr(status)));
5405 * If we hit this case, there is something completely
5406 * wrong, so we better disconnect the transport connection.
5408 END_PROFILE(SMBtdis);
5409 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
5410 return;
5413 TALLOC_FREE(tcon);
5415 reply_outbuf(req, 0, 0);
5416 END_PROFILE(SMBtdis);
5417 return;
5420 /****************************************************************************
5421 Reply to a echo.
5422 conn POINTER CAN BE NULL HERE !
5423 ****************************************************************************/
5425 void reply_echo(struct smb_request *req)
5427 connection_struct *conn = req->conn;
5428 struct smb_perfcount_data local_pcd;
5429 struct smb_perfcount_data *cur_pcd;
5430 int smb_reverb;
5431 int seq_num;
5433 START_PROFILE(SMBecho);
5435 smb_init_perfcount_data(&local_pcd);
5437 if (req->wct < 1) {
5438 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5439 END_PROFILE(SMBecho);
5440 return;
5443 smb_reverb = SVAL(req->vwv+0, 0);
5445 reply_outbuf(req, 1, req->buflen);
5447 /* copy any incoming data back out */
5448 if (req->buflen > 0) {
5449 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5452 if (smb_reverb > 100) {
5453 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5454 smb_reverb = 100;
5457 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5459 /* this makes sure we catch the request pcd */
5460 if (seq_num == smb_reverb) {
5461 cur_pcd = &req->pcd;
5462 } else {
5463 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5464 cur_pcd = &local_pcd;
5467 SSVAL(req->outbuf,smb_vwv0,seq_num);
5469 show_msg((char *)req->outbuf);
5470 if (!srv_send_smb(req->sconn,
5471 (char *)req->outbuf,
5472 true, req->seqnum+1,
5473 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5474 cur_pcd))
5475 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5478 DEBUG(3,("echo %d times\n", smb_reverb));
5480 TALLOC_FREE(req->outbuf);
5482 END_PROFILE(SMBecho);
5483 return;
5486 /****************************************************************************
5487 Reply to a printopen.
5488 ****************************************************************************/
5490 void reply_printopen(struct smb_request *req)
5492 connection_struct *conn = req->conn;
5493 files_struct *fsp;
5494 NTSTATUS status;
5496 START_PROFILE(SMBsplopen);
5498 if (req->wct < 2) {
5499 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5500 END_PROFILE(SMBsplopen);
5501 return;
5504 if (!CAN_PRINT(conn)) {
5505 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5506 END_PROFILE(SMBsplopen);
5507 return;
5510 status = file_new(req, conn, &fsp);
5511 if(!NT_STATUS_IS_OK(status)) {
5512 reply_nterror(req, status);
5513 END_PROFILE(SMBsplopen);
5514 return;
5517 /* Open for exclusive use, write only. */
5518 status = print_spool_open(fsp, NULL, req->vuid);
5520 if (!NT_STATUS_IS_OK(status)) {
5521 file_free(req, fsp);
5522 reply_nterror(req, status);
5523 END_PROFILE(SMBsplopen);
5524 return;
5527 reply_outbuf(req, 1, 0);
5528 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5530 DEBUG(3,("openprint fd=%d %s\n",
5531 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5533 END_PROFILE(SMBsplopen);
5534 return;
5537 /****************************************************************************
5538 Reply to a printclose.
5539 ****************************************************************************/
5541 void reply_printclose(struct smb_request *req)
5543 connection_struct *conn = req->conn;
5544 files_struct *fsp;
5545 NTSTATUS status;
5547 START_PROFILE(SMBsplclose);
5549 if (req->wct < 1) {
5550 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5551 END_PROFILE(SMBsplclose);
5552 return;
5555 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5557 if (!check_fsp(conn, req, fsp)) {
5558 END_PROFILE(SMBsplclose);
5559 return;
5562 if (!CAN_PRINT(conn)) {
5563 reply_force_doserror(req, ERRSRV, ERRerror);
5564 END_PROFILE(SMBsplclose);
5565 return;
5568 DEBUG(3,("printclose fd=%d %s\n",
5569 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5571 status = close_file(req, fsp, NORMAL_CLOSE);
5573 if(!NT_STATUS_IS_OK(status)) {
5574 reply_nterror(req, status);
5575 END_PROFILE(SMBsplclose);
5576 return;
5579 reply_outbuf(req, 0, 0);
5581 END_PROFILE(SMBsplclose);
5582 return;
5585 /****************************************************************************
5586 Reply to a printqueue.
5587 ****************************************************************************/
5589 void reply_printqueue(struct smb_request *req)
5591 connection_struct *conn = req->conn;
5592 int max_count;
5593 int start_index;
5595 START_PROFILE(SMBsplretq);
5597 if (req->wct < 2) {
5598 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5599 END_PROFILE(SMBsplretq);
5600 return;
5603 max_count = SVAL(req->vwv+0, 0);
5604 start_index = SVAL(req->vwv+1, 0);
5606 /* we used to allow the client to get the cnum wrong, but that
5607 is really quite gross and only worked when there was only
5608 one printer - I think we should now only accept it if they
5609 get it right (tridge) */
5610 if (!CAN_PRINT(conn)) {
5611 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5612 END_PROFILE(SMBsplretq);
5613 return;
5616 reply_outbuf(req, 2, 3);
5617 SSVAL(req->outbuf,smb_vwv0,0);
5618 SSVAL(req->outbuf,smb_vwv1,0);
5619 SCVAL(smb_buf(req->outbuf),0,1);
5620 SSVAL(smb_buf(req->outbuf),1,0);
5622 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5623 start_index, max_count));
5626 TALLOC_CTX *mem_ctx = talloc_tos();
5627 NTSTATUS status;
5628 WERROR werr;
5629 const char *sharename = lp_servicename(mem_ctx, SNUM(conn));
5630 struct rpc_pipe_client *cli = NULL;
5631 struct dcerpc_binding_handle *b = NULL;
5632 struct policy_handle handle;
5633 struct spoolss_DevmodeContainer devmode_ctr;
5634 union spoolss_JobInfo *info;
5635 uint32_t count;
5636 uint32_t num_to_get;
5637 uint32_t first;
5638 uint32_t i;
5640 ZERO_STRUCT(handle);
5642 status = rpc_pipe_open_interface(conn,
5643 &ndr_table_spoolss,
5644 conn->session_info,
5645 conn->sconn->remote_address,
5646 conn->sconn->msg_ctx,
5647 &cli);
5648 if (!NT_STATUS_IS_OK(status)) {
5649 DEBUG(0, ("reply_printqueue: "
5650 "could not connect to spoolss: %s\n",
5651 nt_errstr(status)));
5652 reply_nterror(req, status);
5653 goto out;
5655 b = cli->binding_handle;
5657 ZERO_STRUCT(devmode_ctr);
5659 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5660 sharename,
5661 NULL, devmode_ctr,
5662 SEC_FLAG_MAXIMUM_ALLOWED,
5663 &handle,
5664 &werr);
5665 if (!NT_STATUS_IS_OK(status)) {
5666 reply_nterror(req, status);
5667 goto out;
5669 if (!W_ERROR_IS_OK(werr)) {
5670 reply_nterror(req, werror_to_ntstatus(werr));
5671 goto out;
5674 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5675 &handle,
5676 0, /* firstjob */
5677 0xff, /* numjobs */
5678 2, /* level */
5679 0, /* offered */
5680 &count,
5681 &info);
5682 if (!W_ERROR_IS_OK(werr)) {
5683 reply_nterror(req, werror_to_ntstatus(werr));
5684 goto out;
5687 if (max_count > 0) {
5688 first = start_index;
5689 } else {
5690 first = start_index + max_count + 1;
5693 if (first >= count) {
5694 num_to_get = first;
5695 } else {
5696 num_to_get = first + MIN(ABS(max_count), count - first);
5699 for (i = first; i < num_to_get; i++) {
5700 char blob[28];
5701 char *p = blob;
5702 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
5703 int qstatus;
5704 uint16_t qrapjobid = pjobid_to_rap(sharename,
5705 info[i].info2.job_id);
5707 if (info[i].info2.status == JOB_STATUS_PRINTING) {
5708 qstatus = 2;
5709 } else {
5710 qstatus = 3;
5713 srv_put_dos_date2(p, 0, qtime);
5714 SCVAL(p, 4, qstatus);
5715 SSVAL(p, 5, qrapjobid);
5716 SIVAL(p, 7, info[i].info2.size);
5717 SCVAL(p, 11, 0);
5718 srvstr_push(blob, req->flags2, p+12,
5719 info[i].info2.notify_name, 16, STR_ASCII);
5721 if (message_push_blob(
5722 &req->outbuf,
5723 data_blob_const(
5724 blob, sizeof(blob))) == -1) {
5725 reply_nterror(req, NT_STATUS_NO_MEMORY);
5726 goto out;
5730 if (count > 0) {
5731 SSVAL(req->outbuf,smb_vwv0,count);
5732 SSVAL(req->outbuf,smb_vwv1,
5733 (max_count>0?first+count:first-1));
5734 SCVAL(smb_buf(req->outbuf),0,1);
5735 SSVAL(smb_buf(req->outbuf),1,28*count);
5739 DEBUG(3, ("%u entries returned in queue\n",
5740 (unsigned)count));
5742 out:
5743 if (b && is_valid_policy_hnd(&handle)) {
5744 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5749 END_PROFILE(SMBsplretq);
5750 return;
5753 /****************************************************************************
5754 Reply to a printwrite.
5755 ****************************************************************************/
5757 void reply_printwrite(struct smb_request *req)
5759 connection_struct *conn = req->conn;
5760 int numtowrite;
5761 const char *data;
5762 files_struct *fsp;
5764 START_PROFILE(SMBsplwr);
5766 if (req->wct < 1) {
5767 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5768 END_PROFILE(SMBsplwr);
5769 return;
5772 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5774 if (!check_fsp(conn, req, fsp)) {
5775 END_PROFILE(SMBsplwr);
5776 return;
5779 if (!fsp->print_file) {
5780 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5781 END_PROFILE(SMBsplwr);
5782 return;
5785 if (!CHECK_WRITE(fsp)) {
5786 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5787 END_PROFILE(SMBsplwr);
5788 return;
5791 numtowrite = SVAL(req->buf, 1);
5793 if (req->buflen < numtowrite + 3) {
5794 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5795 END_PROFILE(SMBsplwr);
5796 return;
5799 data = (const char *)req->buf + 3;
5801 if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
5802 reply_nterror(req, map_nt_error_from_unix(errno));
5803 END_PROFILE(SMBsplwr);
5804 return;
5807 DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
5809 END_PROFILE(SMBsplwr);
5810 return;
5813 /****************************************************************************
5814 Reply to a mkdir.
5815 ****************************************************************************/
5817 void reply_mkdir(struct smb_request *req)
5819 connection_struct *conn = req->conn;
5820 struct smb_filename *smb_dname = NULL;
5821 char *directory = NULL;
5822 NTSTATUS status;
5823 TALLOC_CTX *ctx = talloc_tos();
5825 START_PROFILE(SMBmkdir);
5827 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5828 STR_TERMINATE, &status);
5829 if (!NT_STATUS_IS_OK(status)) {
5830 reply_nterror(req, status);
5831 goto out;
5834 status = filename_convert(ctx, conn,
5835 req->flags2 & FLAGS2_DFS_PATHNAMES,
5836 directory,
5837 UCF_PREP_CREATEFILE,
5838 NULL,
5839 &smb_dname);
5840 if (!NT_STATUS_IS_OK(status)) {
5841 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5842 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5843 ERRSRV, ERRbadpath);
5844 goto out;
5846 reply_nterror(req, status);
5847 goto out;
5850 status = create_directory(conn, req, smb_dname);
5852 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
5854 if (!NT_STATUS_IS_OK(status)) {
5856 if (!use_nt_status()
5857 && NT_STATUS_EQUAL(status,
5858 NT_STATUS_OBJECT_NAME_COLLISION)) {
5860 * Yes, in the DOS error code case we get a
5861 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
5862 * samba4 torture test.
5864 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
5867 reply_nterror(req, status);
5868 goto out;
5871 reply_outbuf(req, 0, 0);
5873 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
5874 out:
5875 TALLOC_FREE(smb_dname);
5876 END_PROFILE(SMBmkdir);
5877 return;
5880 /****************************************************************************
5881 Reply to a rmdir.
5882 ****************************************************************************/
5884 void reply_rmdir(struct smb_request *req)
5886 connection_struct *conn = req->conn;
5887 struct smb_filename *smb_dname = NULL;
5888 char *directory = NULL;
5889 NTSTATUS status;
5890 TALLOC_CTX *ctx = talloc_tos();
5891 files_struct *fsp = NULL;
5892 int info = 0;
5893 struct smbd_server_connection *sconn = req->sconn;
5895 START_PROFILE(SMBrmdir);
5897 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5898 STR_TERMINATE, &status);
5899 if (!NT_STATUS_IS_OK(status)) {
5900 reply_nterror(req, status);
5901 goto out;
5904 status = filename_convert(ctx, conn,
5905 req->flags2 & FLAGS2_DFS_PATHNAMES,
5906 directory,
5908 NULL,
5909 &smb_dname);
5910 if (!NT_STATUS_IS_OK(status)) {
5911 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5912 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5913 ERRSRV, ERRbadpath);
5914 goto out;
5916 reply_nterror(req, status);
5917 goto out;
5920 if (is_ntfs_stream_smb_fname(smb_dname)) {
5921 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
5922 goto out;
5925 status = SMB_VFS_CREATE_FILE(
5926 conn, /* conn */
5927 req, /* req */
5928 0, /* root_dir_fid */
5929 smb_dname, /* fname */
5930 DELETE_ACCESS, /* access_mask */
5931 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5932 FILE_SHARE_DELETE),
5933 FILE_OPEN, /* create_disposition*/
5934 FILE_DIRECTORY_FILE, /* create_options */
5935 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
5936 0, /* oplock_request */
5937 0, /* allocation_size */
5938 0, /* private_flags */
5939 NULL, /* sd */
5940 NULL, /* ea_list */
5941 &fsp, /* result */
5942 &info); /* pinfo */
5944 if (!NT_STATUS_IS_OK(status)) {
5945 if (open_was_deferred(req->sconn, req->mid)) {
5946 /* We have re-scheduled this call. */
5947 goto out;
5949 reply_nterror(req, status);
5950 goto out;
5953 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
5954 if (!NT_STATUS_IS_OK(status)) {
5955 close_file(req, fsp, ERROR_CLOSE);
5956 reply_nterror(req, status);
5957 goto out;
5960 if (!set_delete_on_close(fsp, true,
5961 conn->session_info->security_token,
5962 conn->session_info->unix_token)) {
5963 close_file(req, fsp, ERROR_CLOSE);
5964 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5965 goto out;
5968 status = close_file(req, fsp, NORMAL_CLOSE);
5969 if (!NT_STATUS_IS_OK(status)) {
5970 reply_nterror(req, status);
5971 } else {
5972 reply_outbuf(req, 0, 0);
5975 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
5977 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
5978 out:
5979 TALLOC_FREE(smb_dname);
5980 END_PROFILE(SMBrmdir);
5981 return;
5984 /*******************************************************************
5985 Resolve wildcards in a filename rename.
5986 ********************************************************************/
5988 static bool resolve_wildcards(TALLOC_CTX *ctx,
5989 const char *name1,
5990 const char *name2,
5991 char **pp_newname)
5993 char *name2_copy = NULL;
5994 char *root1 = NULL;
5995 char *root2 = NULL;
5996 char *ext1 = NULL;
5997 char *ext2 = NULL;
5998 char *p,*p2, *pname1, *pname2;
6000 name2_copy = talloc_strdup(ctx, name2);
6001 if (!name2_copy) {
6002 return False;
6005 pname1 = strrchr_m(name1,'/');
6006 pname2 = strrchr_m(name2_copy,'/');
6008 if (!pname1 || !pname2) {
6009 return False;
6012 /* Truncate the copy of name2 at the last '/' */
6013 *pname2 = '\0';
6015 /* Now go past the '/' */
6016 pname1++;
6017 pname2++;
6019 root1 = talloc_strdup(ctx, pname1);
6020 root2 = talloc_strdup(ctx, pname2);
6022 if (!root1 || !root2) {
6023 return False;
6026 p = strrchr_m(root1,'.');
6027 if (p) {
6028 *p = 0;
6029 ext1 = talloc_strdup(ctx, p+1);
6030 } else {
6031 ext1 = talloc_strdup(ctx, "");
6033 p = strrchr_m(root2,'.');
6034 if (p) {
6035 *p = 0;
6036 ext2 = talloc_strdup(ctx, p+1);
6037 } else {
6038 ext2 = talloc_strdup(ctx, "");
6041 if (!ext1 || !ext2) {
6042 return False;
6045 p = root1;
6046 p2 = root2;
6047 while (*p2) {
6048 if (*p2 == '?') {
6049 /* Hmmm. Should this be mb-aware ? */
6050 *p2 = *p;
6051 p2++;
6052 } else if (*p2 == '*') {
6053 *p2 = '\0';
6054 root2 = talloc_asprintf(ctx, "%s%s",
6055 root2,
6057 if (!root2) {
6058 return False;
6060 break;
6061 } else {
6062 p2++;
6064 if (*p) {
6065 p++;
6069 p = ext1;
6070 p2 = ext2;
6071 while (*p2) {
6072 if (*p2 == '?') {
6073 /* Hmmm. Should this be mb-aware ? */
6074 *p2 = *p;
6075 p2++;
6076 } else if (*p2 == '*') {
6077 *p2 = '\0';
6078 ext2 = talloc_asprintf(ctx, "%s%s",
6079 ext2,
6081 if (!ext2) {
6082 return False;
6084 break;
6085 } else {
6086 p2++;
6088 if (*p) {
6089 p++;
6093 if (*ext2) {
6094 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
6095 name2_copy,
6096 root2,
6097 ext2);
6098 } else {
6099 *pp_newname = talloc_asprintf(ctx, "%s/%s",
6100 name2_copy,
6101 root2);
6104 if (!*pp_newname) {
6105 return False;
6108 return True;
6111 /****************************************************************************
6112 Ensure open files have their names updated. Updated to notify other smbd's
6113 asynchronously.
6114 ****************************************************************************/
6116 static void rename_open_files(connection_struct *conn,
6117 struct share_mode_lock *lck,
6118 struct file_id id,
6119 uint32_t orig_name_hash,
6120 const struct smb_filename *smb_fname_dst)
6122 files_struct *fsp;
6123 bool did_rename = False;
6124 NTSTATUS status;
6125 uint32_t new_name_hash = 0;
6127 for(fsp = file_find_di_first(conn->sconn, id); fsp;
6128 fsp = file_find_di_next(fsp)) {
6129 /* fsp_name is a relative path under the fsp. To change this for other
6130 sharepaths we need to manipulate relative paths. */
6131 /* TODO - create the absolute path and manipulate the newname
6132 relative to the sharepath. */
6133 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
6134 continue;
6136 if (fsp->name_hash != orig_name_hash) {
6137 continue;
6139 DEBUG(10, ("rename_open_files: renaming file %s "
6140 "(file_id %s) from %s -> %s\n", fsp_fnum_dbg(fsp),
6141 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
6142 smb_fname_str_dbg(smb_fname_dst)));
6144 status = fsp_set_smb_fname(fsp, smb_fname_dst);
6145 if (NT_STATUS_IS_OK(status)) {
6146 did_rename = True;
6147 new_name_hash = fsp->name_hash;
6151 if (!did_rename) {
6152 DEBUG(10, ("rename_open_files: no open files on file_id %s "
6153 "for %s\n", file_id_string_tos(&id),
6154 smb_fname_str_dbg(smb_fname_dst)));
6157 /* Send messages to all smbd's (not ourself) that the name has changed. */
6158 rename_share_filename(conn->sconn->msg_ctx, lck, id, conn->connectpath,
6159 orig_name_hash, new_name_hash,
6160 smb_fname_dst);
6164 /****************************************************************************
6165 We need to check if the source path is a parent directory of the destination
6166 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
6167 refuse the rename with a sharing violation. Under UNIX the above call can
6168 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
6169 probably need to check that the client is a Windows one before disallowing
6170 this as a UNIX client (one with UNIX extensions) can know the source is a
6171 symlink and make this decision intelligently. Found by an excellent bug
6172 report from <AndyLiebman@aol.com>.
6173 ****************************************************************************/
6175 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
6176 const struct smb_filename *smb_fname_dst)
6178 const char *psrc = smb_fname_src->base_name;
6179 const char *pdst = smb_fname_dst->base_name;
6180 size_t slen;
6182 if (psrc[0] == '.' && psrc[1] == '/') {
6183 psrc += 2;
6185 if (pdst[0] == '.' && pdst[1] == '/') {
6186 pdst += 2;
6188 if ((slen = strlen(psrc)) > strlen(pdst)) {
6189 return False;
6191 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
6195 * Do the notify calls from a rename
6198 static void notify_rename(connection_struct *conn, bool is_dir,
6199 const struct smb_filename *smb_fname_src,
6200 const struct smb_filename *smb_fname_dst)
6202 char *parent_dir_src = NULL;
6203 char *parent_dir_dst = NULL;
6204 uint32 mask;
6206 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
6207 : FILE_NOTIFY_CHANGE_FILE_NAME;
6209 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
6210 &parent_dir_src, NULL) ||
6211 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
6212 &parent_dir_dst, NULL)) {
6213 goto out;
6216 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
6217 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
6218 smb_fname_src->base_name);
6219 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
6220 smb_fname_dst->base_name);
6222 else {
6223 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
6224 smb_fname_src->base_name);
6225 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
6226 smb_fname_dst->base_name);
6229 /* this is a strange one. w2k3 gives an additional event for
6230 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
6231 files, but not directories */
6232 if (!is_dir) {
6233 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6234 FILE_NOTIFY_CHANGE_ATTRIBUTES
6235 |FILE_NOTIFY_CHANGE_CREATION,
6236 smb_fname_dst->base_name);
6238 out:
6239 TALLOC_FREE(parent_dir_src);
6240 TALLOC_FREE(parent_dir_dst);
6243 /****************************************************************************
6244 Returns an error if the parent directory for a filename is open in an
6245 incompatible way.
6246 ****************************************************************************/
6248 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
6249 const struct smb_filename *smb_fname_dst_in)
6251 char *parent_dir = NULL;
6252 struct smb_filename smb_fname_parent;
6253 struct file_id id;
6254 files_struct *fsp = NULL;
6255 int ret;
6257 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
6258 &parent_dir, NULL)) {
6259 return NT_STATUS_NO_MEMORY;
6261 ZERO_STRUCT(smb_fname_parent);
6262 smb_fname_parent.base_name = parent_dir;
6264 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
6265 if (ret == -1) {
6266 return map_nt_error_from_unix(errno);
6270 * We're only checking on this smbd here, mostly good
6271 * enough.. and will pass tests.
6274 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
6275 for (fsp = file_find_di_first(conn->sconn, id); fsp;
6276 fsp = file_find_di_next(fsp)) {
6277 if (fsp->access_mask & DELETE_ACCESS) {
6278 return NT_STATUS_SHARING_VIOLATION;
6281 return NT_STATUS_OK;
6284 /****************************************************************************
6285 Rename an open file - given an fsp.
6286 ****************************************************************************/
6288 NTSTATUS rename_internals_fsp(connection_struct *conn,
6289 files_struct *fsp,
6290 const struct smb_filename *smb_fname_dst_in,
6291 uint32 attrs,
6292 bool replace_if_exists)
6294 TALLOC_CTX *ctx = talloc_tos();
6295 struct smb_filename *smb_fname_dst = NULL;
6296 NTSTATUS status = NT_STATUS_OK;
6297 struct share_mode_lock *lck = NULL;
6298 bool dst_exists, old_is_stream, new_is_stream;
6300 status = check_name(conn, smb_fname_dst_in->base_name);
6301 if (!NT_STATUS_IS_OK(status)) {
6302 return status;
6305 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
6306 if (!NT_STATUS_IS_OK(status)) {
6307 return status;
6310 /* Make a copy of the dst smb_fname structs */
6312 smb_fname_dst = cp_smb_filename(ctx, smb_fname_dst_in);
6313 if (smb_fname_dst == NULL) {
6314 status = NT_STATUS_NO_MEMORY;
6315 goto out;
6319 * Check for special case with case preserving and not
6320 * case sensitive. If the old last component differs from the original
6321 * last component only by case, then we should allow
6322 * the rename (user is trying to change the case of the
6323 * filename).
6325 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
6326 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6327 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
6328 char *last_slash;
6329 char *fname_dst_lcomp_base_mod = NULL;
6330 struct smb_filename *smb_fname_orig_lcomp = NULL;
6333 * Get the last component of the destination name.
6335 last_slash = strrchr_m(smb_fname_dst->base_name, '/');
6336 if (last_slash) {
6337 fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1);
6338 } else {
6339 fname_dst_lcomp_base_mod = talloc_strdup(ctx, smb_fname_dst->base_name);
6341 if (!fname_dst_lcomp_base_mod) {
6342 status = NT_STATUS_NO_MEMORY;
6343 goto out;
6347 * Create an smb_filename struct using the original last
6348 * component of the destination.
6350 smb_fname_orig_lcomp = synthetic_smb_fname_split(
6351 ctx, smb_fname_dst->original_lcomp, NULL);
6352 if (smb_fname_orig_lcomp == NULL) {
6353 status = NT_STATUS_NO_MEMORY;
6354 TALLOC_FREE(fname_dst_lcomp_base_mod);
6355 goto out;
6358 /* If the base names only differ by case, use original. */
6359 if(!strcsequal(fname_dst_lcomp_base_mod,
6360 smb_fname_orig_lcomp->base_name)) {
6361 char *tmp;
6363 * Replace the modified last component with the
6364 * original.
6366 if (last_slash) {
6367 *last_slash = '\0'; /* Truncate at the '/' */
6368 tmp = talloc_asprintf(smb_fname_dst,
6369 "%s/%s",
6370 smb_fname_dst->base_name,
6371 smb_fname_orig_lcomp->base_name);
6372 } else {
6373 tmp = talloc_asprintf(smb_fname_dst,
6374 "%s",
6375 smb_fname_orig_lcomp->base_name);
6377 if (tmp == NULL) {
6378 status = NT_STATUS_NO_MEMORY;
6379 TALLOC_FREE(fname_dst_lcomp_base_mod);
6380 TALLOC_FREE(smb_fname_orig_lcomp);
6381 goto out;
6383 TALLOC_FREE(smb_fname_dst->base_name);
6384 smb_fname_dst->base_name = tmp;
6387 /* If the stream_names only differ by case, use original. */
6388 if(!strcsequal(smb_fname_dst->stream_name,
6389 smb_fname_orig_lcomp->stream_name)) {
6390 char *tmp = NULL;
6391 /* Use the original stream. */
6392 tmp = talloc_strdup(smb_fname_dst,
6393 smb_fname_orig_lcomp->stream_name);
6394 if (tmp == NULL) {
6395 status = NT_STATUS_NO_MEMORY;
6396 TALLOC_FREE(fname_dst_lcomp_base_mod);
6397 TALLOC_FREE(smb_fname_orig_lcomp);
6398 goto out;
6400 TALLOC_FREE(smb_fname_dst->stream_name);
6401 smb_fname_dst->stream_name = tmp;
6403 TALLOC_FREE(fname_dst_lcomp_base_mod);
6404 TALLOC_FREE(smb_fname_orig_lcomp);
6408 * If the src and dest names are identical - including case,
6409 * don't do the rename, just return success.
6412 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6413 strcsequal(fsp->fsp_name->stream_name,
6414 smb_fname_dst->stream_name)) {
6415 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6416 "- returning success\n",
6417 smb_fname_str_dbg(smb_fname_dst)));
6418 status = NT_STATUS_OK;
6419 goto out;
6422 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6423 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6425 /* Return the correct error code if both names aren't streams. */
6426 if (!old_is_stream && new_is_stream) {
6427 status = NT_STATUS_OBJECT_NAME_INVALID;
6428 goto out;
6431 if (old_is_stream && !new_is_stream) {
6432 status = NT_STATUS_INVALID_PARAMETER;
6433 goto out;
6436 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6438 if(!replace_if_exists && dst_exists) {
6439 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6440 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6441 smb_fname_str_dbg(smb_fname_dst)));
6442 status = NT_STATUS_OBJECT_NAME_COLLISION;
6443 goto out;
6446 if (dst_exists) {
6447 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6448 &smb_fname_dst->st);
6449 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6450 fileid);
6451 /* The file can be open when renaming a stream */
6452 if (dst_fsp && !new_is_stream) {
6453 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6454 status = NT_STATUS_ACCESS_DENIED;
6455 goto out;
6459 /* Ensure we have a valid stat struct for the source. */
6460 status = vfs_stat_fsp(fsp);
6461 if (!NT_STATUS_IS_OK(status)) {
6462 goto out;
6465 status = can_rename(conn, fsp, attrs);
6467 if (!NT_STATUS_IS_OK(status)) {
6468 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6469 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6470 smb_fname_str_dbg(smb_fname_dst)));
6471 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6472 status = NT_STATUS_ACCESS_DENIED;
6473 goto out;
6476 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6477 status = NT_STATUS_ACCESS_DENIED;
6480 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
6483 * We have the file open ourselves, so not being able to get the
6484 * corresponding share mode lock is a fatal error.
6487 SMB_ASSERT(lck != NULL);
6489 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6490 uint32 create_options = fsp->fh->private_options;
6492 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6493 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6494 smb_fname_str_dbg(smb_fname_dst)));
6496 if (!fsp->is_directory &&
6497 !lp_posix_pathnames() &&
6498 (lp_map_archive(SNUM(conn)) ||
6499 lp_store_dos_attributes(SNUM(conn)))) {
6500 /* We must set the archive bit on the newly
6501 renamed file. */
6502 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6503 uint32_t old_dosmode = dos_mode(conn,
6504 smb_fname_dst);
6505 file_set_dosmode(conn,
6506 smb_fname_dst,
6507 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6508 NULL,
6509 true);
6513 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6514 smb_fname_dst);
6516 rename_open_files(conn, lck, fsp->file_id, fsp->name_hash,
6517 smb_fname_dst);
6520 * A rename acts as a new file create w.r.t. allowing an initial delete
6521 * on close, probably because in Windows there is a new handle to the
6522 * new file. If initial delete on close was requested but not
6523 * originally set, we need to set it here. This is probably not 100% correct,
6524 * but will work for the CIFSFS client which in non-posix mode
6525 * depends on these semantics. JRA.
6528 if (create_options & FILE_DELETE_ON_CLOSE) {
6529 status = can_set_delete_on_close(fsp, 0);
6531 if (NT_STATUS_IS_OK(status)) {
6532 /* Note that here we set the *inital* delete on close flag,
6533 * not the regular one. The magic gets handled in close. */
6534 fsp->initial_delete_on_close = True;
6537 TALLOC_FREE(lck);
6538 status = NT_STATUS_OK;
6539 goto out;
6542 TALLOC_FREE(lck);
6544 if (errno == ENOTDIR || errno == EISDIR) {
6545 status = NT_STATUS_OBJECT_NAME_COLLISION;
6546 } else {
6547 status = map_nt_error_from_unix(errno);
6550 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6551 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6552 smb_fname_str_dbg(smb_fname_dst)));
6554 out:
6555 TALLOC_FREE(smb_fname_dst);
6557 return status;
6560 /****************************************************************************
6561 The guts of the rename command, split out so it may be called by the NT SMB
6562 code.
6563 ****************************************************************************/
6565 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6566 connection_struct *conn,
6567 struct smb_request *req,
6568 struct smb_filename *smb_fname_src,
6569 struct smb_filename *smb_fname_dst,
6570 uint32 attrs,
6571 bool replace_if_exists,
6572 bool src_has_wild,
6573 bool dest_has_wild,
6574 uint32_t access_mask)
6576 char *fname_src_dir = NULL;
6577 char *fname_src_mask = NULL;
6578 int count=0;
6579 NTSTATUS status = NT_STATUS_OK;
6580 struct smb_Dir *dir_hnd = NULL;
6581 const char *dname = NULL;
6582 char *talloced = NULL;
6583 long offset = 0;
6584 int create_options = 0;
6585 bool posix_pathnames = lp_posix_pathnames();
6586 int rc;
6589 * Split the old name into directory and last component
6590 * strings. Note that unix_convert may have stripped off a
6591 * leading ./ from both name and newname if the rename is
6592 * at the root of the share. We need to make sure either both
6593 * name and newname contain a / character or neither of them do
6594 * as this is checked in resolve_wildcards().
6597 /* Split up the directory from the filename/mask. */
6598 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6599 &fname_src_dir, &fname_src_mask);
6600 if (!NT_STATUS_IS_OK(status)) {
6601 status = NT_STATUS_NO_MEMORY;
6602 goto out;
6606 * We should only check the mangled cache
6607 * here if unix_convert failed. This means
6608 * that the path in 'mask' doesn't exist
6609 * on the file system and so we need to look
6610 * for a possible mangle. This patch from
6611 * Tine Smukavec <valentin.smukavec@hermes.si>.
6614 if (!VALID_STAT(smb_fname_src->st) &&
6615 mangle_is_mangled(fname_src_mask, conn->params)) {
6616 char *new_mask = NULL;
6617 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6618 conn->params);
6619 if (new_mask) {
6620 TALLOC_FREE(fname_src_mask);
6621 fname_src_mask = new_mask;
6625 if (!src_has_wild) {
6626 files_struct *fsp;
6629 * Only one file needs to be renamed. Append the mask back
6630 * onto the directory.
6632 TALLOC_FREE(smb_fname_src->base_name);
6633 if (ISDOT(fname_src_dir)) {
6634 /* Ensure we use canonical names on open. */
6635 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6636 "%s",
6637 fname_src_mask);
6638 } else {
6639 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6640 "%s/%s",
6641 fname_src_dir,
6642 fname_src_mask);
6644 if (!smb_fname_src->base_name) {
6645 status = NT_STATUS_NO_MEMORY;
6646 goto out;
6649 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6650 "case_preserve = %d, short case preserve = %d, "
6651 "directory = %s, newname = %s, "
6652 "last_component_dest = %s\n",
6653 conn->case_sensitive, conn->case_preserve,
6654 conn->short_case_preserve,
6655 smb_fname_str_dbg(smb_fname_src),
6656 smb_fname_str_dbg(smb_fname_dst),
6657 smb_fname_dst->original_lcomp));
6659 /* The dest name still may have wildcards. */
6660 if (dest_has_wild) {
6661 char *fname_dst_mod = NULL;
6662 if (!resolve_wildcards(smb_fname_dst,
6663 smb_fname_src->base_name,
6664 smb_fname_dst->base_name,
6665 &fname_dst_mod)) {
6666 DEBUG(6, ("rename_internals: resolve_wildcards "
6667 "%s %s failed\n",
6668 smb_fname_src->base_name,
6669 smb_fname_dst->base_name));
6670 status = NT_STATUS_NO_MEMORY;
6671 goto out;
6673 TALLOC_FREE(smb_fname_dst->base_name);
6674 smb_fname_dst->base_name = fname_dst_mod;
6677 ZERO_STRUCT(smb_fname_src->st);
6678 if (posix_pathnames) {
6679 rc = SMB_VFS_LSTAT(conn, smb_fname_src);
6680 } else {
6681 rc = SMB_VFS_STAT(conn, smb_fname_src);
6683 if (rc == -1) {
6684 status = map_nt_error_from_unix_common(errno);
6685 goto out;
6688 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6689 create_options |= FILE_DIRECTORY_FILE;
6692 status = SMB_VFS_CREATE_FILE(
6693 conn, /* conn */
6694 req, /* req */
6695 0, /* root_dir_fid */
6696 smb_fname_src, /* fname */
6697 access_mask, /* access_mask */
6698 (FILE_SHARE_READ | /* share_access */
6699 FILE_SHARE_WRITE),
6700 FILE_OPEN, /* create_disposition*/
6701 create_options, /* create_options */
6702 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6703 0, /* oplock_request */
6704 0, /* allocation_size */
6705 0, /* private_flags */
6706 NULL, /* sd */
6707 NULL, /* ea_list */
6708 &fsp, /* result */
6709 NULL); /* pinfo */
6711 if (!NT_STATUS_IS_OK(status)) {
6712 DEBUG(3, ("Could not open rename source %s: %s\n",
6713 smb_fname_str_dbg(smb_fname_src),
6714 nt_errstr(status)));
6715 goto out;
6718 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6719 attrs, replace_if_exists);
6721 close_file(req, fsp, NORMAL_CLOSE);
6723 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
6724 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
6725 smb_fname_str_dbg(smb_fname_dst)));
6727 goto out;
6731 * Wildcards - process each file that matches.
6733 if (strequal(fname_src_mask, "????????.???")) {
6734 TALLOC_FREE(fname_src_mask);
6735 fname_src_mask = talloc_strdup(ctx, "*");
6736 if (!fname_src_mask) {
6737 status = NT_STATUS_NO_MEMORY;
6738 goto out;
6742 status = check_name(conn, fname_src_dir);
6743 if (!NT_STATUS_IS_OK(status)) {
6744 goto out;
6747 dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask,
6748 attrs);
6749 if (dir_hnd == NULL) {
6750 status = map_nt_error_from_unix(errno);
6751 goto out;
6754 status = NT_STATUS_NO_SUCH_FILE;
6756 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
6757 * - gentest fix. JRA
6760 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
6761 &talloced))) {
6762 files_struct *fsp = NULL;
6763 char *destname = NULL;
6764 bool sysdir_entry = False;
6766 /* Quick check for "." and ".." */
6767 if (ISDOT(dname) || ISDOTDOT(dname)) {
6768 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
6769 sysdir_entry = True;
6770 } else {
6771 TALLOC_FREE(talloced);
6772 continue;
6776 if (!is_visible_file(conn, fname_src_dir, dname,
6777 &smb_fname_src->st, false)) {
6778 TALLOC_FREE(talloced);
6779 continue;
6782 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
6783 TALLOC_FREE(talloced);
6784 continue;
6787 if (sysdir_entry) {
6788 status = NT_STATUS_OBJECT_NAME_INVALID;
6789 break;
6792 TALLOC_FREE(smb_fname_src->base_name);
6793 if (ISDOT(fname_src_dir)) {
6794 /* Ensure we use canonical names on open. */
6795 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6796 "%s",
6797 dname);
6798 } else {
6799 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6800 "%s/%s",
6801 fname_src_dir,
6802 dname);
6804 if (!smb_fname_src->base_name) {
6805 status = NT_STATUS_NO_MEMORY;
6806 goto out;
6809 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6810 smb_fname_dst->base_name,
6811 &destname)) {
6812 DEBUG(6, ("resolve_wildcards %s %s failed\n",
6813 smb_fname_src->base_name, destname));
6814 TALLOC_FREE(talloced);
6815 continue;
6817 if (!destname) {
6818 status = NT_STATUS_NO_MEMORY;
6819 goto out;
6822 TALLOC_FREE(smb_fname_dst->base_name);
6823 smb_fname_dst->base_name = destname;
6825 ZERO_STRUCT(smb_fname_src->st);
6826 if (posix_pathnames) {
6827 SMB_VFS_LSTAT(conn, smb_fname_src);
6828 } else {
6829 SMB_VFS_STAT(conn, smb_fname_src);
6832 create_options = 0;
6834 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6835 create_options |= FILE_DIRECTORY_FILE;
6838 status = SMB_VFS_CREATE_FILE(
6839 conn, /* conn */
6840 req, /* req */
6841 0, /* root_dir_fid */
6842 smb_fname_src, /* fname */
6843 access_mask, /* access_mask */
6844 (FILE_SHARE_READ | /* share_access */
6845 FILE_SHARE_WRITE),
6846 FILE_OPEN, /* create_disposition*/
6847 create_options, /* create_options */
6848 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6849 0, /* oplock_request */
6850 0, /* allocation_size */
6851 0, /* private_flags */
6852 NULL, /* sd */
6853 NULL, /* ea_list */
6854 &fsp, /* result */
6855 NULL); /* pinfo */
6857 if (!NT_STATUS_IS_OK(status)) {
6858 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
6859 "returned %s rename %s -> %s\n",
6860 nt_errstr(status),
6861 smb_fname_str_dbg(smb_fname_src),
6862 smb_fname_str_dbg(smb_fname_dst)));
6863 break;
6866 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6867 dname);
6868 if (!smb_fname_dst->original_lcomp) {
6869 status = NT_STATUS_NO_MEMORY;
6870 goto out;
6873 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6874 attrs, replace_if_exists);
6876 close_file(req, fsp, NORMAL_CLOSE);
6878 if (!NT_STATUS_IS_OK(status)) {
6879 DEBUG(3, ("rename_internals_fsp returned %s for "
6880 "rename %s -> %s\n", nt_errstr(status),
6881 smb_fname_str_dbg(smb_fname_src),
6882 smb_fname_str_dbg(smb_fname_dst)));
6883 break;
6886 count++;
6888 DEBUG(3,("rename_internals: doing rename on %s -> "
6889 "%s\n", smb_fname_str_dbg(smb_fname_src),
6890 smb_fname_str_dbg(smb_fname_src)));
6891 TALLOC_FREE(talloced);
6893 TALLOC_FREE(dir_hnd);
6895 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
6896 status = map_nt_error_from_unix(errno);
6899 out:
6900 TALLOC_FREE(talloced);
6901 TALLOC_FREE(fname_src_dir);
6902 TALLOC_FREE(fname_src_mask);
6903 return status;
6906 /****************************************************************************
6907 Reply to a mv.
6908 ****************************************************************************/
6910 void reply_mv(struct smb_request *req)
6912 connection_struct *conn = req->conn;
6913 char *name = NULL;
6914 char *newname = NULL;
6915 const char *p;
6916 uint32 attrs;
6917 NTSTATUS status;
6918 bool src_has_wcard = False;
6919 bool dest_has_wcard = False;
6920 TALLOC_CTX *ctx = talloc_tos();
6921 struct smb_filename *smb_fname_src = NULL;
6922 struct smb_filename *smb_fname_dst = NULL;
6923 uint32_t src_ucf_flags = lp_posix_pathnames() ? UCF_UNIX_NAME_LOOKUP : UCF_COND_ALLOW_WCARD_LCOMP;
6924 uint32_t dst_ucf_flags = UCF_SAVE_LCOMP | (lp_posix_pathnames() ? 0 : UCF_COND_ALLOW_WCARD_LCOMP);
6925 bool stream_rename = false;
6927 START_PROFILE(SMBmv);
6929 if (req->wct < 1) {
6930 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6931 goto out;
6934 attrs = SVAL(req->vwv+0, 0);
6936 p = (const char *)req->buf + 1;
6937 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
6938 &status, &src_has_wcard);
6939 if (!NT_STATUS_IS_OK(status)) {
6940 reply_nterror(req, status);
6941 goto out;
6943 p++;
6944 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
6945 &status, &dest_has_wcard);
6946 if (!NT_STATUS_IS_OK(status)) {
6947 reply_nterror(req, status);
6948 goto out;
6951 if (!lp_posix_pathnames()) {
6952 /* The newname must begin with a ':' if the
6953 name contains a ':'. */
6954 if (strchr_m(name, ':')) {
6955 if (newname[0] != ':') {
6956 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6957 goto out;
6959 stream_rename = true;
6963 status = filename_convert(ctx,
6964 conn,
6965 req->flags2 & FLAGS2_DFS_PATHNAMES,
6966 name,
6967 src_ucf_flags,
6968 &src_has_wcard,
6969 &smb_fname_src);
6971 if (!NT_STATUS_IS_OK(status)) {
6972 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6973 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6974 ERRSRV, ERRbadpath);
6975 goto out;
6977 reply_nterror(req, status);
6978 goto out;
6981 status = filename_convert(ctx,
6982 conn,
6983 req->flags2 & FLAGS2_DFS_PATHNAMES,
6984 newname,
6985 dst_ucf_flags,
6986 &dest_has_wcard,
6987 &smb_fname_dst);
6989 if (!NT_STATUS_IS_OK(status)) {
6990 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6991 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6992 ERRSRV, ERRbadpath);
6993 goto out;
6995 reply_nterror(req, status);
6996 goto out;
6999 if (stream_rename) {
7000 /* smb_fname_dst->base_name must be the same as
7001 smb_fname_src->base_name. */
7002 TALLOC_FREE(smb_fname_dst->base_name);
7003 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
7004 smb_fname_src->base_name);
7005 if (!smb_fname_dst->base_name) {
7006 reply_nterror(req, NT_STATUS_NO_MEMORY);
7007 goto out;
7011 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
7012 smb_fname_str_dbg(smb_fname_dst)));
7014 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
7015 attrs, False, src_has_wcard, dest_has_wcard,
7016 DELETE_ACCESS);
7017 if (!NT_STATUS_IS_OK(status)) {
7018 if (open_was_deferred(req->sconn, req->mid)) {
7019 /* We have re-scheduled this call. */
7020 goto out;
7022 reply_nterror(req, status);
7023 goto out;
7026 reply_outbuf(req, 0, 0);
7027 out:
7028 TALLOC_FREE(smb_fname_src);
7029 TALLOC_FREE(smb_fname_dst);
7030 END_PROFILE(SMBmv);
7031 return;
7034 /*******************************************************************
7035 Copy a file as part of a reply_copy.
7036 ******************************************************************/
7039 * TODO: check error codes on all callers
7042 NTSTATUS copy_file(TALLOC_CTX *ctx,
7043 connection_struct *conn,
7044 struct smb_filename *smb_fname_src,
7045 struct smb_filename *smb_fname_dst,
7046 int ofun,
7047 int count,
7048 bool target_is_directory)
7050 struct smb_filename *smb_fname_dst_tmp = NULL;
7051 off_t ret=-1;
7052 files_struct *fsp1,*fsp2;
7053 uint32 dosattrs;
7054 uint32 new_create_disposition;
7055 NTSTATUS status;
7058 smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
7059 if (smb_fname_dst_tmp == NULL) {
7060 return NT_STATUS_NO_MEMORY;
7064 * If the target is a directory, extract the last component from the
7065 * src filename and append it to the dst filename
7067 if (target_is_directory) {
7068 const char *p;
7070 /* dest/target can't be a stream if it's a directory. */
7071 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
7073 p = strrchr_m(smb_fname_src->base_name,'/');
7074 if (p) {
7075 p++;
7076 } else {
7077 p = smb_fname_src->base_name;
7079 smb_fname_dst_tmp->base_name =
7080 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
7082 if (!smb_fname_dst_tmp->base_name) {
7083 status = NT_STATUS_NO_MEMORY;
7084 goto out;
7088 status = vfs_file_exist(conn, smb_fname_src);
7089 if (!NT_STATUS_IS_OK(status)) {
7090 goto out;
7093 if (!target_is_directory && count) {
7094 new_create_disposition = FILE_OPEN;
7095 } else {
7096 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
7097 0, ofun,
7098 NULL, NULL,
7099 &new_create_disposition,
7100 NULL,
7101 NULL)) {
7102 status = NT_STATUS_INVALID_PARAMETER;
7103 goto out;
7107 /* Open the src file for reading. */
7108 status = SMB_VFS_CREATE_FILE(
7109 conn, /* conn */
7110 NULL, /* req */
7111 0, /* root_dir_fid */
7112 smb_fname_src, /* fname */
7113 FILE_GENERIC_READ, /* access_mask */
7114 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7115 FILE_OPEN, /* create_disposition*/
7116 0, /* create_options */
7117 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
7118 INTERNAL_OPEN_ONLY, /* oplock_request */
7119 0, /* allocation_size */
7120 0, /* private_flags */
7121 NULL, /* sd */
7122 NULL, /* ea_list */
7123 &fsp1, /* result */
7124 NULL); /* psbuf */
7126 if (!NT_STATUS_IS_OK(status)) {
7127 goto out;
7130 dosattrs = dos_mode(conn, smb_fname_src);
7132 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
7133 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
7136 /* Open the dst file for writing. */
7137 status = SMB_VFS_CREATE_FILE(
7138 conn, /* conn */
7139 NULL, /* req */
7140 0, /* root_dir_fid */
7141 smb_fname_dst, /* fname */
7142 FILE_GENERIC_WRITE, /* access_mask */
7143 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7144 new_create_disposition, /* create_disposition*/
7145 0, /* create_options */
7146 dosattrs, /* file_attributes */
7147 INTERNAL_OPEN_ONLY, /* oplock_request */
7148 0, /* allocation_size */
7149 0, /* private_flags */
7150 NULL, /* sd */
7151 NULL, /* ea_list */
7152 &fsp2, /* result */
7153 NULL); /* psbuf */
7155 if (!NT_STATUS_IS_OK(status)) {
7156 close_file(NULL, fsp1, ERROR_CLOSE);
7157 goto out;
7160 if (ofun & OPENX_FILE_EXISTS_OPEN) {
7161 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
7162 if (ret == -1) {
7163 DEBUG(0, ("error - vfs lseek returned error %s\n",
7164 strerror(errno)));
7165 status = map_nt_error_from_unix(errno);
7166 close_file(NULL, fsp1, ERROR_CLOSE);
7167 close_file(NULL, fsp2, ERROR_CLOSE);
7168 goto out;
7172 /* Do the actual copy. */
7173 if (smb_fname_src->st.st_ex_size) {
7174 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
7175 } else {
7176 ret = 0;
7179 close_file(NULL, fsp1, NORMAL_CLOSE);
7181 /* Ensure the modtime is set correctly on the destination file. */
7182 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
7185 * As we are opening fsp1 read-only we only expect
7186 * an error on close on fsp2 if we are out of space.
7187 * Thus we don't look at the error return from the
7188 * close of fsp1.
7190 status = close_file(NULL, fsp2, NORMAL_CLOSE);
7192 if (!NT_STATUS_IS_OK(status)) {
7193 goto out;
7196 if (ret != (off_t)smb_fname_src->st.st_ex_size) {
7197 status = NT_STATUS_DISK_FULL;
7198 goto out;
7201 status = NT_STATUS_OK;
7203 out:
7204 TALLOC_FREE(smb_fname_dst_tmp);
7205 return status;
7208 /****************************************************************************
7209 Reply to a file copy.
7210 ****************************************************************************/
7212 void reply_copy(struct smb_request *req)
7214 connection_struct *conn = req->conn;
7215 struct smb_filename *smb_fname_src = NULL;
7216 struct smb_filename *smb_fname_dst = NULL;
7217 char *fname_src = NULL;
7218 char *fname_dst = NULL;
7219 char *fname_src_mask = NULL;
7220 char *fname_src_dir = NULL;
7221 const char *p;
7222 int count=0;
7223 int error = ERRnoaccess;
7224 int tid2;
7225 int ofun;
7226 int flags;
7227 bool target_is_directory=False;
7228 bool source_has_wild = False;
7229 bool dest_has_wild = False;
7230 NTSTATUS status;
7231 TALLOC_CTX *ctx = talloc_tos();
7233 START_PROFILE(SMBcopy);
7235 if (req->wct < 3) {
7236 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7237 goto out;
7240 tid2 = SVAL(req->vwv+0, 0);
7241 ofun = SVAL(req->vwv+1, 0);
7242 flags = SVAL(req->vwv+2, 0);
7244 p = (const char *)req->buf;
7245 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
7246 &status, &source_has_wild);
7247 if (!NT_STATUS_IS_OK(status)) {
7248 reply_nterror(req, status);
7249 goto out;
7251 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
7252 &status, &dest_has_wild);
7253 if (!NT_STATUS_IS_OK(status)) {
7254 reply_nterror(req, status);
7255 goto out;
7258 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
7260 if (tid2 != conn->cnum) {
7261 /* can't currently handle inter share copies XXXX */
7262 DEBUG(3,("Rejecting inter-share copy\n"));
7263 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
7264 goto out;
7267 status = filename_convert(ctx, conn,
7268 req->flags2 & FLAGS2_DFS_PATHNAMES,
7269 fname_src,
7270 UCF_COND_ALLOW_WCARD_LCOMP,
7271 &source_has_wild,
7272 &smb_fname_src);
7273 if (!NT_STATUS_IS_OK(status)) {
7274 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7275 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7276 ERRSRV, ERRbadpath);
7277 goto out;
7279 reply_nterror(req, status);
7280 goto out;
7283 status = filename_convert(ctx, conn,
7284 req->flags2 & FLAGS2_DFS_PATHNAMES,
7285 fname_dst,
7286 UCF_COND_ALLOW_WCARD_LCOMP,
7287 &dest_has_wild,
7288 &smb_fname_dst);
7289 if (!NT_STATUS_IS_OK(status)) {
7290 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7291 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7292 ERRSRV, ERRbadpath);
7293 goto out;
7295 reply_nterror(req, status);
7296 goto out;
7299 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
7301 if ((flags&1) && target_is_directory) {
7302 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
7303 goto out;
7306 if ((flags&2) && !target_is_directory) {
7307 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
7308 goto out;
7311 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
7312 /* wants a tree copy! XXXX */
7313 DEBUG(3,("Rejecting tree copy\n"));
7314 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7315 goto out;
7318 /* Split up the directory from the filename/mask. */
7319 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7320 &fname_src_dir, &fname_src_mask);
7321 if (!NT_STATUS_IS_OK(status)) {
7322 reply_nterror(req, NT_STATUS_NO_MEMORY);
7323 goto out;
7327 * We should only check the mangled cache
7328 * here if unix_convert failed. This means
7329 * that the path in 'mask' doesn't exist
7330 * on the file system and so we need to look
7331 * for a possible mangle. This patch from
7332 * Tine Smukavec <valentin.smukavec@hermes.si>.
7334 if (!VALID_STAT(smb_fname_src->st) &&
7335 mangle_is_mangled(fname_src_mask, conn->params)) {
7336 char *new_mask = NULL;
7337 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
7338 &new_mask, conn->params);
7340 /* Use demangled name if one was successfully found. */
7341 if (new_mask) {
7342 TALLOC_FREE(fname_src_mask);
7343 fname_src_mask = new_mask;
7347 if (!source_has_wild) {
7350 * Only one file needs to be copied. Append the mask back onto
7351 * the directory.
7353 TALLOC_FREE(smb_fname_src->base_name);
7354 if (ISDOT(fname_src_dir)) {
7355 /* Ensure we use canonical names on open. */
7356 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7357 "%s",
7358 fname_src_mask);
7359 } else {
7360 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7361 "%s/%s",
7362 fname_src_dir,
7363 fname_src_mask);
7365 if (!smb_fname_src->base_name) {
7366 reply_nterror(req, NT_STATUS_NO_MEMORY);
7367 goto out;
7370 if (dest_has_wild) {
7371 char *fname_dst_mod = NULL;
7372 if (!resolve_wildcards(smb_fname_dst,
7373 smb_fname_src->base_name,
7374 smb_fname_dst->base_name,
7375 &fname_dst_mod)) {
7376 reply_nterror(req, NT_STATUS_NO_MEMORY);
7377 goto out;
7379 TALLOC_FREE(smb_fname_dst->base_name);
7380 smb_fname_dst->base_name = fname_dst_mod;
7383 status = check_name(conn, smb_fname_src->base_name);
7384 if (!NT_STATUS_IS_OK(status)) {
7385 reply_nterror(req, status);
7386 goto out;
7389 status = check_name(conn, smb_fname_dst->base_name);
7390 if (!NT_STATUS_IS_OK(status)) {
7391 reply_nterror(req, status);
7392 goto out;
7395 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7396 ofun, count, target_is_directory);
7398 if(!NT_STATUS_IS_OK(status)) {
7399 reply_nterror(req, status);
7400 goto out;
7401 } else {
7402 count++;
7404 } else {
7405 struct smb_Dir *dir_hnd = NULL;
7406 const char *dname = NULL;
7407 char *talloced = NULL;
7408 long offset = 0;
7411 * There is a wildcard that requires us to actually read the
7412 * src dir and copy each file matching the mask to the dst.
7413 * Right now streams won't be copied, but this could
7414 * presumably be added with a nested loop for reach dir entry.
7416 SMB_ASSERT(!smb_fname_src->stream_name);
7417 SMB_ASSERT(!smb_fname_dst->stream_name);
7419 smb_fname_src->stream_name = NULL;
7420 smb_fname_dst->stream_name = NULL;
7422 if (strequal(fname_src_mask,"????????.???")) {
7423 TALLOC_FREE(fname_src_mask);
7424 fname_src_mask = talloc_strdup(ctx, "*");
7425 if (!fname_src_mask) {
7426 reply_nterror(req, NT_STATUS_NO_MEMORY);
7427 goto out;
7431 status = check_name(conn, fname_src_dir);
7432 if (!NT_STATUS_IS_OK(status)) {
7433 reply_nterror(req, status);
7434 goto out;
7437 dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0);
7438 if (dir_hnd == NULL) {
7439 status = map_nt_error_from_unix(errno);
7440 reply_nterror(req, status);
7441 goto out;
7444 error = ERRbadfile;
7446 /* Iterate over the src dir copying each entry to the dst. */
7447 while ((dname = ReadDirName(dir_hnd, &offset,
7448 &smb_fname_src->st, &talloced))) {
7449 char *destname = NULL;
7451 if (ISDOT(dname) || ISDOTDOT(dname)) {
7452 TALLOC_FREE(talloced);
7453 continue;
7456 if (!is_visible_file(conn, fname_src_dir, dname,
7457 &smb_fname_src->st, false)) {
7458 TALLOC_FREE(talloced);
7459 continue;
7462 if(!mask_match(dname, fname_src_mask,
7463 conn->case_sensitive)) {
7464 TALLOC_FREE(talloced);
7465 continue;
7468 error = ERRnoaccess;
7470 /* Get the src smb_fname struct setup. */
7471 TALLOC_FREE(smb_fname_src->base_name);
7472 if (ISDOT(fname_src_dir)) {
7473 /* Ensure we use canonical names on open. */
7474 smb_fname_src->base_name =
7475 talloc_asprintf(smb_fname_src, "%s",
7476 dname);
7477 } else {
7478 smb_fname_src->base_name =
7479 talloc_asprintf(smb_fname_src, "%s/%s",
7480 fname_src_dir, dname);
7483 if (!smb_fname_src->base_name) {
7484 TALLOC_FREE(dir_hnd);
7485 TALLOC_FREE(talloced);
7486 reply_nterror(req, NT_STATUS_NO_MEMORY);
7487 goto out;
7490 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7491 smb_fname_dst->base_name,
7492 &destname)) {
7493 TALLOC_FREE(talloced);
7494 continue;
7496 if (!destname) {
7497 TALLOC_FREE(dir_hnd);
7498 TALLOC_FREE(talloced);
7499 reply_nterror(req, NT_STATUS_NO_MEMORY);
7500 goto out;
7503 TALLOC_FREE(smb_fname_dst->base_name);
7504 smb_fname_dst->base_name = destname;
7506 status = check_name(conn, smb_fname_src->base_name);
7507 if (!NT_STATUS_IS_OK(status)) {
7508 TALLOC_FREE(dir_hnd);
7509 TALLOC_FREE(talloced);
7510 reply_nterror(req, status);
7511 goto out;
7514 status = check_name(conn, smb_fname_dst->base_name);
7515 if (!NT_STATUS_IS_OK(status)) {
7516 TALLOC_FREE(dir_hnd);
7517 TALLOC_FREE(talloced);
7518 reply_nterror(req, status);
7519 goto out;
7522 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7523 smb_fname_src->base_name,
7524 smb_fname_dst->base_name));
7526 status = copy_file(ctx, conn, smb_fname_src,
7527 smb_fname_dst, ofun, count,
7528 target_is_directory);
7529 if (NT_STATUS_IS_OK(status)) {
7530 count++;
7533 TALLOC_FREE(talloced);
7535 TALLOC_FREE(dir_hnd);
7538 if (count == 0) {
7539 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7540 goto out;
7543 reply_outbuf(req, 1, 0);
7544 SSVAL(req->outbuf,smb_vwv0,count);
7545 out:
7546 TALLOC_FREE(smb_fname_src);
7547 TALLOC_FREE(smb_fname_dst);
7548 TALLOC_FREE(fname_src);
7549 TALLOC_FREE(fname_dst);
7550 TALLOC_FREE(fname_src_mask);
7551 TALLOC_FREE(fname_src_dir);
7553 END_PROFILE(SMBcopy);
7554 return;
7557 #undef DBGC_CLASS
7558 #define DBGC_CLASS DBGC_LOCKING
7560 /****************************************************************************
7561 Get a lock pid, dealing with large count requests.
7562 ****************************************************************************/
7564 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7565 bool large_file_format)
7567 if(!large_file_format)
7568 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7569 else
7570 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7573 /****************************************************************************
7574 Get a lock count, dealing with large count requests.
7575 ****************************************************************************/
7577 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7578 bool large_file_format)
7580 uint64_t count = 0;
7582 if(!large_file_format) {
7583 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7584 } else {
7586 #if defined(HAVE_LONGLONG)
7587 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7588 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7589 #else /* HAVE_LONGLONG */
7592 * NT4.x seems to be broken in that it sends large file (64 bit)
7593 * lockingX calls even if the CAP_LARGE_FILES was *not*
7594 * negotiated. For boxes without large unsigned ints truncate the
7595 * lock count by dropping the top 32 bits.
7598 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
7599 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
7600 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
7601 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
7602 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
7605 count = (uint64_t)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
7606 #endif /* HAVE_LONGLONG */
7609 return count;
7612 #if !defined(HAVE_LONGLONG)
7613 /****************************************************************************
7614 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
7615 ****************************************************************************/
7617 static uint32 map_lock_offset(uint32 high, uint32 low)
7619 unsigned int i;
7620 uint32 mask = 0;
7621 uint32 highcopy = high;
7624 * Try and find out how many significant bits there are in high.
7627 for(i = 0; highcopy; i++)
7628 highcopy >>= 1;
7631 * We use 31 bits not 32 here as POSIX
7632 * lock offsets may not be negative.
7635 mask = (~0) << (31 - i);
7637 if(low & mask)
7638 return 0; /* Fail. */
7640 high <<= (31 - i);
7642 return (high|low);
7644 #endif /* !defined(HAVE_LONGLONG) */
7646 /****************************************************************************
7647 Get a lock offset, dealing with large offset requests.
7648 ****************************************************************************/
7650 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7651 bool large_file_format, bool *err)
7653 uint64_t offset = 0;
7655 *err = False;
7657 if(!large_file_format) {
7658 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7659 } else {
7661 #if defined(HAVE_LONGLONG)
7662 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7663 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7664 #else /* HAVE_LONGLONG */
7667 * NT4.x seems to be broken in that it sends large file (64 bit)
7668 * lockingX calls even if the CAP_LARGE_FILES was *not*
7669 * negotiated. For boxes without large unsigned ints mangle the
7670 * lock offset by mapping the top 32 bits onto the lower 32.
7673 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
7674 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7675 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
7676 uint32 new_low = 0;
7678 if((new_low = map_lock_offset(high, low)) == 0) {
7679 *err = True;
7680 return (uint64_t)-1;
7683 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
7684 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
7685 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
7686 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
7689 offset = (uint64_t)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7690 #endif /* HAVE_LONGLONG */
7693 return offset;
7696 NTSTATUS smbd_do_locking(struct smb_request *req,
7697 files_struct *fsp,
7698 uint8_t type,
7699 int32_t timeout,
7700 uint16_t num_ulocks,
7701 struct smbd_lock_element *ulocks,
7702 uint16_t num_locks,
7703 struct smbd_lock_element *locks,
7704 bool *async)
7706 connection_struct *conn = req->conn;
7707 int i;
7708 NTSTATUS status = NT_STATUS_OK;
7710 *async = false;
7712 /* Data now points at the beginning of the list
7713 of smb_unlkrng structs */
7714 for(i = 0; i < (int)num_ulocks; i++) {
7715 struct smbd_lock_element *e = &ulocks[i];
7717 DEBUG(10,("smbd_do_locking: unlock start=%.0f, len=%.0f for "
7718 "pid %u, file %s\n",
7719 (double)e->offset,
7720 (double)e->count,
7721 (unsigned int)e->smblctx,
7722 fsp_str_dbg(fsp)));
7724 if (e->brltype != UNLOCK_LOCK) {
7725 /* this can only happen with SMB2 */
7726 return NT_STATUS_INVALID_PARAMETER;
7729 status = do_unlock(req->sconn->msg_ctx,
7730 fsp,
7731 e->smblctx,
7732 e->count,
7733 e->offset,
7734 WINDOWS_LOCK);
7736 DEBUG(10, ("smbd_do_locking: unlock returned %s\n",
7737 nt_errstr(status)));
7739 if (!NT_STATUS_IS_OK(status)) {
7740 return status;
7744 /* Setup the timeout in seconds. */
7746 if (!lp_blocking_locks(SNUM(conn))) {
7747 timeout = 0;
7750 /* Data now points at the beginning of the list
7751 of smb_lkrng structs */
7753 for(i = 0; i < (int)num_locks; i++) {
7754 struct smbd_lock_element *e = &locks[i];
7756 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
7757 "%llu, file %s timeout = %d\n",
7758 (double)e->offset,
7759 (double)e->count,
7760 (unsigned long long)e->smblctx,
7761 fsp_str_dbg(fsp),
7762 (int)timeout));
7764 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7765 struct blocking_lock_record *blr = NULL;
7767 if (num_locks > 1) {
7769 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
7770 * if the lock vector contains one entry. When given mutliple cancel
7771 * requests in a single PDU we expect the server to return an
7772 * error. Windows servers seem to accept the request but only
7773 * cancel the first lock.
7774 * JRA - Do what Windows does (tm) :-).
7777 #if 0
7778 /* MS-CIFS (2.2.4.32.1) behavior. */
7779 return NT_STATUS_DOS(ERRDOS,
7780 ERRcancelviolation);
7781 #else
7782 /* Windows behavior. */
7783 if (i != 0) {
7784 DEBUG(10,("smbd_do_locking: ignoring subsequent "
7785 "cancel request\n"));
7786 continue;
7788 #endif
7791 if (lp_blocking_locks(SNUM(conn))) {
7793 /* Schedule a message to ourselves to
7794 remove the blocking lock record and
7795 return the right error. */
7797 blr = blocking_lock_cancel_smb1(fsp,
7798 e->smblctx,
7799 e->offset,
7800 e->count,
7801 WINDOWS_LOCK,
7802 type,
7803 NT_STATUS_FILE_LOCK_CONFLICT);
7804 if (blr == NULL) {
7805 return NT_STATUS_DOS(
7806 ERRDOS,
7807 ERRcancelviolation);
7810 /* Remove a matching pending lock. */
7811 status = do_lock_cancel(fsp,
7812 e->smblctx,
7813 e->count,
7814 e->offset,
7815 WINDOWS_LOCK,
7816 blr);
7817 } else {
7818 bool blocking_lock = timeout ? true : false;
7819 bool defer_lock = false;
7820 struct byte_range_lock *br_lck;
7821 uint64_t block_smblctx;
7823 br_lck = do_lock(req->sconn->msg_ctx,
7824 fsp,
7825 e->smblctx,
7826 e->count,
7827 e->offset,
7828 e->brltype,
7829 WINDOWS_LOCK,
7830 blocking_lock,
7831 &status,
7832 &block_smblctx,
7833 NULL);
7835 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
7836 /* Windows internal resolution for blocking locks seems
7837 to be about 200ms... Don't wait for less than that. JRA. */
7838 if (timeout != -1 && timeout < lp_lock_spin_time()) {
7839 timeout = lp_lock_spin_time();
7841 defer_lock = true;
7844 /* If a lock sent with timeout of zero would fail, and
7845 * this lock has been requested multiple times,
7846 * according to brl_lock_failed() we convert this
7847 * request to a blocking lock with a timeout of between
7848 * 150 - 300 milliseconds.
7850 * If lp_lock_spin_time() has been set to 0, we skip
7851 * this blocking retry and fail immediately.
7853 * Replacement for do_lock_spin(). JRA. */
7855 if (!req->sconn->using_smb2 &&
7856 br_lck && lp_blocking_locks(SNUM(conn)) &&
7857 lp_lock_spin_time() && !blocking_lock &&
7858 NT_STATUS_EQUAL((status),
7859 NT_STATUS_FILE_LOCK_CONFLICT))
7861 defer_lock = true;
7862 timeout = lp_lock_spin_time();
7865 if (br_lck && defer_lock) {
7867 * A blocking lock was requested. Package up
7868 * this smb into a queued request and push it
7869 * onto the blocking lock queue.
7871 if(push_blocking_lock_request(br_lck,
7872 req,
7873 fsp,
7874 timeout,
7876 e->smblctx,
7877 e->brltype,
7878 WINDOWS_LOCK,
7879 e->offset,
7880 e->count,
7881 block_smblctx)) {
7882 TALLOC_FREE(br_lck);
7883 *async = true;
7884 return NT_STATUS_OK;
7888 TALLOC_FREE(br_lck);
7891 if (!NT_STATUS_IS_OK(status)) {
7892 break;
7896 /* If any of the above locks failed, then we must unlock
7897 all of the previous locks (X/Open spec). */
7899 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
7901 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7902 i = -1; /* we want to skip the for loop */
7906 * Ensure we don't do a remove on the lock that just failed,
7907 * as under POSIX rules, if we have a lock already there, we
7908 * will delete it (and we shouldn't) .....
7910 for(i--; i >= 0; i--) {
7911 struct smbd_lock_element *e = &locks[i];
7913 do_unlock(req->sconn->msg_ctx,
7914 fsp,
7915 e->smblctx,
7916 e->count,
7917 e->offset,
7918 WINDOWS_LOCK);
7920 return status;
7923 DEBUG(3, ("smbd_do_locking: %s type=%d num_locks=%d num_ulocks=%d\n",
7924 fsp_fnum_dbg(fsp), (unsigned int)type, num_locks, num_ulocks));
7926 return NT_STATUS_OK;
7929 /****************************************************************************
7930 Reply to a lockingX request.
7931 ****************************************************************************/
7933 void reply_lockingX(struct smb_request *req)
7935 connection_struct *conn = req->conn;
7936 files_struct *fsp;
7937 unsigned char locktype;
7938 unsigned char oplocklevel;
7939 uint16 num_ulocks;
7940 uint16 num_locks;
7941 int32 lock_timeout;
7942 int i;
7943 const uint8_t *data;
7944 bool large_file_format;
7945 bool err;
7946 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
7947 struct smbd_lock_element *ulocks;
7948 struct smbd_lock_element *locks;
7949 bool async = false;
7951 START_PROFILE(SMBlockingX);
7953 if (req->wct < 8) {
7954 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7955 END_PROFILE(SMBlockingX);
7956 return;
7959 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
7960 locktype = CVAL(req->vwv+3, 0);
7961 oplocklevel = CVAL(req->vwv+3, 1);
7962 num_ulocks = SVAL(req->vwv+6, 0);
7963 num_locks = SVAL(req->vwv+7, 0);
7964 lock_timeout = IVAL(req->vwv+4, 0);
7965 large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
7967 if (!check_fsp(conn, req, fsp)) {
7968 END_PROFILE(SMBlockingX);
7969 return;
7972 data = req->buf;
7974 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
7975 /* we don't support these - and CANCEL_LOCK makes w2k
7976 and XP reboot so I don't really want to be
7977 compatible! (tridge) */
7978 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
7979 END_PROFILE(SMBlockingX);
7980 return;
7983 /* Check if this is an oplock break on a file
7984 we have granted an oplock on.
7986 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
7987 /* Client can insist on breaking to none. */
7988 bool break_to_none = (oplocklevel == 0);
7989 bool result;
7991 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
7992 "for %s\n", (unsigned int)oplocklevel,
7993 fsp_fnum_dbg(fsp)));
7996 * Make sure we have granted an exclusive or batch oplock on
7997 * this file.
8000 if (fsp->oplock_type == 0) {
8002 /* The Samba4 nbench simulator doesn't understand
8003 the difference between break to level2 and break
8004 to none from level2 - it sends oplock break
8005 replies in both cases. Don't keep logging an error
8006 message here - just ignore it. JRA. */
8008 DEBUG(5,("reply_lockingX: Error : oplock break from "
8009 "client for %s (oplock=%d) and no "
8010 "oplock granted on this file (%s).\n",
8011 fsp_fnum_dbg(fsp), fsp->oplock_type,
8012 fsp_str_dbg(fsp)));
8014 /* if this is a pure oplock break request then don't
8015 * send a reply */
8016 if (num_locks == 0 && num_ulocks == 0) {
8017 END_PROFILE(SMBlockingX);
8018 return;
8019 } else {
8020 END_PROFILE(SMBlockingX);
8021 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
8022 return;
8026 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
8027 (break_to_none)) {
8028 result = remove_oplock(fsp);
8029 } else {
8030 result = downgrade_oplock(fsp);
8033 if (!result) {
8034 DEBUG(0, ("reply_lockingX: error in removing "
8035 "oplock on file %s\n", fsp_str_dbg(fsp)));
8036 /* Hmmm. Is this panic justified? */
8037 smb_panic("internal tdb error");
8040 /* if this is a pure oplock break request then don't send a
8041 * reply */
8042 if (num_locks == 0 && num_ulocks == 0) {
8043 /* Sanity check - ensure a pure oplock break is not a
8044 chained request. */
8045 if(CVAL(req->vwv+0, 0) != 0xff)
8046 DEBUG(0,("reply_lockingX: Error : pure oplock "
8047 "break is a chained %d request !\n",
8048 (unsigned int)CVAL(req->vwv+0, 0)));
8049 END_PROFILE(SMBlockingX);
8050 return;
8054 if (req->buflen <
8055 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
8056 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8057 END_PROFILE(SMBlockingX);
8058 return;
8061 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
8062 if (ulocks == NULL) {
8063 reply_nterror(req, NT_STATUS_NO_MEMORY);
8064 END_PROFILE(SMBlockingX);
8065 return;
8068 locks = talloc_array(req, struct smbd_lock_element, num_locks);
8069 if (locks == NULL) {
8070 reply_nterror(req, NT_STATUS_NO_MEMORY);
8071 END_PROFILE(SMBlockingX);
8072 return;
8075 /* Data now points at the beginning of the list
8076 of smb_unlkrng structs */
8077 for(i = 0; i < (int)num_ulocks; i++) {
8078 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
8079 ulocks[i].count = get_lock_count(data, i, large_file_format);
8080 ulocks[i].offset = get_lock_offset(data, i, large_file_format, &err);
8081 ulocks[i].brltype = UNLOCK_LOCK;
8084 * There is no error code marked "stupid client bug".... :-).
8086 if(err) {
8087 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8088 END_PROFILE(SMBlockingX);
8089 return;
8093 /* Now do any requested locks */
8094 data += ((large_file_format ? 20 : 10)*num_ulocks);
8096 /* Data now points at the beginning of the list
8097 of smb_lkrng structs */
8099 for(i = 0; i < (int)num_locks; i++) {
8100 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
8101 locks[i].count = get_lock_count(data, i, large_file_format);
8102 locks[i].offset = get_lock_offset(data, i, large_file_format, &err);
8104 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
8105 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8106 locks[i].brltype = PENDING_READ_LOCK;
8107 } else {
8108 locks[i].brltype = READ_LOCK;
8110 } else {
8111 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8112 locks[i].brltype = PENDING_WRITE_LOCK;
8113 } else {
8114 locks[i].brltype = WRITE_LOCK;
8119 * There is no error code marked "stupid client bug".... :-).
8121 if(err) {
8122 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8123 END_PROFILE(SMBlockingX);
8124 return;
8128 status = smbd_do_locking(req, fsp,
8129 locktype, lock_timeout,
8130 num_ulocks, ulocks,
8131 num_locks, locks,
8132 &async);
8133 if (!NT_STATUS_IS_OK(status)) {
8134 END_PROFILE(SMBlockingX);
8135 reply_nterror(req, status);
8136 return;
8138 if (async) {
8139 END_PROFILE(SMBlockingX);
8140 return;
8143 reply_outbuf(req, 2, 0);
8144 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
8145 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
8147 DEBUG(3, ("lockingX %s type=%d num_locks=%d num_ulocks=%d\n",
8148 fsp_fnum_dbg(fsp), (unsigned int)locktype, num_locks, num_ulocks));
8150 END_PROFILE(SMBlockingX);
8153 #undef DBGC_CLASS
8154 #define DBGC_CLASS DBGC_ALL
8156 /****************************************************************************
8157 Reply to a SMBreadbmpx (read block multiplex) request.
8158 Always reply with an error, if someone has a platform really needs this,
8159 please contact vl@samba.org
8160 ****************************************************************************/
8162 void reply_readbmpx(struct smb_request *req)
8164 START_PROFILE(SMBreadBmpx);
8165 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8166 END_PROFILE(SMBreadBmpx);
8167 return;
8170 /****************************************************************************
8171 Reply to a SMBreadbs (read block multiplex secondary) request.
8172 Always reply with an error, if someone has a platform really needs this,
8173 please contact vl@samba.org
8174 ****************************************************************************/
8176 void reply_readbs(struct smb_request *req)
8178 START_PROFILE(SMBreadBs);
8179 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8180 END_PROFILE(SMBreadBs);
8181 return;
8184 /****************************************************************************
8185 Reply to a SMBsetattrE.
8186 ****************************************************************************/
8188 void reply_setattrE(struct smb_request *req)
8190 connection_struct *conn = req->conn;
8191 struct smb_file_time ft;
8192 files_struct *fsp;
8193 NTSTATUS status;
8195 START_PROFILE(SMBsetattrE);
8196 ZERO_STRUCT(ft);
8198 if (req->wct < 7) {
8199 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8200 goto out;
8203 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8205 if(!fsp || (fsp->conn != conn)) {
8206 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8207 goto out;
8211 * Convert the DOS times into unix times.
8214 ft.atime = convert_time_t_to_timespec(
8215 srv_make_unix_date2(req->vwv+3));
8216 ft.mtime = convert_time_t_to_timespec(
8217 srv_make_unix_date2(req->vwv+5));
8218 ft.create_time = convert_time_t_to_timespec(
8219 srv_make_unix_date2(req->vwv+1));
8221 reply_outbuf(req, 0, 0);
8224 * Patch from Ray Frush <frush@engr.colostate.edu>
8225 * Sometimes times are sent as zero - ignore them.
8228 /* Ensure we have a valid stat struct for the source. */
8229 status = vfs_stat_fsp(fsp);
8230 if (!NT_STATUS_IS_OK(status)) {
8231 reply_nterror(req, status);
8232 goto out;
8235 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
8236 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8237 goto out;
8240 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
8241 if (!NT_STATUS_IS_OK(status)) {
8242 reply_nterror(req, status);
8243 goto out;
8246 DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
8247 " createtime=%u\n",
8248 fsp_fnum_dbg(fsp),
8249 (unsigned int)ft.atime.tv_sec,
8250 (unsigned int)ft.mtime.tv_sec,
8251 (unsigned int)ft.create_time.tv_sec
8253 out:
8254 END_PROFILE(SMBsetattrE);
8255 return;
8259 /* Back from the dead for OS/2..... JRA. */
8261 /****************************************************************************
8262 Reply to a SMBwritebmpx (write block multiplex primary) request.
8263 Always reply with an error, if someone has a platform really needs this,
8264 please contact vl@samba.org
8265 ****************************************************************************/
8267 void reply_writebmpx(struct smb_request *req)
8269 START_PROFILE(SMBwriteBmpx);
8270 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8271 END_PROFILE(SMBwriteBmpx);
8272 return;
8275 /****************************************************************************
8276 Reply to a SMBwritebs (write block multiplex secondary) request.
8277 Always reply with an error, if someone has a platform really needs this,
8278 please contact vl@samba.org
8279 ****************************************************************************/
8281 void reply_writebs(struct smb_request *req)
8283 START_PROFILE(SMBwriteBs);
8284 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8285 END_PROFILE(SMBwriteBs);
8286 return;
8289 /****************************************************************************
8290 Reply to a SMBgetattrE.
8291 ****************************************************************************/
8293 void reply_getattrE(struct smb_request *req)
8295 connection_struct *conn = req->conn;
8296 int mode;
8297 files_struct *fsp;
8298 struct timespec create_ts;
8300 START_PROFILE(SMBgetattrE);
8302 if (req->wct < 1) {
8303 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8304 END_PROFILE(SMBgetattrE);
8305 return;
8308 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8310 if(!fsp || (fsp->conn != conn)) {
8311 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8312 END_PROFILE(SMBgetattrE);
8313 return;
8316 /* Do an fstat on this file */
8317 if(fsp_stat(fsp)) {
8318 reply_nterror(req, map_nt_error_from_unix(errno));
8319 END_PROFILE(SMBgetattrE);
8320 return;
8323 mode = dos_mode(conn, fsp->fsp_name);
8326 * Convert the times into dos times. Set create
8327 * date to be last modify date as UNIX doesn't save
8328 * this.
8331 reply_outbuf(req, 11, 0);
8333 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
8334 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
8335 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
8336 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
8337 /* Should we check pending modtime here ? JRA */
8338 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
8339 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
8341 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
8342 SIVAL(req->outbuf, smb_vwv6, 0);
8343 SIVAL(req->outbuf, smb_vwv8, 0);
8344 } else {
8345 uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8346 SIVAL(req->outbuf, smb_vwv6, (uint32)fsp->fsp_name->st.st_ex_size);
8347 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8349 SSVAL(req->outbuf,smb_vwv10, mode);
8351 DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp)));
8353 END_PROFILE(SMBgetattrE);
8354 return;