libcli/smb: add basic session->smb2.channel_sequence handling
[Samba/gebeck_regimport.git] / source3 / smbd / reply.c
blobc043bb6e0639d2677155caaf41c92352be9e43c9
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"
46 /****************************************************************************
47 Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
48 path or anything including wildcards.
49 We're assuming here that '/' is not the second byte in any multibyte char
50 set (a safe assumption). '\\' *may* be the second byte in a multibyte char
51 set.
52 ****************************************************************************/
54 /* Custom version for processing POSIX paths. */
55 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
57 static NTSTATUS check_path_syntax_internal(char *path,
58 bool posix_path,
59 bool *p_last_component_contains_wcard)
61 char *d = path;
62 const char *s = path;
63 NTSTATUS ret = NT_STATUS_OK;
64 bool start_of_name_component = True;
65 bool stream_started = false;
67 *p_last_component_contains_wcard = False;
69 while (*s) {
70 if (stream_started) {
71 switch (*s) {
72 case '/':
73 case '\\':
74 return NT_STATUS_OBJECT_NAME_INVALID;
75 case ':':
76 if (s[1] == '\0') {
77 return NT_STATUS_OBJECT_NAME_INVALID;
79 if (strchr_m(&s[1], ':')) {
80 return NT_STATUS_OBJECT_NAME_INVALID;
82 break;
86 if ((*s == ':') && !posix_path && !stream_started) {
87 if (*p_last_component_contains_wcard) {
88 return NT_STATUS_OBJECT_NAME_INVALID;
90 /* Stream names allow more characters than file names.
91 We're overloading posix_path here to allow a wider
92 range of characters. If stream_started is true this
93 is still a Windows path even if posix_path is true.
94 JRA.
96 stream_started = true;
97 start_of_name_component = false;
98 posix_path = true;
100 if (s[1] == '\0') {
101 return NT_STATUS_OBJECT_NAME_INVALID;
105 if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
107 * Safe to assume is not the second part of a mb char
108 * as this is handled below.
110 /* Eat multiple '/' or '\\' */
111 while (IS_PATH_SEP(*s,posix_path)) {
112 s++;
114 if ((d != path) && (*s != '\0')) {
115 /* We only care about non-leading or trailing '/' or '\\' */
116 *d++ = '/';
119 start_of_name_component = True;
120 /* New component. */
121 *p_last_component_contains_wcard = False;
122 continue;
125 if (start_of_name_component) {
126 if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
127 /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
130 * No mb char starts with '.' so we're safe checking the directory separator here.
133 /* If we just added a '/' - delete it */
134 if ((d > path) && (*(d-1) == '/')) {
135 *(d-1) = '\0';
136 d--;
139 /* Are we at the start ? Can't go back further if so. */
140 if (d <= path) {
141 ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
142 break;
144 /* Go back one level... */
145 /* We know this is safe as '/' cannot be part of a mb sequence. */
146 /* NOTE - if this assumption is invalid we are not in good shape... */
147 /* Decrement d first as d points to the *next* char to write into. */
148 for (d--; d > path; d--) {
149 if (*d == '/')
150 break;
152 s += 2; /* Else go past the .. */
153 /* We're still at the start of a name component, just the previous one. */
154 continue;
156 } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
157 if (posix_path) {
158 /* Eat the '.' */
159 s++;
160 continue;
166 if (!(*s & 0x80)) {
167 if (!posix_path) {
168 if (*s <= 0x1f || *s == '|') {
169 return NT_STATUS_OBJECT_NAME_INVALID;
171 switch (*s) {
172 case '*':
173 case '?':
174 case '<':
175 case '>':
176 case '"':
177 *p_last_component_contains_wcard = True;
178 break;
179 default:
180 break;
183 *d++ = *s++;
184 } else {
185 size_t siz;
186 /* Get the size of the next MB character. */
187 next_codepoint(s,&siz);
188 switch(siz) {
189 case 5:
190 *d++ = *s++;
191 /*fall through*/
192 case 4:
193 *d++ = *s++;
194 /*fall through*/
195 case 3:
196 *d++ = *s++;
197 /*fall through*/
198 case 2:
199 *d++ = *s++;
200 /*fall through*/
201 case 1:
202 *d++ = *s++;
203 break;
204 default:
205 DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
206 *d = '\0';
207 return NT_STATUS_INVALID_PARAMETER;
210 start_of_name_component = False;
213 *d = '\0';
215 return ret;
218 /****************************************************************************
219 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
220 No wildcards allowed.
221 ****************************************************************************/
223 NTSTATUS check_path_syntax(char *path)
225 bool ignore;
226 return check_path_syntax_internal(path, False, &ignore);
229 /****************************************************************************
230 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
231 Wildcards allowed - p_contains_wcard returns true if the last component contained
232 a wildcard.
233 ****************************************************************************/
235 NTSTATUS check_path_syntax_wcard(char *path, bool *p_contains_wcard)
237 return check_path_syntax_internal(path, False, p_contains_wcard);
240 /****************************************************************************
241 Check the path for a POSIX client.
242 We're assuming here that '/' is not the second byte in any multibyte char
243 set (a safe assumption).
244 ****************************************************************************/
246 NTSTATUS check_path_syntax_posix(char *path)
248 bool ignore;
249 return check_path_syntax_internal(path, True, &ignore);
252 /****************************************************************************
253 Pull a string and check the path allowing a wilcard - provide for error return.
254 ****************************************************************************/
256 size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
257 const char *base_ptr,
258 uint16 smb_flags2,
259 char **pp_dest,
260 const char *src,
261 size_t src_len,
262 int flags,
263 NTSTATUS *err,
264 bool *contains_wcard)
266 size_t ret;
268 *pp_dest = NULL;
270 ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
271 src_len, flags);
273 if (!*pp_dest) {
274 *err = NT_STATUS_INVALID_PARAMETER;
275 return ret;
278 *contains_wcard = False;
280 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
282 * For a DFS path the function parse_dfs_path()
283 * will do the path processing, just make a copy.
285 *err = NT_STATUS_OK;
286 return ret;
289 if (lp_posix_pathnames()) {
290 *err = check_path_syntax_posix(*pp_dest);
291 } else {
292 *err = check_path_syntax_wcard(*pp_dest, contains_wcard);
295 return ret;
298 /****************************************************************************
299 Pull a string and check the path - provide for error return.
300 ****************************************************************************/
302 size_t srvstr_get_path(TALLOC_CTX *ctx,
303 const char *base_ptr,
304 uint16 smb_flags2,
305 char **pp_dest,
306 const char *src,
307 size_t src_len,
308 int flags,
309 NTSTATUS *err)
311 bool ignore;
312 return srvstr_get_path_wcard(ctx, base_ptr, smb_flags2, pp_dest, src,
313 src_len, flags, err, &ignore);
316 size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req,
317 char **pp_dest, const char *src, int flags,
318 NTSTATUS *err, bool *contains_wcard)
320 return srvstr_get_path_wcard(mem_ctx, (const char *)req->inbuf, req->flags2,
321 pp_dest, src, smbreq_bufrem(req, src),
322 flags, err, contains_wcard);
325 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
326 char **pp_dest, const char *src, int flags,
327 NTSTATUS *err)
329 bool ignore;
330 return srvstr_get_path_req_wcard(mem_ctx, req, pp_dest, src,
331 flags, err, &ignore);
334 /****************************************************************************
335 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
336 ****************************************************************************/
338 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
339 files_struct *fsp)
341 if ((fsp == NULL) || (conn == NULL)) {
342 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
343 return False;
345 if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
346 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
347 return False;
349 return True;
352 /****************************************************************************
353 Check if we have a correct fsp pointing to a file.
354 ****************************************************************************/
356 bool check_fsp(connection_struct *conn, struct smb_request *req,
357 files_struct *fsp)
359 if (!check_fsp_open(conn, req, fsp)) {
360 return False;
362 if (fsp->is_directory) {
363 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
364 return False;
366 if (fsp->fh->fd == -1) {
367 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
368 return False;
370 fsp->num_smb_operations++;
371 return True;
374 /****************************************************************************
375 Check if we have a correct fsp pointing to a quota fake file. Replacement for
376 the CHECK_NTQUOTA_HANDLE_OK macro.
377 ****************************************************************************/
379 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
380 files_struct *fsp)
382 if (!check_fsp_open(conn, req, fsp)) {
383 return false;
386 if (fsp->is_directory) {
387 return false;
390 if (fsp->fake_file_handle == NULL) {
391 return false;
394 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
395 return false;
398 if (fsp->fake_file_handle->private_data == NULL) {
399 return false;
402 return true;
405 static bool netbios_session_retarget(struct smbd_server_connection *sconn,
406 const char *name, int name_type)
408 char *trim_name;
409 char *trim_name_type;
410 const char *retarget_parm;
411 char *retarget;
412 char *p;
413 int retarget_type = 0x20;
414 int retarget_port = NBT_SMB_PORT;
415 struct sockaddr_storage retarget_addr;
416 struct sockaddr_in *in_addr;
417 bool ret = false;
418 uint8_t outbuf[10];
420 if (get_socket_port(sconn->sock) != NBT_SMB_PORT) {
421 return false;
424 trim_name = talloc_strdup(talloc_tos(), name);
425 if (trim_name == NULL) {
426 goto fail;
428 trim_char(trim_name, ' ', ' ');
430 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
431 name_type);
432 if (trim_name_type == NULL) {
433 goto fail;
436 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
437 trim_name_type, NULL);
438 if (retarget_parm == NULL) {
439 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
440 trim_name, NULL);
442 if (retarget_parm == NULL) {
443 goto fail;
446 retarget = talloc_strdup(trim_name, retarget_parm);
447 if (retarget == NULL) {
448 goto fail;
451 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
453 p = strchr(retarget, ':');
454 if (p != NULL) {
455 *p++ = '\0';
456 retarget_port = atoi(p);
459 p = strchr_m(retarget, '#');
460 if (p != NULL) {
461 *p++ = '\0';
462 if (sscanf(p, "%x", &retarget_type) != 1) {
463 goto fail;
467 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
468 if (!ret) {
469 DEBUG(10, ("could not resolve %s\n", retarget));
470 goto fail;
473 if (retarget_addr.ss_family != AF_INET) {
474 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
475 goto fail;
478 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
480 _smb_setlen(outbuf, 6);
481 SCVAL(outbuf, 0, 0x84);
482 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
483 *(uint16_t *)(outbuf+8) = htons(retarget_port);
485 if (!srv_send_smb(sconn, (char *)outbuf, false, 0, false,
486 NULL)) {
487 exit_server_cleanly("netbios_session_retarget: srv_send_smb "
488 "failed.");
491 ret = true;
492 fail:
493 TALLOC_FREE(trim_name);
494 return ret;
497 static void reply_called_name_not_present(char *outbuf)
499 smb_setlen(outbuf, 1);
500 SCVAL(outbuf, 0, 0x83);
501 SCVAL(outbuf, 4, 0x82);
504 /****************************************************************************
505 Reply to a (netbios-level) special message.
506 ****************************************************************************/
508 void reply_special(struct smbd_server_connection *sconn, char *inbuf, size_t inbuf_size)
510 int msg_type = CVAL(inbuf,0);
511 int msg_flags = CVAL(inbuf,1);
513 * We only really use 4 bytes of the outbuf, but for the smb_setlen
514 * calculation & friends (srv_send_smb uses that) we need the full smb
515 * header.
517 char outbuf[smb_size];
519 memset(outbuf, '\0', sizeof(outbuf));
521 smb_setlen(outbuf,0);
523 switch (msg_type) {
524 case NBSSrequest: /* session request */
526 /* inbuf_size is guarenteed to be at least 4. */
527 fstring name1,name2;
528 int name_type1, name_type2;
529 int name_len1, name_len2;
531 *name1 = *name2 = 0;
533 if (sconn->nbt.got_session) {
534 exit_server_cleanly("multiple session request not permitted");
537 SCVAL(outbuf,0,NBSSpositive);
538 SCVAL(outbuf,3,0);
540 /* inbuf_size is guaranteed to be at least 4. */
541 name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
542 if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
543 DEBUG(0,("Invalid name length in session request\n"));
544 reply_called_name_not_present(outbuf);
545 break;
547 name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
548 if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
549 DEBUG(0,("Invalid name length in session request\n"));
550 reply_called_name_not_present(outbuf);
551 break;
554 name_type1 = name_extract((unsigned char *)inbuf,
555 inbuf_size,(unsigned int)4,name1);
556 name_type2 = name_extract((unsigned char *)inbuf,
557 inbuf_size,(unsigned int)(4 + name_len1),name2);
559 if (name_type1 == -1 || name_type2 == -1) {
560 DEBUG(0,("Invalid name type in session request\n"));
561 reply_called_name_not_present(outbuf);
562 break;
565 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
566 name1, name_type1, name2, name_type2));
568 if (netbios_session_retarget(sconn, name1, name_type1)) {
569 exit_server_cleanly("retargeted client");
573 * Windows NT/2k uses "*SMBSERVER" and XP uses
574 * "*SMBSERV" arrggg!!!
576 if (strequal(name1, "*SMBSERVER ")
577 || strequal(name1, "*SMBSERV ")) {
578 char *raddr;
580 raddr = tsocket_address_inet_addr_string(sconn->remote_address,
581 talloc_tos());
582 if (raddr == NULL) {
583 exit_server_cleanly("could not allocate raddr");
586 fstrcpy(name1, raddr);
589 set_local_machine_name(name1, True);
590 set_remote_machine_name(name2, True);
592 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
593 get_local_machine_name(), get_remote_machine_name(),
594 name_type2));
596 if (name_type2 == 'R') {
597 /* We are being asked for a pathworks session ---
598 no thanks! */
599 reply_called_name_not_present(outbuf);
600 break;
603 reload_services(sconn, conn_snum_used, true);
604 reopen_logs();
606 sconn->nbt.got_session = true;
607 break;
610 case 0x89: /* session keepalive request
611 (some old clients produce this?) */
612 SCVAL(outbuf,0,NBSSkeepalive);
613 SCVAL(outbuf,3,0);
614 break;
616 case NBSSpositive: /* positive session response */
617 case NBSSnegative: /* negative session response */
618 case NBSSretarget: /* retarget session response */
619 DEBUG(0,("Unexpected session response\n"));
620 break;
622 case NBSSkeepalive: /* session keepalive */
623 default:
624 return;
627 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
628 msg_type, msg_flags));
630 srv_send_smb(sconn, outbuf, false, 0, false, NULL);
632 if (CVAL(outbuf, 0) != 0x82) {
633 exit_server_cleanly("invalid netbios session");
635 return;
638 /****************************************************************************
639 Reply to a tcon.
640 conn POINTER CAN BE NULL HERE !
641 ****************************************************************************/
643 void reply_tcon(struct smb_request *req)
645 connection_struct *conn = req->conn;
646 const char *service;
647 char *service_buf = NULL;
648 char *password = NULL;
649 char *dev = NULL;
650 int pwlen=0;
651 NTSTATUS nt_status;
652 const char *p;
653 TALLOC_CTX *ctx = talloc_tos();
654 struct smbd_server_connection *sconn = req->sconn;
656 START_PROFILE(SMBtcon);
658 if (req->buflen < 4) {
659 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
660 END_PROFILE(SMBtcon);
661 return;
664 p = (const char *)req->buf + 1;
665 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
666 p += 1;
667 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
668 p += pwlen+1;
669 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
670 p += 1;
672 if (service_buf == NULL || password == NULL || dev == NULL) {
673 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
674 END_PROFILE(SMBtcon);
675 return;
677 p = strrchr_m(service_buf,'\\');
678 if (p) {
679 service = p+1;
680 } else {
681 service = service_buf;
684 conn = make_connection(sconn,service,dev,
685 req->vuid,&nt_status);
686 req->conn = conn;
688 if (!conn) {
689 reply_nterror(req, nt_status);
690 END_PROFILE(SMBtcon);
691 return;
694 reply_outbuf(req, 2, 0);
695 SSVAL(req->outbuf,smb_vwv0,sconn->smb1.negprot.max_recv);
696 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
697 SSVAL(req->outbuf,smb_tid,conn->cnum);
699 DEBUG(3,("tcon service=%s cnum=%d\n",
700 service, conn->cnum));
702 END_PROFILE(SMBtcon);
703 return;
706 /****************************************************************************
707 Reply to a tcon and X.
708 conn POINTER CAN BE NULL HERE !
709 ****************************************************************************/
711 void reply_tcon_and_X(struct smb_request *req)
713 connection_struct *conn = req->conn;
714 const char *service = NULL;
715 TALLOC_CTX *ctx = talloc_tos();
716 /* what the cleint thinks the device is */
717 char *client_devicetype = NULL;
718 /* what the server tells the client the share represents */
719 const char *server_devicetype;
720 NTSTATUS nt_status;
721 int passlen;
722 char *path = NULL;
723 const char *p, *q;
724 uint16 tcon_flags;
725 struct smbd_server_connection *sconn = req->sconn;
727 START_PROFILE(SMBtconX);
729 if (req->wct < 4) {
730 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
731 END_PROFILE(SMBtconX);
732 return;
735 passlen = SVAL(req->vwv+3, 0);
736 tcon_flags = SVAL(req->vwv+2, 0);
738 /* we might have to close an old one */
739 if ((tcon_flags & 0x1) && conn) {
740 struct smbXsrv_tcon *tcon;
741 NTSTATUS status;
743 tcon = conn->tcon;
744 req->conn = NULL;
745 conn = NULL;
748 * TODO: cancel all outstanding requests on the tcon
750 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
751 if (!NT_STATUS_IS_OK(status)) {
752 DEBUG(0, ("reply_tcon_and_X: "
753 "smbXsrv_tcon_disconnect() failed: %s\n",
754 nt_errstr(status)));
756 * If we hit this case, there is something completely
757 * wrong, so we better disconnect the transport connection.
759 END_PROFILE(SMBtconX);
760 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
761 return;
764 TALLOC_FREE(tcon);
767 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
768 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
769 END_PROFILE(SMBtconX);
770 return;
773 if (sconn->smb1.negprot.encrypted_passwords) {
774 p = (const char *)req->buf + passlen;
775 } else {
776 p = (const char *)req->buf + passlen + 1;
779 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
781 if (path == NULL) {
782 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
783 END_PROFILE(SMBtconX);
784 return;
788 * the service name can be either: \\server\share
789 * or share directly like on the DELL PowerVault 705
791 if (*path=='\\') {
792 q = strchr_m(path+2,'\\');
793 if (!q) {
794 reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
795 END_PROFILE(SMBtconX);
796 return;
798 service = q+1;
799 } else {
800 service = path;
803 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
804 &client_devicetype, p,
805 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
807 if (client_devicetype == NULL) {
808 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
809 END_PROFILE(SMBtconX);
810 return;
813 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
815 conn = make_connection(sconn, service, client_devicetype,
816 req->vuid, &nt_status);
817 req->conn =conn;
819 if (!conn) {
820 reply_nterror(req, nt_status);
821 END_PROFILE(SMBtconX);
822 return;
825 if ( IS_IPC(conn) )
826 server_devicetype = "IPC";
827 else if ( IS_PRINT(conn) )
828 server_devicetype = "LPT1:";
829 else
830 server_devicetype = "A:";
832 if (get_Protocol() < PROTOCOL_NT1) {
833 reply_outbuf(req, 2, 0);
834 if (message_push_string(&req->outbuf, server_devicetype,
835 STR_TERMINATE|STR_ASCII) == -1) {
836 reply_nterror(req, NT_STATUS_NO_MEMORY);
837 END_PROFILE(SMBtconX);
838 return;
840 } else {
841 /* NT sets the fstype of IPC$ to the null string */
842 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(ctx, SNUM(conn));
844 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
845 /* Return permissions. */
846 uint32 perm1 = 0;
847 uint32 perm2 = 0;
849 reply_outbuf(req, 7, 0);
851 if (IS_IPC(conn)) {
852 perm1 = FILE_ALL_ACCESS;
853 perm2 = FILE_ALL_ACCESS;
854 } else {
855 perm1 = conn->share_access;
858 SIVAL(req->outbuf, smb_vwv3, perm1);
859 SIVAL(req->outbuf, smb_vwv5, perm2);
860 } else {
861 reply_outbuf(req, 3, 0);
864 if ((message_push_string(&req->outbuf, server_devicetype,
865 STR_TERMINATE|STR_ASCII) == -1)
866 || (message_push_string(&req->outbuf, fstype,
867 STR_TERMINATE) == -1)) {
868 reply_nterror(req, NT_STATUS_NO_MEMORY);
869 END_PROFILE(SMBtconX);
870 return;
873 /* what does setting this bit do? It is set by NT4 and
874 may affect the ability to autorun mounted cdroms */
875 SSVAL(req->outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS|
876 (lp_csc_policy(SNUM(conn)) << 2));
878 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
879 DEBUG(2,("Serving %s as a Dfs root\n",
880 lp_servicename(ctx, SNUM(conn)) ));
881 SSVAL(req->outbuf, smb_vwv2,
882 SMB_SHARE_IN_DFS | SVAL(req->outbuf, smb_vwv2));
886 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
887 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
889 DEBUG(3,("tconX service=%s \n",
890 service));
892 /* set the incoming and outgoing tid to the just created one */
893 SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
894 SSVAL(req->outbuf,smb_tid,conn->cnum);
896 END_PROFILE(SMBtconX);
898 req->tid = conn->cnum;
901 /****************************************************************************
902 Reply to an unknown type.
903 ****************************************************************************/
905 void reply_unknown_new(struct smb_request *req, uint8 type)
907 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
908 smb_fn_name(type), type, type));
909 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
910 return;
913 /****************************************************************************
914 Reply to an ioctl.
915 conn POINTER CAN BE NULL HERE !
916 ****************************************************************************/
918 void reply_ioctl(struct smb_request *req)
920 connection_struct *conn = req->conn;
921 uint16 device;
922 uint16 function;
923 uint32 ioctl_code;
924 int replysize;
925 char *p;
927 START_PROFILE(SMBioctl);
929 if (req->wct < 3) {
930 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
931 END_PROFILE(SMBioctl);
932 return;
935 device = SVAL(req->vwv+1, 0);
936 function = SVAL(req->vwv+2, 0);
937 ioctl_code = (device << 16) + function;
939 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
941 switch (ioctl_code) {
942 case IOCTL_QUERY_JOB_INFO:
943 replysize = 32;
944 break;
945 default:
946 reply_force_doserror(req, ERRSRV, ERRnosupport);
947 END_PROFILE(SMBioctl);
948 return;
951 reply_outbuf(req, 8, replysize+1);
952 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
953 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
954 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
955 p = smb_buf(req->outbuf);
956 memset(p, '\0', replysize+1); /* valgrind-safe. */
957 p += 1; /* Allow for alignment */
959 switch (ioctl_code) {
960 case IOCTL_QUERY_JOB_INFO:
962 files_struct *fsp = file_fsp(
963 req, SVAL(req->vwv+0, 0));
964 if (!fsp) {
965 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
966 END_PROFILE(SMBioctl);
967 return;
969 /* Job number */
970 SSVAL(p, 0, print_spool_rap_jobid(fsp->print_file));
972 srvstr_push((char *)req->outbuf, req->flags2, p+2,
973 lp_netbios_name(), 15,
974 STR_TERMINATE|STR_ASCII);
975 if (conn) {
976 srvstr_push((char *)req->outbuf, req->flags2,
977 p+18,
978 lp_servicename(talloc_tos(),
979 SNUM(conn)),
980 13, STR_TERMINATE|STR_ASCII);
981 } else {
982 memset(p+18, 0, 13);
984 break;
988 END_PROFILE(SMBioctl);
989 return;
992 /****************************************************************************
993 Strange checkpath NTSTATUS mapping.
994 ****************************************************************************/
996 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
998 /* Strange DOS error code semantics only for checkpath... */
999 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
1000 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
1001 /* We need to map to ERRbadpath */
1002 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1005 return status;
1008 /****************************************************************************
1009 Reply to a checkpath.
1010 ****************************************************************************/
1012 void reply_checkpath(struct smb_request *req)
1014 connection_struct *conn = req->conn;
1015 struct smb_filename *smb_fname = NULL;
1016 char *name = NULL;
1017 NTSTATUS status;
1018 TALLOC_CTX *ctx = talloc_tos();
1020 START_PROFILE(SMBcheckpath);
1022 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
1023 STR_TERMINATE, &status);
1025 if (!NT_STATUS_IS_OK(status)) {
1026 status = map_checkpath_error(req->flags2, status);
1027 reply_nterror(req, status);
1028 END_PROFILE(SMBcheckpath);
1029 return;
1032 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1034 status = filename_convert(ctx,
1035 conn,
1036 req->flags2 & FLAGS2_DFS_PATHNAMES,
1037 name,
1039 NULL,
1040 &smb_fname);
1042 if (!NT_STATUS_IS_OK(status)) {
1043 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1044 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1045 ERRSRV, ERRbadpath);
1046 END_PROFILE(SMBcheckpath);
1047 return;
1049 goto path_err;
1052 if (!VALID_STAT(smb_fname->st) &&
1053 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1054 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1055 smb_fname_str_dbg(smb_fname), strerror(errno)));
1056 status = map_nt_error_from_unix(errno);
1057 goto path_err;
1060 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1061 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1062 ERRDOS, ERRbadpath);
1063 goto out;
1066 reply_outbuf(req, 0, 0);
1068 path_err:
1069 /* We special case this - as when a Windows machine
1070 is parsing a path is steps through the components
1071 one at a time - if a component fails it expects
1072 ERRbadpath, not ERRbadfile.
1074 status = map_checkpath_error(req->flags2, status);
1075 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1077 * Windows returns different error codes if
1078 * the parent directory is valid but not the
1079 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1080 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1081 * if the path is invalid.
1083 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1084 ERRDOS, ERRbadpath);
1085 goto out;
1088 reply_nterror(req, status);
1090 out:
1091 TALLOC_FREE(smb_fname);
1092 END_PROFILE(SMBcheckpath);
1093 return;
1096 /****************************************************************************
1097 Reply to a getatr.
1098 ****************************************************************************/
1100 void reply_getatr(struct smb_request *req)
1102 connection_struct *conn = req->conn;
1103 struct smb_filename *smb_fname = NULL;
1104 char *fname = NULL;
1105 int mode=0;
1106 off_t size=0;
1107 time_t mtime=0;
1108 const char *p;
1109 NTSTATUS status;
1110 TALLOC_CTX *ctx = talloc_tos();
1111 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1113 START_PROFILE(SMBgetatr);
1115 p = (const char *)req->buf + 1;
1116 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1117 if (!NT_STATUS_IS_OK(status)) {
1118 reply_nterror(req, status);
1119 goto out;
1122 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1123 under WfWg - weird! */
1124 if (*fname == '\0') {
1125 mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1126 if (!CAN_WRITE(conn)) {
1127 mode |= FILE_ATTRIBUTE_READONLY;
1129 size = 0;
1130 mtime = 0;
1131 } else {
1132 status = filename_convert(ctx,
1133 conn,
1134 req->flags2 & FLAGS2_DFS_PATHNAMES,
1135 fname,
1137 NULL,
1138 &smb_fname);
1139 if (!NT_STATUS_IS_OK(status)) {
1140 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1141 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1142 ERRSRV, ERRbadpath);
1143 goto out;
1145 reply_nterror(req, status);
1146 goto out;
1148 if (!VALID_STAT(smb_fname->st) &&
1149 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1150 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1151 smb_fname_str_dbg(smb_fname),
1152 strerror(errno)));
1153 reply_nterror(req, map_nt_error_from_unix(errno));
1154 goto out;
1157 mode = dos_mode(conn, smb_fname);
1158 size = smb_fname->st.st_ex_size;
1160 if (ask_sharemode) {
1161 struct timespec write_time_ts;
1162 struct file_id fileid;
1164 ZERO_STRUCT(write_time_ts);
1165 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1166 get_file_infos(fileid, 0, NULL, &write_time_ts);
1167 if (!null_timespec(write_time_ts)) {
1168 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1172 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1173 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1174 size = 0;
1178 reply_outbuf(req, 10, 0);
1180 SSVAL(req->outbuf,smb_vwv0,mode);
1181 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1182 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1183 } else {
1184 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1186 SIVAL(req->outbuf,smb_vwv3,(uint32)size);
1188 if (get_Protocol() >= PROTOCOL_NT1) {
1189 SSVAL(req->outbuf, smb_flg2,
1190 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1193 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1194 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1196 out:
1197 TALLOC_FREE(smb_fname);
1198 TALLOC_FREE(fname);
1199 END_PROFILE(SMBgetatr);
1200 return;
1203 /****************************************************************************
1204 Reply to a setatr.
1205 ****************************************************************************/
1207 void reply_setatr(struct smb_request *req)
1209 struct smb_file_time ft;
1210 connection_struct *conn = req->conn;
1211 struct smb_filename *smb_fname = NULL;
1212 char *fname = NULL;
1213 int mode;
1214 time_t mtime;
1215 const char *p;
1216 NTSTATUS status;
1217 TALLOC_CTX *ctx = talloc_tos();
1219 START_PROFILE(SMBsetatr);
1221 ZERO_STRUCT(ft);
1223 if (req->wct < 2) {
1224 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1225 goto out;
1228 p = (const char *)req->buf + 1;
1229 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1230 if (!NT_STATUS_IS_OK(status)) {
1231 reply_nterror(req, status);
1232 goto out;
1235 status = filename_convert(ctx,
1236 conn,
1237 req->flags2 & FLAGS2_DFS_PATHNAMES,
1238 fname,
1240 NULL,
1241 &smb_fname);
1242 if (!NT_STATUS_IS_OK(status)) {
1243 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1244 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1245 ERRSRV, ERRbadpath);
1246 goto out;
1248 reply_nterror(req, status);
1249 goto out;
1252 if (smb_fname->base_name[0] == '.' &&
1253 smb_fname->base_name[1] == '\0') {
1255 * Not sure here is the right place to catch this
1256 * condition. Might be moved to somewhere else later -- vl
1258 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1259 goto out;
1262 mode = SVAL(req->vwv+0, 0);
1263 mtime = srv_make_unix_date3(req->vwv+1);
1265 if (mode != FILE_ATTRIBUTE_NORMAL) {
1266 if (VALID_STAT_OF_DIR(smb_fname->st))
1267 mode |= FILE_ATTRIBUTE_DIRECTORY;
1268 else
1269 mode &= ~FILE_ATTRIBUTE_DIRECTORY;
1271 status = check_access(conn, NULL, smb_fname,
1272 FILE_WRITE_ATTRIBUTES);
1273 if (!NT_STATUS_IS_OK(status)) {
1274 reply_nterror(req, status);
1275 goto out;
1278 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1279 false) != 0) {
1280 reply_nterror(req, map_nt_error_from_unix(errno));
1281 goto out;
1285 ft.mtime = convert_time_t_to_timespec(mtime);
1286 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1287 if (!NT_STATUS_IS_OK(status)) {
1288 reply_nterror(req, status);
1289 goto out;
1292 reply_outbuf(req, 0, 0);
1294 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1295 mode));
1296 out:
1297 TALLOC_FREE(smb_fname);
1298 END_PROFILE(SMBsetatr);
1299 return;
1302 /****************************************************************************
1303 Reply to a dskattr.
1304 ****************************************************************************/
1306 void reply_dskattr(struct smb_request *req)
1308 connection_struct *conn = req->conn;
1309 uint64_t dfree,dsize,bsize;
1310 START_PROFILE(SMBdskattr);
1312 if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (uint64_t)-1) {
1313 reply_nterror(req, map_nt_error_from_unix(errno));
1314 END_PROFILE(SMBdskattr);
1315 return;
1318 reply_outbuf(req, 5, 0);
1320 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1321 double total_space, free_space;
1322 /* we need to scale this to a number that DOS6 can handle. We
1323 use floating point so we can handle large drives on systems
1324 that don't have 64 bit integers
1326 we end up displaying a maximum of 2G to DOS systems
1328 total_space = dsize * (double)bsize;
1329 free_space = dfree * (double)bsize;
1331 dsize = (uint64_t)((total_space+63*512) / (64*512));
1332 dfree = (uint64_t)((free_space+63*512) / (64*512));
1334 if (dsize > 0xFFFF) dsize = 0xFFFF;
1335 if (dfree > 0xFFFF) dfree = 0xFFFF;
1337 SSVAL(req->outbuf,smb_vwv0,dsize);
1338 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1339 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1340 SSVAL(req->outbuf,smb_vwv3,dfree);
1341 } else {
1342 SSVAL(req->outbuf,smb_vwv0,dsize);
1343 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1344 SSVAL(req->outbuf,smb_vwv2,512);
1345 SSVAL(req->outbuf,smb_vwv3,dfree);
1348 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1350 END_PROFILE(SMBdskattr);
1351 return;
1355 * Utility function to split the filename from the directory.
1357 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1358 char **fname_dir_out,
1359 char **fname_mask_out)
1361 const char *p = NULL;
1362 char *fname_dir = NULL;
1363 char *fname_mask = NULL;
1365 p = strrchr_m(fname_in, '/');
1366 if (!p) {
1367 fname_dir = talloc_strdup(ctx, ".");
1368 fname_mask = talloc_strdup(ctx, fname_in);
1369 } else {
1370 fname_dir = talloc_strndup(ctx, fname_in,
1371 PTR_DIFF(p, fname_in));
1372 fname_mask = talloc_strdup(ctx, p+1);
1375 if (!fname_dir || !fname_mask) {
1376 TALLOC_FREE(fname_dir);
1377 TALLOC_FREE(fname_mask);
1378 return NT_STATUS_NO_MEMORY;
1381 *fname_dir_out = fname_dir;
1382 *fname_mask_out = fname_mask;
1383 return NT_STATUS_OK;
1386 /****************************************************************************
1387 Reply to a search.
1388 Can be called from SMBsearch, SMBffirst or SMBfunique.
1389 ****************************************************************************/
1391 void reply_search(struct smb_request *req)
1393 connection_struct *conn = req->conn;
1394 char *path = NULL;
1395 const char *mask = NULL;
1396 char *directory = NULL;
1397 struct smb_filename *smb_fname = NULL;
1398 char *fname = NULL;
1399 off_t size;
1400 uint32 mode;
1401 struct timespec date;
1402 uint32 dirtype;
1403 unsigned int numentries = 0;
1404 unsigned int maxentries = 0;
1405 bool finished = False;
1406 const char *p;
1407 int status_len;
1408 char status[21];
1409 int dptr_num= -1;
1410 bool check_descend = False;
1411 bool expect_close = False;
1412 NTSTATUS nt_status;
1413 bool mask_contains_wcard = False;
1414 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1415 TALLOC_CTX *ctx = talloc_tos();
1416 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1417 struct dptr_struct *dirptr = NULL;
1418 struct smbd_server_connection *sconn = req->sconn;
1420 START_PROFILE(SMBsearch);
1422 if (req->wct < 2) {
1423 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1424 goto out;
1427 if (lp_posix_pathnames()) {
1428 reply_unknown_new(req, req->cmd);
1429 goto out;
1432 /* If we were called as SMBffirst then we must expect close. */
1433 if(req->cmd == SMBffirst) {
1434 expect_close = True;
1437 reply_outbuf(req, 1, 3);
1438 maxentries = SVAL(req->vwv+0, 0);
1439 dirtype = SVAL(req->vwv+1, 0);
1440 p = (const char *)req->buf + 1;
1441 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1442 &nt_status, &mask_contains_wcard);
1443 if (!NT_STATUS_IS_OK(nt_status)) {
1444 reply_nterror(req, nt_status);
1445 goto out;
1448 p++;
1449 status_len = SVAL(p, 0);
1450 p += 2;
1452 /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1454 if (status_len == 0) {
1455 nt_status = filename_convert(ctx, conn,
1456 req->flags2 & FLAGS2_DFS_PATHNAMES,
1457 path,
1458 UCF_ALWAYS_ALLOW_WCARD_LCOMP,
1459 &mask_contains_wcard,
1460 &smb_fname);
1461 if (!NT_STATUS_IS_OK(nt_status)) {
1462 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1463 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1464 ERRSRV, ERRbadpath);
1465 goto out;
1467 reply_nterror(req, nt_status);
1468 goto out;
1471 directory = smb_fname->base_name;
1473 p = strrchr_m(directory,'/');
1474 if ((p != NULL) && (*directory != '/')) {
1475 mask = p + 1;
1476 directory = talloc_strndup(ctx, directory,
1477 PTR_DIFF(p, directory));
1478 } else {
1479 mask = directory;
1480 directory = talloc_strdup(ctx,".");
1483 if (!directory) {
1484 reply_nterror(req, NT_STATUS_NO_MEMORY);
1485 goto out;
1488 memset((char *)status,'\0',21);
1489 SCVAL(status,0,(dirtype & 0x1F));
1491 nt_status = dptr_create(conn,
1492 NULL, /* req */
1493 NULL, /* fsp */
1494 directory,
1495 True,
1496 expect_close,
1497 req->smbpid,
1498 mask,
1499 mask_contains_wcard,
1500 dirtype,
1501 &dirptr);
1502 if (!NT_STATUS_IS_OK(nt_status)) {
1503 reply_nterror(req, nt_status);
1504 goto out;
1506 dptr_num = dptr_dnum(dirptr);
1507 } else {
1508 int status_dirtype;
1509 const char *dirpath;
1511 memcpy(status,p,21);
1512 status_dirtype = CVAL(status,0) & 0x1F;
1513 if (status_dirtype != (dirtype & 0x1F)) {
1514 dirtype = status_dirtype;
1517 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1518 if (!dirptr) {
1519 goto SearchEmpty;
1521 dirpath = dptr_path(sconn, dptr_num);
1522 directory = talloc_strdup(ctx, dirpath);
1523 if (!directory) {
1524 reply_nterror(req, NT_STATUS_NO_MEMORY);
1525 goto out;
1528 mask = dptr_wcard(sconn, dptr_num);
1529 if (!mask) {
1530 goto SearchEmpty;
1533 * For a 'continue' search we have no string. So
1534 * check from the initial saved string.
1536 mask_contains_wcard = ms_has_wild(mask);
1537 dirtype = dptr_attr(sconn, dptr_num);
1540 DEBUG(4,("dptr_num is %d\n",dptr_num));
1542 /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
1543 dptr_init_search_op(dirptr);
1545 if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1546 char buf[DIR_STRUCT_SIZE];
1547 memcpy(buf,status,21);
1548 if (!make_dir_struct(ctx,buf,"???????????",volume_label(ctx, SNUM(conn)),
1549 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1550 reply_nterror(req, NT_STATUS_NO_MEMORY);
1551 goto out;
1553 dptr_fill(sconn, buf+12,dptr_num);
1554 if (dptr_zero(buf+12) && (status_len==0)) {
1555 numentries = 1;
1556 } else {
1557 numentries = 0;
1559 if (message_push_blob(&req->outbuf,
1560 data_blob_const(buf, sizeof(buf)))
1561 == -1) {
1562 reply_nterror(req, NT_STATUS_NO_MEMORY);
1563 goto out;
1565 } else {
1566 unsigned int i;
1567 maxentries = MIN(
1568 maxentries,
1569 ((BUFFER_SIZE -
1570 ((uint8 *)smb_buf(req->outbuf) + 3 - req->outbuf))
1571 /DIR_STRUCT_SIZE));
1573 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1574 directory,lp_dontdescend(ctx, SNUM(conn))));
1575 if (in_list(directory, lp_dontdescend(ctx, SNUM(conn)),True)) {
1576 check_descend = True;
1579 for (i=numentries;(i<maxentries) && !finished;i++) {
1580 finished = !get_dir_entry(ctx,
1581 dirptr,
1582 mask,
1583 dirtype,
1584 &fname,
1585 &size,
1586 &mode,
1587 &date,
1588 check_descend,
1589 ask_sharemode);
1590 if (!finished) {
1591 char buf[DIR_STRUCT_SIZE];
1592 memcpy(buf,status,21);
1593 if (!make_dir_struct(ctx,
1594 buf,
1595 mask,
1596 fname,
1597 size,
1598 mode,
1599 convert_timespec_to_time_t(date),
1600 !allow_long_path_components)) {
1601 reply_nterror(req, NT_STATUS_NO_MEMORY);
1602 goto out;
1604 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1605 break;
1607 if (message_push_blob(&req->outbuf,
1608 data_blob_const(buf, sizeof(buf)))
1609 == -1) {
1610 reply_nterror(req, NT_STATUS_NO_MEMORY);
1611 goto out;
1613 numentries++;
1618 SearchEmpty:
1620 /* If we were called as SMBffirst with smb_search_id == NULL
1621 and no entries were found then return error and close dirptr
1622 (X/Open spec) */
1624 if (numentries == 0) {
1625 dptr_close(sconn, &dptr_num);
1626 } else if(expect_close && status_len == 0) {
1627 /* Close the dptr - we know it's gone */
1628 dptr_close(sconn, &dptr_num);
1631 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1632 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1633 dptr_close(sconn, &dptr_num);
1636 if ((numentries == 0) && !mask_contains_wcard) {
1637 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1638 goto out;
1641 SSVAL(req->outbuf,smb_vwv0,numentries);
1642 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1643 SCVAL(smb_buf(req->outbuf),0,5);
1644 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1646 /* The replies here are never long name. */
1647 SSVAL(req->outbuf, smb_flg2,
1648 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1649 if (!allow_long_path_components) {
1650 SSVAL(req->outbuf, smb_flg2,
1651 SVAL(req->outbuf, smb_flg2)
1652 & (~FLAGS2_LONG_PATH_COMPONENTS));
1655 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
1656 SSVAL(req->outbuf, smb_flg2,
1657 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
1659 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
1660 smb_fn_name(req->cmd),
1661 mask,
1662 directory,
1663 dirtype,
1664 numentries,
1665 maxentries ));
1666 out:
1667 TALLOC_FREE(directory);
1668 TALLOC_FREE(smb_fname);
1669 END_PROFILE(SMBsearch);
1670 return;
1673 /****************************************************************************
1674 Reply to a fclose (stop directory search).
1675 ****************************************************************************/
1677 void reply_fclose(struct smb_request *req)
1679 int status_len;
1680 char status[21];
1681 int dptr_num= -2;
1682 const char *p;
1683 char *path = NULL;
1684 NTSTATUS err;
1685 bool path_contains_wcard = False;
1686 TALLOC_CTX *ctx = talloc_tos();
1687 struct smbd_server_connection *sconn = req->sconn;
1689 START_PROFILE(SMBfclose);
1691 if (lp_posix_pathnames()) {
1692 reply_unknown_new(req, req->cmd);
1693 END_PROFILE(SMBfclose);
1694 return;
1697 p = (const char *)req->buf + 1;
1698 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1699 &err, &path_contains_wcard);
1700 if (!NT_STATUS_IS_OK(err)) {
1701 reply_nterror(req, err);
1702 END_PROFILE(SMBfclose);
1703 return;
1705 p++;
1706 status_len = SVAL(p,0);
1707 p += 2;
1709 if (status_len == 0) {
1710 reply_force_doserror(req, ERRSRV, ERRsrverror);
1711 END_PROFILE(SMBfclose);
1712 return;
1715 memcpy(status,p,21);
1717 if(dptr_fetch(sconn, status+12,&dptr_num)) {
1718 /* Close the dptr - we know it's gone */
1719 dptr_close(sconn, &dptr_num);
1722 reply_outbuf(req, 1, 0);
1723 SSVAL(req->outbuf,smb_vwv0,0);
1725 DEBUG(3,("search close\n"));
1727 END_PROFILE(SMBfclose);
1728 return;
1731 /****************************************************************************
1732 Reply to an open.
1733 ****************************************************************************/
1735 void reply_open(struct smb_request *req)
1737 connection_struct *conn = req->conn;
1738 struct smb_filename *smb_fname = NULL;
1739 char *fname = NULL;
1740 uint32 fattr=0;
1741 off_t size = 0;
1742 time_t mtime=0;
1743 int info;
1744 files_struct *fsp;
1745 int oplock_request;
1746 int deny_mode;
1747 uint32 dos_attr;
1748 uint32 access_mask;
1749 uint32 share_mode;
1750 uint32 create_disposition;
1751 uint32 create_options = 0;
1752 uint32_t private_flags = 0;
1753 NTSTATUS status;
1754 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1755 TALLOC_CTX *ctx = talloc_tos();
1757 START_PROFILE(SMBopen);
1759 if (req->wct < 2) {
1760 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1761 goto out;
1764 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1765 deny_mode = SVAL(req->vwv+0, 0);
1766 dos_attr = SVAL(req->vwv+1, 0);
1768 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
1769 STR_TERMINATE, &status);
1770 if (!NT_STATUS_IS_OK(status)) {
1771 reply_nterror(req, status);
1772 goto out;
1775 status = filename_convert(ctx,
1776 conn,
1777 req->flags2 & FLAGS2_DFS_PATHNAMES,
1778 fname,
1780 NULL,
1781 &smb_fname);
1782 if (!NT_STATUS_IS_OK(status)) {
1783 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1784 reply_botherror(req,
1785 NT_STATUS_PATH_NOT_COVERED,
1786 ERRSRV, ERRbadpath);
1787 goto out;
1789 reply_nterror(req, status);
1790 goto out;
1793 if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode,
1794 OPENX_FILE_EXISTS_OPEN, &access_mask,
1795 &share_mode, &create_disposition,
1796 &create_options, &private_flags)) {
1797 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1798 goto out;
1801 status = SMB_VFS_CREATE_FILE(
1802 conn, /* conn */
1803 req, /* req */
1804 0, /* root_dir_fid */
1805 smb_fname, /* fname */
1806 access_mask, /* access_mask */
1807 share_mode, /* share_access */
1808 create_disposition, /* create_disposition*/
1809 create_options, /* create_options */
1810 dos_attr, /* file_attributes */
1811 oplock_request, /* oplock_request */
1812 0, /* allocation_size */
1813 private_flags,
1814 NULL, /* sd */
1815 NULL, /* ea_list */
1816 &fsp, /* result */
1817 &info); /* pinfo */
1819 if (!NT_STATUS_IS_OK(status)) {
1820 if (open_was_deferred(req->sconn, req->mid)) {
1821 /* We have re-scheduled this call. */
1822 goto out;
1824 reply_openerror(req, status);
1825 goto out;
1828 size = smb_fname->st.st_ex_size;
1829 fattr = dos_mode(conn, smb_fname);
1831 /* Deal with other possible opens having a modified
1832 write time. JRA. */
1833 if (ask_sharemode) {
1834 struct timespec write_time_ts;
1836 ZERO_STRUCT(write_time_ts);
1837 get_file_infos(fsp->file_id, 0, NULL, &write_time_ts);
1838 if (!null_timespec(write_time_ts)) {
1839 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1843 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1845 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
1846 DEBUG(3,("attempt to open a directory %s\n",
1847 fsp_str_dbg(fsp)));
1848 close_file(req, fsp, ERROR_CLOSE);
1849 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
1850 ERRDOS, ERRnoaccess);
1851 goto out;
1854 reply_outbuf(req, 7, 0);
1855 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
1856 SSVAL(req->outbuf,smb_vwv1,fattr);
1857 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1858 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
1859 } else {
1860 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
1862 SIVAL(req->outbuf,smb_vwv4,(uint32)size);
1863 SSVAL(req->outbuf,smb_vwv6,deny_mode);
1865 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1866 SCVAL(req->outbuf,smb_flg,
1867 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1870 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1871 SCVAL(req->outbuf,smb_flg,
1872 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1874 out:
1875 TALLOC_FREE(smb_fname);
1876 END_PROFILE(SMBopen);
1877 return;
1880 /****************************************************************************
1881 Reply to an open and X.
1882 ****************************************************************************/
1884 void reply_open_and_X(struct smb_request *req)
1886 connection_struct *conn = req->conn;
1887 struct smb_filename *smb_fname = NULL;
1888 char *fname = NULL;
1889 uint16 open_flags;
1890 int deny_mode;
1891 uint32 smb_attr;
1892 /* Breakout the oplock request bits so we can set the
1893 reply bits separately. */
1894 int ex_oplock_request;
1895 int core_oplock_request;
1896 int oplock_request;
1897 #if 0
1898 int smb_sattr = SVAL(req->vwv+4, 0);
1899 uint32 smb_time = make_unix_date3(req->vwv+6);
1900 #endif
1901 int smb_ofun;
1902 uint32 fattr=0;
1903 int mtime=0;
1904 int smb_action = 0;
1905 files_struct *fsp;
1906 NTSTATUS status;
1907 uint64_t allocation_size;
1908 ssize_t retval = -1;
1909 uint32 access_mask;
1910 uint32 share_mode;
1911 uint32 create_disposition;
1912 uint32 create_options = 0;
1913 uint32_t private_flags = 0;
1914 TALLOC_CTX *ctx = talloc_tos();
1916 START_PROFILE(SMBopenX);
1918 if (req->wct < 15) {
1919 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1920 goto out;
1923 open_flags = SVAL(req->vwv+2, 0);
1924 deny_mode = SVAL(req->vwv+3, 0);
1925 smb_attr = SVAL(req->vwv+5, 0);
1926 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
1927 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1928 oplock_request = ex_oplock_request | core_oplock_request;
1929 smb_ofun = SVAL(req->vwv+8, 0);
1930 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
1932 /* If it's an IPC, pass off the pipe handler. */
1933 if (IS_IPC(conn)) {
1934 if (lp_nt_pipe_support()) {
1935 reply_open_pipe_and_X(conn, req);
1936 } else {
1937 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
1939 goto out;
1942 /* XXXX we need to handle passed times, sattr and flags */
1943 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
1944 STR_TERMINATE, &status);
1945 if (!NT_STATUS_IS_OK(status)) {
1946 reply_nterror(req, status);
1947 goto out;
1950 status = filename_convert(ctx,
1951 conn,
1952 req->flags2 & FLAGS2_DFS_PATHNAMES,
1953 fname,
1955 NULL,
1956 &smb_fname);
1957 if (!NT_STATUS_IS_OK(status)) {
1958 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1959 reply_botherror(req,
1960 NT_STATUS_PATH_NOT_COVERED,
1961 ERRSRV, ERRbadpath);
1962 goto out;
1964 reply_nterror(req, status);
1965 goto out;
1968 if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode,
1969 smb_ofun,
1970 &access_mask, &share_mode,
1971 &create_disposition,
1972 &create_options,
1973 &private_flags)) {
1974 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1975 goto out;
1978 status = SMB_VFS_CREATE_FILE(
1979 conn, /* conn */
1980 req, /* req */
1981 0, /* root_dir_fid */
1982 smb_fname, /* fname */
1983 access_mask, /* access_mask */
1984 share_mode, /* share_access */
1985 create_disposition, /* create_disposition*/
1986 create_options, /* create_options */
1987 smb_attr, /* file_attributes */
1988 oplock_request, /* oplock_request */
1989 0, /* allocation_size */
1990 private_flags,
1991 NULL, /* sd */
1992 NULL, /* ea_list */
1993 &fsp, /* result */
1994 &smb_action); /* pinfo */
1996 if (!NT_STATUS_IS_OK(status)) {
1997 if (open_was_deferred(req->sconn, req->mid)) {
1998 /* We have re-scheduled this call. */
1999 goto out;
2001 reply_openerror(req, status);
2002 goto out;
2005 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2006 if the file is truncated or created. */
2007 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2008 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2009 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2010 close_file(req, fsp, ERROR_CLOSE);
2011 reply_nterror(req, NT_STATUS_DISK_FULL);
2012 goto out;
2014 retval = vfs_set_filelen(fsp, (off_t)allocation_size);
2015 if (retval < 0) {
2016 close_file(req, fsp, ERROR_CLOSE);
2017 reply_nterror(req, NT_STATUS_DISK_FULL);
2018 goto out;
2020 status = vfs_stat_fsp(fsp);
2021 if (!NT_STATUS_IS_OK(status)) {
2022 close_file(req, fsp, ERROR_CLOSE);
2023 reply_nterror(req, status);
2024 goto out;
2028 fattr = dos_mode(conn, fsp->fsp_name);
2029 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2030 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2031 close_file(req, fsp, ERROR_CLOSE);
2032 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2033 goto out;
2036 /* If the caller set the extended oplock request bit
2037 and we granted one (by whatever means) - set the
2038 correct bit for extended oplock reply.
2041 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2042 smb_action |= EXTENDED_OPLOCK_GRANTED;
2045 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2046 smb_action |= EXTENDED_OPLOCK_GRANTED;
2049 /* If the caller set the core oplock request bit
2050 and we granted one (by whatever means) - set the
2051 correct bit for core oplock reply.
2054 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2055 reply_outbuf(req, 19, 0);
2056 } else {
2057 reply_outbuf(req, 15, 0);
2060 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2061 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2063 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2064 SCVAL(req->outbuf, smb_flg,
2065 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2068 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2069 SCVAL(req->outbuf, smb_flg,
2070 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2073 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2074 SSVAL(req->outbuf,smb_vwv3,fattr);
2075 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2076 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2077 } else {
2078 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2080 SIVAL(req->outbuf,smb_vwv6,(uint32)fsp->fsp_name->st.st_ex_size);
2081 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2082 SSVAL(req->outbuf,smb_vwv11,smb_action);
2084 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2085 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2088 out:
2089 TALLOC_FREE(smb_fname);
2090 END_PROFILE(SMBopenX);
2091 return;
2094 /****************************************************************************
2095 Reply to a SMBulogoffX.
2096 ****************************************************************************/
2098 void reply_ulogoffX(struct smb_request *req)
2100 struct smbd_server_connection *sconn = req->sconn;
2101 struct user_struct *vuser;
2102 struct smbXsrv_session *session = NULL;
2103 NTSTATUS status;
2105 START_PROFILE(SMBulogoffX);
2107 vuser = get_valid_user_struct(sconn, req->vuid);
2109 if(vuser == NULL) {
2110 DEBUG(3,("ulogoff, vuser id %llu does not map to user.\n",
2111 (unsigned long long)req->vuid));
2113 req->vuid = UID_FIELD_INVALID;
2114 reply_force_doserror(req, ERRSRV, ERRbaduid);
2115 END_PROFILE(SMBulogoffX);
2116 return;
2119 session = vuser->session;
2120 vuser = NULL;
2123 * TODO: cancel all outstanding requests on the session
2125 status = smbXsrv_session_logoff(session);
2126 if (!NT_STATUS_IS_OK(status)) {
2127 DEBUG(0, ("reply_ulogoff: "
2128 "smbXsrv_session_logoff() failed: %s\n",
2129 nt_errstr(status)));
2131 * If we hit this case, there is something completely
2132 * wrong, so we better disconnect the transport connection.
2134 END_PROFILE(SMBulogoffX);
2135 exit_server(__location__ ": smbXsrv_session_logoff failed");
2136 return;
2139 TALLOC_FREE(session);
2141 reply_outbuf(req, 2, 0);
2142 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2143 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2145 DEBUG(3, ("ulogoffX vuid=%llu\n",
2146 (unsigned long long)req->vuid));
2148 END_PROFILE(SMBulogoffX);
2149 req->vuid = UID_FIELD_INVALID;
2152 /****************************************************************************
2153 Reply to a mknew or a create.
2154 ****************************************************************************/
2156 void reply_mknew(struct smb_request *req)
2158 connection_struct *conn = req->conn;
2159 struct smb_filename *smb_fname = NULL;
2160 char *fname = NULL;
2161 uint32 fattr = 0;
2162 struct smb_file_time ft;
2163 files_struct *fsp;
2164 int oplock_request = 0;
2165 NTSTATUS status;
2166 uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2167 uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2168 uint32 create_disposition;
2169 uint32 create_options = 0;
2170 TALLOC_CTX *ctx = talloc_tos();
2172 START_PROFILE(SMBcreate);
2173 ZERO_STRUCT(ft);
2175 if (req->wct < 3) {
2176 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2177 goto out;
2180 fattr = SVAL(req->vwv+0, 0);
2181 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2183 /* mtime. */
2184 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2186 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2187 STR_TERMINATE, &status);
2188 if (!NT_STATUS_IS_OK(status)) {
2189 reply_nterror(req, status);
2190 goto out;
2193 status = filename_convert(ctx,
2194 conn,
2195 req->flags2 & FLAGS2_DFS_PATHNAMES,
2196 fname,
2198 NULL,
2199 &smb_fname);
2200 if (!NT_STATUS_IS_OK(status)) {
2201 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2202 reply_botherror(req,
2203 NT_STATUS_PATH_NOT_COVERED,
2204 ERRSRV, ERRbadpath);
2205 goto out;
2207 reply_nterror(req, status);
2208 goto out;
2211 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2212 DEBUG(0,("Attempt to create file (%s) with volid set - "
2213 "please report this\n",
2214 smb_fname_str_dbg(smb_fname)));
2217 if(req->cmd == SMBmknew) {
2218 /* We should fail if file exists. */
2219 create_disposition = FILE_CREATE;
2220 } else {
2221 /* Create if file doesn't exist, truncate if it does. */
2222 create_disposition = FILE_OVERWRITE_IF;
2225 status = SMB_VFS_CREATE_FILE(
2226 conn, /* conn */
2227 req, /* req */
2228 0, /* root_dir_fid */
2229 smb_fname, /* fname */
2230 access_mask, /* access_mask */
2231 share_mode, /* share_access */
2232 create_disposition, /* create_disposition*/
2233 create_options, /* create_options */
2234 fattr, /* file_attributes */
2235 oplock_request, /* oplock_request */
2236 0, /* allocation_size */
2237 0, /* private_flags */
2238 NULL, /* sd */
2239 NULL, /* ea_list */
2240 &fsp, /* result */
2241 NULL); /* pinfo */
2243 if (!NT_STATUS_IS_OK(status)) {
2244 if (open_was_deferred(req->sconn, req->mid)) {
2245 /* We have re-scheduled this call. */
2246 goto out;
2248 reply_openerror(req, status);
2249 goto out;
2252 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2253 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2254 if (!NT_STATUS_IS_OK(status)) {
2255 END_PROFILE(SMBcreate);
2256 goto out;
2259 reply_outbuf(req, 1, 0);
2260 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2262 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2263 SCVAL(req->outbuf,smb_flg,
2264 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2267 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2268 SCVAL(req->outbuf,smb_flg,
2269 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2272 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2273 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2274 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2275 (unsigned int)fattr));
2277 out:
2278 TALLOC_FREE(smb_fname);
2279 END_PROFILE(SMBcreate);
2280 return;
2283 /****************************************************************************
2284 Reply to a create temporary file.
2285 ****************************************************************************/
2287 void reply_ctemp(struct smb_request *req)
2289 connection_struct *conn = req->conn;
2290 struct smb_filename *smb_fname = NULL;
2291 char *fname = NULL;
2292 uint32 fattr;
2293 files_struct *fsp;
2294 int oplock_request;
2295 int tmpfd;
2296 char *s;
2297 NTSTATUS status;
2298 TALLOC_CTX *ctx = talloc_tos();
2300 START_PROFILE(SMBctemp);
2302 if (req->wct < 3) {
2303 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2304 goto out;
2307 fattr = SVAL(req->vwv+0, 0);
2308 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2310 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
2311 STR_TERMINATE, &status);
2312 if (!NT_STATUS_IS_OK(status)) {
2313 reply_nterror(req, status);
2314 goto out;
2316 if (*fname) {
2317 fname = talloc_asprintf(ctx,
2318 "%s/TMXXXXXX",
2319 fname);
2320 } else {
2321 fname = talloc_strdup(ctx, "TMXXXXXX");
2324 if (!fname) {
2325 reply_nterror(req, NT_STATUS_NO_MEMORY);
2326 goto out;
2329 status = filename_convert(ctx, conn,
2330 req->flags2 & FLAGS2_DFS_PATHNAMES,
2331 fname,
2333 NULL,
2334 &smb_fname);
2335 if (!NT_STATUS_IS_OK(status)) {
2336 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2337 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2338 ERRSRV, ERRbadpath);
2339 goto out;
2341 reply_nterror(req, status);
2342 goto out;
2345 tmpfd = mkstemp(smb_fname->base_name);
2346 if (tmpfd == -1) {
2347 reply_nterror(req, map_nt_error_from_unix(errno));
2348 goto out;
2351 SMB_VFS_STAT(conn, smb_fname);
2353 /* We should fail if file does not exist. */
2354 status = SMB_VFS_CREATE_FILE(
2355 conn, /* conn */
2356 req, /* req */
2357 0, /* root_dir_fid */
2358 smb_fname, /* fname */
2359 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2360 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2361 FILE_OPEN, /* create_disposition*/
2362 0, /* create_options */
2363 fattr, /* file_attributes */
2364 oplock_request, /* oplock_request */
2365 0, /* allocation_size */
2366 0, /* private_flags */
2367 NULL, /* sd */
2368 NULL, /* ea_list */
2369 &fsp, /* result */
2370 NULL); /* pinfo */
2372 /* close fd from mkstemp() */
2373 close(tmpfd);
2375 if (!NT_STATUS_IS_OK(status)) {
2376 if (open_was_deferred(req->sconn, req->mid)) {
2377 /* We have re-scheduled this call. */
2378 goto out;
2380 reply_openerror(req, status);
2381 goto out;
2384 reply_outbuf(req, 1, 0);
2385 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2387 /* the returned filename is relative to the directory */
2388 s = strrchr_m(fsp->fsp_name->base_name, '/');
2389 if (!s) {
2390 s = fsp->fsp_name->base_name;
2391 } else {
2392 s++;
2395 #if 0
2396 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2397 thing in the byte section. JRA */
2398 SSVALS(p, 0, -1); /* what is this? not in spec */
2399 #endif
2400 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2401 == -1) {
2402 reply_nterror(req, NT_STATUS_NO_MEMORY);
2403 goto out;
2406 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2407 SCVAL(req->outbuf, smb_flg,
2408 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2411 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2412 SCVAL(req->outbuf, smb_flg,
2413 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2416 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2417 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2418 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2419 out:
2420 TALLOC_FREE(smb_fname);
2421 END_PROFILE(SMBctemp);
2422 return;
2425 /*******************************************************************
2426 Check if a user is allowed to rename a file.
2427 ********************************************************************/
2429 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2430 uint16 dirtype)
2432 if (!CAN_WRITE(conn)) {
2433 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2436 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
2437 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2438 /* Only bother to read the DOS attribute if we might deny the
2439 rename on the grounds of attribute missmatch. */
2440 uint32_t fmode = dos_mode(conn, fsp->fsp_name);
2441 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2442 return NT_STATUS_NO_SUCH_FILE;
2446 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2447 if (fsp->posix_open) {
2448 return NT_STATUS_OK;
2451 /* If no pathnames are open below this
2452 directory, allow the rename. */
2454 if (file_find_subpath(fsp)) {
2455 return NT_STATUS_ACCESS_DENIED;
2457 return NT_STATUS_OK;
2460 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2461 return NT_STATUS_OK;
2464 return NT_STATUS_ACCESS_DENIED;
2467 /*******************************************************************
2468 * unlink a file with all relevant access checks
2469 *******************************************************************/
2471 static NTSTATUS do_unlink(connection_struct *conn,
2472 struct smb_request *req,
2473 struct smb_filename *smb_fname,
2474 uint32 dirtype)
2476 uint32 fattr;
2477 files_struct *fsp;
2478 uint32 dirtype_orig = dirtype;
2479 NTSTATUS status;
2480 int ret;
2481 bool posix_paths = lp_posix_pathnames();
2483 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2484 smb_fname_str_dbg(smb_fname),
2485 dirtype));
2487 if (!CAN_WRITE(conn)) {
2488 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2491 if (posix_paths) {
2492 ret = SMB_VFS_LSTAT(conn, smb_fname);
2493 } else {
2494 ret = SMB_VFS_STAT(conn, smb_fname);
2496 if (ret != 0) {
2497 return map_nt_error_from_unix(errno);
2500 fattr = dos_mode(conn, smb_fname);
2502 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2503 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
2506 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
2507 if (!dirtype) {
2508 return NT_STATUS_NO_SUCH_FILE;
2511 if (!dir_check_ftype(conn, fattr, dirtype)) {
2512 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2513 return NT_STATUS_FILE_IS_A_DIRECTORY;
2515 return NT_STATUS_NO_SUCH_FILE;
2518 if (dirtype_orig & 0x8000) {
2519 /* These will never be set for POSIX. */
2520 return NT_STATUS_NO_SUCH_FILE;
2523 #if 0
2524 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2525 return NT_STATUS_FILE_IS_A_DIRECTORY;
2528 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2529 return NT_STATUS_NO_SUCH_FILE;
2532 if (dirtype & 0xFF00) {
2533 /* These will never be set for POSIX. */
2534 return NT_STATUS_NO_SUCH_FILE;
2537 dirtype &= 0xFF;
2538 if (!dirtype) {
2539 return NT_STATUS_NO_SUCH_FILE;
2542 /* Can't delete a directory. */
2543 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2544 return NT_STATUS_FILE_IS_A_DIRECTORY;
2546 #endif
2548 #if 0 /* JRATEST */
2549 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
2550 return NT_STATUS_OBJECT_NAME_INVALID;
2551 #endif /* JRATEST */
2553 /* On open checks the open itself will check the share mode, so
2554 don't do it here as we'll get it wrong. */
2556 status = SMB_VFS_CREATE_FILE
2557 (conn, /* conn */
2558 req, /* req */
2559 0, /* root_dir_fid */
2560 smb_fname, /* fname */
2561 DELETE_ACCESS, /* access_mask */
2562 FILE_SHARE_NONE, /* share_access */
2563 FILE_OPEN, /* create_disposition*/
2564 FILE_NON_DIRECTORY_FILE, /* create_options */
2565 /* file_attributes */
2566 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2567 FILE_ATTRIBUTE_NORMAL,
2568 0, /* oplock_request */
2569 0, /* allocation_size */
2570 0, /* private_flags */
2571 NULL, /* sd */
2572 NULL, /* ea_list */
2573 &fsp, /* result */
2574 NULL); /* pinfo */
2576 if (!NT_STATUS_IS_OK(status)) {
2577 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2578 nt_errstr(status)));
2579 return status;
2582 status = can_set_delete_on_close(fsp, fattr);
2583 if (!NT_STATUS_IS_OK(status)) {
2584 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2585 "(%s)\n",
2586 smb_fname_str_dbg(smb_fname),
2587 nt_errstr(status)));
2588 close_file(req, fsp, NORMAL_CLOSE);
2589 return status;
2592 /* The set is across all open files on this dev/inode pair. */
2593 if (!set_delete_on_close(fsp, True,
2594 conn->session_info->security_token,
2595 conn->session_info->unix_token)) {
2596 close_file(req, fsp, NORMAL_CLOSE);
2597 return NT_STATUS_ACCESS_DENIED;
2600 return close_file(req, fsp, NORMAL_CLOSE);
2603 /****************************************************************************
2604 The guts of the unlink command, split out so it may be called by the NT SMB
2605 code.
2606 ****************************************************************************/
2608 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2609 uint32 dirtype, struct smb_filename *smb_fname,
2610 bool has_wild)
2612 char *fname_dir = NULL;
2613 char *fname_mask = NULL;
2614 int count=0;
2615 NTSTATUS status = NT_STATUS_OK;
2616 TALLOC_CTX *ctx = talloc_tos();
2618 /* Split up the directory from the filename/mask. */
2619 status = split_fname_dir_mask(ctx, smb_fname->base_name,
2620 &fname_dir, &fname_mask);
2621 if (!NT_STATUS_IS_OK(status)) {
2622 goto out;
2626 * We should only check the mangled cache
2627 * here if unix_convert failed. This means
2628 * that the path in 'mask' doesn't exist
2629 * on the file system and so we need to look
2630 * for a possible mangle. This patch from
2631 * Tine Smukavec <valentin.smukavec@hermes.si>.
2634 if (!VALID_STAT(smb_fname->st) &&
2635 mangle_is_mangled(fname_mask, conn->params)) {
2636 char *new_mask = NULL;
2637 mangle_lookup_name_from_8_3(ctx, fname_mask,
2638 &new_mask, conn->params);
2639 if (new_mask) {
2640 TALLOC_FREE(fname_mask);
2641 fname_mask = new_mask;
2645 if (!has_wild) {
2648 * Only one file needs to be unlinked. Append the mask back
2649 * onto the directory.
2651 TALLOC_FREE(smb_fname->base_name);
2652 if (ISDOT(fname_dir)) {
2653 /* Ensure we use canonical names on open. */
2654 smb_fname->base_name = talloc_asprintf(smb_fname,
2655 "%s",
2656 fname_mask);
2657 } else {
2658 smb_fname->base_name = talloc_asprintf(smb_fname,
2659 "%s/%s",
2660 fname_dir,
2661 fname_mask);
2663 if (!smb_fname->base_name) {
2664 status = NT_STATUS_NO_MEMORY;
2665 goto out;
2667 if (dirtype == 0) {
2668 dirtype = FILE_ATTRIBUTE_NORMAL;
2671 status = check_name(conn, smb_fname->base_name);
2672 if (!NT_STATUS_IS_OK(status)) {
2673 goto out;
2676 status = do_unlink(conn, req, smb_fname, dirtype);
2677 if (!NT_STATUS_IS_OK(status)) {
2678 goto out;
2681 count++;
2682 } else {
2683 struct smb_Dir *dir_hnd = NULL;
2684 long offset = 0;
2685 const char *dname = NULL;
2686 char *talloced = NULL;
2688 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
2689 status = NT_STATUS_OBJECT_NAME_INVALID;
2690 goto out;
2693 if (strequal(fname_mask,"????????.???")) {
2694 TALLOC_FREE(fname_mask);
2695 fname_mask = talloc_strdup(ctx, "*");
2696 if (!fname_mask) {
2697 status = NT_STATUS_NO_MEMORY;
2698 goto out;
2702 status = check_name(conn, fname_dir);
2703 if (!NT_STATUS_IS_OK(status)) {
2704 goto out;
2707 dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask,
2708 dirtype);
2709 if (dir_hnd == NULL) {
2710 status = map_nt_error_from_unix(errno);
2711 goto out;
2714 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2715 the pattern matches against the long name, otherwise the short name
2716 We don't implement this yet XXXX
2719 status = NT_STATUS_NO_SUCH_FILE;
2721 while ((dname = ReadDirName(dir_hnd, &offset,
2722 &smb_fname->st, &talloced))) {
2723 TALLOC_CTX *frame = talloc_stackframe();
2725 if (!is_visible_file(conn, fname_dir, dname,
2726 &smb_fname->st, true)) {
2727 TALLOC_FREE(frame);
2728 TALLOC_FREE(talloced);
2729 continue;
2732 /* Quick check for "." and ".." */
2733 if (ISDOT(dname) || ISDOTDOT(dname)) {
2734 TALLOC_FREE(frame);
2735 TALLOC_FREE(talloced);
2736 continue;
2739 if(!mask_match(dname, fname_mask,
2740 conn->case_sensitive)) {
2741 TALLOC_FREE(frame);
2742 TALLOC_FREE(talloced);
2743 continue;
2746 TALLOC_FREE(smb_fname->base_name);
2747 if (ISDOT(fname_dir)) {
2748 /* Ensure we use canonical names on open. */
2749 smb_fname->base_name =
2750 talloc_asprintf(smb_fname, "%s",
2751 dname);
2752 } else {
2753 smb_fname->base_name =
2754 talloc_asprintf(smb_fname, "%s/%s",
2755 fname_dir, dname);
2758 if (!smb_fname->base_name) {
2759 TALLOC_FREE(dir_hnd);
2760 status = NT_STATUS_NO_MEMORY;
2761 TALLOC_FREE(frame);
2762 TALLOC_FREE(talloced);
2763 goto out;
2766 status = check_name(conn, smb_fname->base_name);
2767 if (!NT_STATUS_IS_OK(status)) {
2768 TALLOC_FREE(dir_hnd);
2769 TALLOC_FREE(frame);
2770 TALLOC_FREE(talloced);
2771 goto out;
2774 status = do_unlink(conn, req, smb_fname, dirtype);
2775 if (!NT_STATUS_IS_OK(status)) {
2776 TALLOC_FREE(frame);
2777 TALLOC_FREE(talloced);
2778 continue;
2781 count++;
2782 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
2783 smb_fname->base_name));
2785 TALLOC_FREE(frame);
2786 TALLOC_FREE(talloced);
2788 TALLOC_FREE(dir_hnd);
2791 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
2792 status = map_nt_error_from_unix(errno);
2795 out:
2796 TALLOC_FREE(fname_dir);
2797 TALLOC_FREE(fname_mask);
2798 return status;
2801 /****************************************************************************
2802 Reply to a unlink
2803 ****************************************************************************/
2805 void reply_unlink(struct smb_request *req)
2807 connection_struct *conn = req->conn;
2808 char *name = NULL;
2809 struct smb_filename *smb_fname = NULL;
2810 uint32 dirtype;
2811 NTSTATUS status;
2812 bool path_contains_wcard = False;
2813 TALLOC_CTX *ctx = talloc_tos();
2815 START_PROFILE(SMBunlink);
2817 if (req->wct < 1) {
2818 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2819 goto out;
2822 dirtype = SVAL(req->vwv+0, 0);
2824 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
2825 STR_TERMINATE, &status,
2826 &path_contains_wcard);
2827 if (!NT_STATUS_IS_OK(status)) {
2828 reply_nterror(req, status);
2829 goto out;
2832 status = filename_convert(ctx, conn,
2833 req->flags2 & FLAGS2_DFS_PATHNAMES,
2834 name,
2835 UCF_COND_ALLOW_WCARD_LCOMP,
2836 &path_contains_wcard,
2837 &smb_fname);
2838 if (!NT_STATUS_IS_OK(status)) {
2839 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2840 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2841 ERRSRV, ERRbadpath);
2842 goto out;
2844 reply_nterror(req, status);
2845 goto out;
2848 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
2850 status = unlink_internals(conn, req, dirtype, smb_fname,
2851 path_contains_wcard);
2852 if (!NT_STATUS_IS_OK(status)) {
2853 if (open_was_deferred(req->sconn, req->mid)) {
2854 /* We have re-scheduled this call. */
2855 goto out;
2857 reply_nterror(req, status);
2858 goto out;
2861 reply_outbuf(req, 0, 0);
2862 out:
2863 TALLOC_FREE(smb_fname);
2864 END_PROFILE(SMBunlink);
2865 return;
2868 /****************************************************************************
2869 Fail for readbraw.
2870 ****************************************************************************/
2872 static void fail_readraw(void)
2874 const char *errstr = talloc_asprintf(talloc_tos(),
2875 "FAIL ! reply_readbraw: socket write fail (%s)",
2876 strerror(errno));
2877 if (!errstr) {
2878 errstr = "";
2880 exit_server_cleanly(errstr);
2883 /****************************************************************************
2884 Fake (read/write) sendfile. Returns -1 on read or write fail.
2885 ****************************************************************************/
2887 ssize_t fake_sendfile(files_struct *fsp, off_t startpos, size_t nread)
2889 size_t bufsize;
2890 size_t tosend = nread;
2891 char *buf;
2893 if (nread == 0) {
2894 return 0;
2897 bufsize = MIN(nread, 65536);
2899 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
2900 return -1;
2903 while (tosend > 0) {
2904 ssize_t ret;
2905 size_t cur_read;
2907 if (tosend > bufsize) {
2908 cur_read = bufsize;
2909 } else {
2910 cur_read = tosend;
2912 ret = read_file(fsp,buf,startpos,cur_read);
2913 if (ret == -1) {
2914 SAFE_FREE(buf);
2915 return -1;
2918 /* If we had a short read, fill with zeros. */
2919 if (ret < cur_read) {
2920 memset(buf + ret, '\0', cur_read - ret);
2923 if (write_data(fsp->conn->sconn->sock, buf, cur_read)
2924 != cur_read) {
2925 char addr[INET6_ADDRSTRLEN];
2927 * Try and give an error message saying what
2928 * client failed.
2930 DEBUG(0, ("write_data failed for client %s. "
2931 "Error %s\n",
2932 get_peer_addr(fsp->conn->sconn->sock, addr,
2933 sizeof(addr)),
2934 strerror(errno)));
2935 SAFE_FREE(buf);
2936 return -1;
2938 tosend -= cur_read;
2939 startpos += cur_read;
2942 SAFE_FREE(buf);
2943 return (ssize_t)nread;
2946 /****************************************************************************
2947 Deal with the case of sendfile reading less bytes from the file than
2948 requested. Fill with zeros (all we can do).
2949 ****************************************************************************/
2951 void sendfile_short_send(files_struct *fsp,
2952 ssize_t nread,
2953 size_t headersize,
2954 size_t smb_maxcnt)
2956 #define SHORT_SEND_BUFSIZE 1024
2957 if (nread < headersize) {
2958 DEBUG(0,("sendfile_short_send: sendfile failed to send "
2959 "header for file %s (%s). Terminating\n",
2960 fsp_str_dbg(fsp), strerror(errno)));
2961 exit_server_cleanly("sendfile_short_send failed");
2964 nread -= headersize;
2966 if (nread < smb_maxcnt) {
2967 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
2968 if (!buf) {
2969 exit_server_cleanly("sendfile_short_send: "
2970 "malloc failed");
2973 DEBUG(0,("sendfile_short_send: filling truncated file %s "
2974 "with zeros !\n", fsp_str_dbg(fsp)));
2976 while (nread < smb_maxcnt) {
2978 * We asked for the real file size and told sendfile
2979 * to not go beyond the end of the file. But it can
2980 * happen that in between our fstat call and the
2981 * sendfile call the file was truncated. This is very
2982 * bad because we have already announced the larger
2983 * number of bytes to the client.
2985 * The best we can do now is to send 0-bytes, just as
2986 * a read from a hole in a sparse file would do.
2988 * This should happen rarely enough that I don't care
2989 * about efficiency here :-)
2991 size_t to_write;
2993 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
2994 if (write_data(fsp->conn->sconn->sock, buf, to_write)
2995 != to_write) {
2996 char addr[INET6_ADDRSTRLEN];
2998 * Try and give an error message saying what
2999 * client failed.
3001 DEBUG(0, ("write_data failed for client %s. "
3002 "Error %s\n",
3003 get_peer_addr(
3004 fsp->conn->sconn->sock, addr,
3005 sizeof(addr)),
3006 strerror(errno)));
3007 exit_server_cleanly("sendfile_short_send: "
3008 "write_data failed");
3010 nread += to_write;
3012 SAFE_FREE(buf);
3016 /****************************************************************************
3017 Return a readbraw error (4 bytes of zero).
3018 ****************************************************************************/
3020 static void reply_readbraw_error(struct smbd_server_connection *sconn)
3022 char header[4];
3024 SIVAL(header,0,0);
3026 smbd_lock_socket(sconn);
3027 if (write_data(sconn->sock,header,4) != 4) {
3028 char addr[INET6_ADDRSTRLEN];
3030 * Try and give an error message saying what
3031 * client failed.
3033 DEBUG(0, ("write_data failed for client %s. "
3034 "Error %s\n",
3035 get_peer_addr(sconn->sock, addr, sizeof(addr)),
3036 strerror(errno)));
3038 fail_readraw();
3040 smbd_unlock_socket(sconn);
3043 /****************************************************************************
3044 Use sendfile in readbraw.
3045 ****************************************************************************/
3047 static void send_file_readbraw(connection_struct *conn,
3048 struct smb_request *req,
3049 files_struct *fsp,
3050 off_t startpos,
3051 size_t nread,
3052 ssize_t mincount)
3054 struct smbd_server_connection *sconn = req->sconn;
3055 char *outbuf = NULL;
3056 ssize_t ret=0;
3059 * We can only use sendfile on a non-chained packet
3060 * but we can use on a non-oplocked file. tridge proved this
3061 * on a train in Germany :-). JRA.
3062 * reply_readbraw has already checked the length.
3065 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3066 (fsp->wcp == NULL) &&
3067 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3068 ssize_t sendfile_read = -1;
3069 char header[4];
3070 DATA_BLOB header_blob;
3072 _smb_setlen(header,nread);
3073 header_blob = data_blob_const(header, 4);
3075 sendfile_read = SMB_VFS_SENDFILE(sconn->sock, fsp,
3076 &header_blob, startpos,
3077 nread);
3078 if (sendfile_read == -1) {
3079 /* Returning ENOSYS means no data at all was sent.
3080 * Do this as a normal read. */
3081 if (errno == ENOSYS) {
3082 goto normal_readbraw;
3086 * Special hack for broken Linux with no working sendfile. If we
3087 * return EINTR we sent the header but not the rest of the data.
3088 * Fake this up by doing read/write calls.
3090 if (errno == EINTR) {
3091 /* Ensure we don't do this again. */
3092 set_use_sendfile(SNUM(conn), False);
3093 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3095 if (fake_sendfile(fsp, startpos, nread) == -1) {
3096 DEBUG(0,("send_file_readbraw: "
3097 "fake_sendfile failed for "
3098 "file %s (%s).\n",
3099 fsp_str_dbg(fsp),
3100 strerror(errno)));
3101 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3103 return;
3106 DEBUG(0,("send_file_readbraw: sendfile failed for "
3107 "file %s (%s). Terminating\n",
3108 fsp_str_dbg(fsp), strerror(errno)));
3109 exit_server_cleanly("send_file_readbraw sendfile failed");
3110 } else if (sendfile_read == 0) {
3112 * Some sendfile implementations return 0 to indicate
3113 * that there was a short read, but nothing was
3114 * actually written to the socket. In this case,
3115 * fallback to the normal read path so the header gets
3116 * the correct byte count.
3118 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3119 "bytes falling back to the normal read: "
3120 "%s\n", fsp_str_dbg(fsp)));
3121 goto normal_readbraw;
3124 /* Deal with possible short send. */
3125 if (sendfile_read != 4+nread) {
3126 sendfile_short_send(fsp, sendfile_read, 4, nread);
3128 return;
3131 normal_readbraw:
3133 outbuf = talloc_array(NULL, char, nread+4);
3134 if (!outbuf) {
3135 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3136 (unsigned)(nread+4)));
3137 reply_readbraw_error(sconn);
3138 return;
3141 if (nread > 0) {
3142 ret = read_file(fsp,outbuf+4,startpos,nread);
3143 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3144 if (ret < mincount)
3145 ret = 0;
3146 #else
3147 if (ret < nread)
3148 ret = 0;
3149 #endif
3152 _smb_setlen(outbuf,ret);
3153 if (write_data(sconn->sock, outbuf, 4+ret) != 4+ret) {
3154 char addr[INET6_ADDRSTRLEN];
3156 * Try and give an error message saying what
3157 * client failed.
3159 DEBUG(0, ("write_data failed for client %s. "
3160 "Error %s\n",
3161 get_peer_addr(fsp->conn->sconn->sock, addr,
3162 sizeof(addr)),
3163 strerror(errno)));
3165 fail_readraw();
3168 TALLOC_FREE(outbuf);
3171 /****************************************************************************
3172 Reply to a readbraw (core+ protocol).
3173 ****************************************************************************/
3175 void reply_readbraw(struct smb_request *req)
3177 connection_struct *conn = req->conn;
3178 struct smbd_server_connection *sconn = req->sconn;
3179 ssize_t maxcount,mincount;
3180 size_t nread = 0;
3181 off_t startpos;
3182 files_struct *fsp;
3183 struct lock_struct lock;
3184 off_t size = 0;
3186 START_PROFILE(SMBreadbraw);
3188 if (srv_is_signing_active(sconn) ||
3189 is_encrypted_packet(sconn, req->inbuf)) {
3190 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3191 "raw reads/writes are disallowed.");
3194 if (req->wct < 8) {
3195 reply_readbraw_error(sconn);
3196 END_PROFILE(SMBreadbraw);
3197 return;
3200 if (sconn->smb1.echo_handler.trusted_fde) {
3201 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3202 "'async smb echo handler = yes'\n"));
3203 reply_readbraw_error(sconn);
3204 END_PROFILE(SMBreadbraw);
3205 return;
3209 * Special check if an oplock break has been issued
3210 * and the readraw request croses on the wire, we must
3211 * return a zero length response here.
3214 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3217 * We have to do a check_fsp by hand here, as
3218 * we must always return 4 zero bytes on error,
3219 * not a NTSTATUS.
3222 if (!fsp || !conn || conn != fsp->conn ||
3223 req->vuid != fsp->vuid ||
3224 fsp->is_directory || fsp->fh->fd == -1) {
3226 * fsp could be NULL here so use the value from the packet. JRA.
3228 DEBUG(3,("reply_readbraw: fnum %d not valid "
3229 "- cache prime?\n",
3230 (int)SVAL(req->vwv+0, 0)));
3231 reply_readbraw_error(sconn);
3232 END_PROFILE(SMBreadbraw);
3233 return;
3236 /* Do a "by hand" version of CHECK_READ. */
3237 if (!(fsp->can_read ||
3238 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3239 (fsp->access_mask & FILE_EXECUTE)))) {
3240 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3241 (int)SVAL(req->vwv+0, 0)));
3242 reply_readbraw_error(sconn);
3243 END_PROFILE(SMBreadbraw);
3244 return;
3247 flush_write_cache(fsp, READRAW_FLUSH);
3249 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3250 if(req->wct == 10) {
3252 * This is a large offset (64 bit) read.
3255 startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32);
3257 if(startpos < 0) {
3258 DEBUG(0,("reply_readbraw: negative 64 bit "
3259 "readraw offset (%.0f) !\n",
3260 (double)startpos ));
3261 reply_readbraw_error(sconn);
3262 END_PROFILE(SMBreadbraw);
3263 return;
3267 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3268 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3270 /* ensure we don't overrun the packet size */
3271 maxcount = MIN(65535,maxcount);
3273 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3274 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3275 &lock);
3277 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3278 reply_readbraw_error(sconn);
3279 END_PROFILE(SMBreadbraw);
3280 return;
3283 if (fsp_stat(fsp) == 0) {
3284 size = fsp->fsp_name->st.st_ex_size;
3287 if (startpos >= size) {
3288 nread = 0;
3289 } else {
3290 nread = MIN(maxcount,(size - startpos));
3293 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3294 if (nread < mincount)
3295 nread = 0;
3296 #endif
3298 DEBUG( 3, ( "reply_readbraw: %s start=%.0f max=%lu "
3299 "min=%lu nread=%lu\n",
3300 fsp_fnum_dbg(fsp), (double)startpos,
3301 (unsigned long)maxcount,
3302 (unsigned long)mincount,
3303 (unsigned long)nread ) );
3305 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3307 DEBUG(5,("reply_readbraw finished\n"));
3309 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3311 END_PROFILE(SMBreadbraw);
3312 return;
3315 #undef DBGC_CLASS
3316 #define DBGC_CLASS DBGC_LOCKING
3318 /****************************************************************************
3319 Reply to a lockread (core+ protocol).
3320 ****************************************************************************/
3322 void reply_lockread(struct smb_request *req)
3324 connection_struct *conn = req->conn;
3325 ssize_t nread = -1;
3326 char *data;
3327 off_t startpos;
3328 size_t numtoread;
3329 NTSTATUS status;
3330 files_struct *fsp;
3331 struct byte_range_lock *br_lck = NULL;
3332 char *p = NULL;
3333 struct smbd_server_connection *sconn = req->sconn;
3335 START_PROFILE(SMBlockread);
3337 if (req->wct < 5) {
3338 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3339 END_PROFILE(SMBlockread);
3340 return;
3343 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3345 if (!check_fsp(conn, req, fsp)) {
3346 END_PROFILE(SMBlockread);
3347 return;
3350 if (!CHECK_READ(fsp,req)) {
3351 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3352 END_PROFILE(SMBlockread);
3353 return;
3356 numtoread = SVAL(req->vwv+1, 0);
3357 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3359 numtoread = MIN(BUFFER_SIZE - (smb_size + 3*2 + 3), numtoread);
3361 reply_outbuf(req, 5, numtoread + 3);
3363 data = smb_buf(req->outbuf) + 3;
3366 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3367 * protocol request that predates the read/write lock concept.
3368 * Thus instead of asking for a read lock here we need to ask
3369 * for a write lock. JRA.
3370 * Note that the requested lock size is unaffected by max_recv.
3373 br_lck = do_lock(req->sconn->msg_ctx,
3374 fsp,
3375 (uint64_t)req->smbpid,
3376 (uint64_t)numtoread,
3377 (uint64_t)startpos,
3378 WRITE_LOCK,
3379 WINDOWS_LOCK,
3380 False, /* Non-blocking lock. */
3381 &status,
3382 NULL,
3383 NULL);
3384 TALLOC_FREE(br_lck);
3386 if (NT_STATUS_V(status)) {
3387 reply_nterror(req, status);
3388 END_PROFILE(SMBlockread);
3389 return;
3393 * However the requested READ size IS affected by max_recv. Insanity.... JRA.
3396 if (numtoread > sconn->smb1.negprot.max_recv) {
3397 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \
3398 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3399 (unsigned int)numtoread,
3400 (unsigned int)sconn->smb1.negprot.max_recv));
3401 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3403 nread = read_file(fsp,data,startpos,numtoread);
3405 if (nread < 0) {
3406 reply_nterror(req, map_nt_error_from_unix(errno));
3407 END_PROFILE(SMBlockread);
3408 return;
3411 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3413 SSVAL(req->outbuf,smb_vwv0,nread);
3414 SSVAL(req->outbuf,smb_vwv5,nread+3);
3415 p = smb_buf(req->outbuf);
3416 SCVAL(p,0,0); /* pad byte. */
3417 SSVAL(p,1,nread);
3419 DEBUG(3,("lockread %s num=%d nread=%d\n",
3420 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3422 END_PROFILE(SMBlockread);
3423 return;
3426 #undef DBGC_CLASS
3427 #define DBGC_CLASS DBGC_ALL
3429 /****************************************************************************
3430 Reply to a read.
3431 ****************************************************************************/
3433 void reply_read(struct smb_request *req)
3435 connection_struct *conn = req->conn;
3436 size_t numtoread;
3437 ssize_t nread = 0;
3438 char *data;
3439 off_t startpos;
3440 int outsize = 0;
3441 files_struct *fsp;
3442 struct lock_struct lock;
3443 struct smbd_server_connection *sconn = req->sconn;
3445 START_PROFILE(SMBread);
3447 if (req->wct < 3) {
3448 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3449 END_PROFILE(SMBread);
3450 return;
3453 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3455 if (!check_fsp(conn, req, fsp)) {
3456 END_PROFILE(SMBread);
3457 return;
3460 if (!CHECK_READ(fsp,req)) {
3461 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3462 END_PROFILE(SMBread);
3463 return;
3466 numtoread = SVAL(req->vwv+1, 0);
3467 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3469 numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
3472 * The requested read size cannot be greater than max_recv. JRA.
3474 if (numtoread > sconn->smb1.negprot.max_recv) {
3475 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \
3476 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3477 (unsigned int)numtoread,
3478 (unsigned int)sconn->smb1.negprot.max_recv));
3479 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3482 reply_outbuf(req, 5, numtoread+3);
3484 data = smb_buf(req->outbuf) + 3;
3486 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3487 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3488 &lock);
3490 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3491 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3492 END_PROFILE(SMBread);
3493 return;
3496 if (numtoread > 0)
3497 nread = read_file(fsp,data,startpos,numtoread);
3499 if (nread < 0) {
3500 reply_nterror(req, map_nt_error_from_unix(errno));
3501 goto strict_unlock;
3504 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3506 SSVAL(req->outbuf,smb_vwv0,nread);
3507 SSVAL(req->outbuf,smb_vwv5,nread+3);
3508 SCVAL(smb_buf(req->outbuf),0,1);
3509 SSVAL(smb_buf(req->outbuf),1,nread);
3511 DEBUG(3, ("read %s num=%d nread=%d\n",
3512 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3514 strict_unlock:
3515 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3517 END_PROFILE(SMBread);
3518 return;
3521 /****************************************************************************
3522 Setup readX header.
3523 ****************************************************************************/
3525 static int setup_readX_header(struct smb_request *req, char *outbuf,
3526 size_t smb_maxcnt)
3528 int outsize;
3530 outsize = srv_set_message(outbuf,12,smb_maxcnt,False);
3532 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3534 SCVAL(outbuf,smb_vwv0,0xFF);
3535 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3536 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3537 SSVAL(outbuf,smb_vwv6,
3538 (smb_wct - 4) /* offset from smb header to wct */
3539 + 1 /* the wct field */
3540 + 12 * sizeof(uint16_t) /* vwv */
3541 + 2); /* the buflen field */
3542 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3543 SSVAL(outbuf,smb_vwv11,smb_maxcnt);
3544 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3545 _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
3546 return outsize;
3549 /****************************************************************************
3550 Reply to a read and X - possibly using sendfile.
3551 ****************************************************************************/
3553 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3554 files_struct *fsp, off_t startpos,
3555 size_t smb_maxcnt)
3557 ssize_t nread = -1;
3558 struct lock_struct lock;
3559 int saved_errno = 0;
3561 if(fsp_stat(fsp) == -1) {
3562 reply_nterror(req, map_nt_error_from_unix(errno));
3563 return;
3566 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3567 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3568 &lock);
3570 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3571 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3572 return;
3575 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3576 (startpos > fsp->fsp_name->st.st_ex_size)
3577 || (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3579 * We already know that we would do a short read, so don't
3580 * try the sendfile() path.
3582 goto nosendfile_read;
3586 * We can only use sendfile on a non-chained packet
3587 * but we can use on a non-oplocked file. tridge proved this
3588 * on a train in Germany :-). JRA.
3591 if (!req_is_in_chain(req) &&
3592 !is_encrypted_packet(req->sconn, req->inbuf) &&
3593 (fsp->base_fsp == NULL) &&
3594 (fsp->wcp == NULL) &&
3595 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3596 uint8 headerbuf[smb_size + 12 * 2];
3597 DATA_BLOB header;
3600 * Set up the packet header before send. We
3601 * assume here the sendfile will work (get the
3602 * correct amount of data).
3605 header = data_blob_const(headerbuf, sizeof(headerbuf));
3607 construct_reply_common_req(req, (char *)headerbuf);
3608 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3610 nread = SMB_VFS_SENDFILE(req->sconn->sock, fsp, &header,
3611 startpos, smb_maxcnt);
3612 if (nread == -1) {
3613 /* Returning ENOSYS means no data at all was sent.
3614 Do this as a normal read. */
3615 if (errno == ENOSYS) {
3616 goto normal_read;
3620 * Special hack for broken Linux with no working sendfile. If we
3621 * return EINTR we sent the header but not the rest of the data.
3622 * Fake this up by doing read/write calls.
3625 if (errno == EINTR) {
3626 /* Ensure we don't do this again. */
3627 set_use_sendfile(SNUM(conn), False);
3628 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3629 nread = fake_sendfile(fsp, startpos,
3630 smb_maxcnt);
3631 if (nread == -1) {
3632 DEBUG(0,("send_file_readX: "
3633 "fake_sendfile failed for "
3634 "file %s (%s).\n",
3635 fsp_str_dbg(fsp),
3636 strerror(errno)));
3637 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3639 DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
3640 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3641 /* No outbuf here means successful sendfile. */
3642 goto strict_unlock;
3645 DEBUG(0,("send_file_readX: sendfile failed for file "
3646 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3647 strerror(errno)));
3648 exit_server_cleanly("send_file_readX sendfile failed");
3649 } else if (nread == 0) {
3651 * Some sendfile implementations return 0 to indicate
3652 * that there was a short read, but nothing was
3653 * actually written to the socket. In this case,
3654 * fallback to the normal read path so the header gets
3655 * the correct byte count.
3657 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
3658 "falling back to the normal read: %s\n",
3659 fsp_str_dbg(fsp)));
3660 goto normal_read;
3663 DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n",
3664 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3666 /* Deal with possible short send. */
3667 if (nread != smb_maxcnt + sizeof(headerbuf)) {
3668 sendfile_short_send(fsp, nread, sizeof(headerbuf), smb_maxcnt);
3670 /* No outbuf here means successful sendfile. */
3671 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
3672 SMB_PERFCOUNT_END(&req->pcd);
3673 goto strict_unlock;
3676 normal_read:
3678 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3679 uint8 headerbuf[smb_size + 2*12];
3681 construct_reply_common_req(req, (char *)headerbuf);
3682 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3684 /* Send out the header. */
3685 if (write_data(req->sconn->sock, (char *)headerbuf,
3686 sizeof(headerbuf)) != sizeof(headerbuf)) {
3688 char addr[INET6_ADDRSTRLEN];
3690 * Try and give an error message saying what
3691 * client failed.
3693 DEBUG(0, ("write_data failed for client %s. "
3694 "Error %s\n",
3695 get_peer_addr(req->sconn->sock, addr,
3696 sizeof(addr)),
3697 strerror(errno)));
3699 DEBUG(0,("send_file_readX: write_data failed for file "
3700 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3701 strerror(errno)));
3702 exit_server_cleanly("send_file_readX sendfile failed");
3704 nread = fake_sendfile(fsp, startpos, smb_maxcnt);
3705 if (nread == -1) {
3706 DEBUG(0,("send_file_readX: fake_sendfile failed for "
3707 "file %s (%s).\n", fsp_str_dbg(fsp),
3708 strerror(errno)));
3709 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3711 goto strict_unlock;
3714 nosendfile_read:
3716 reply_outbuf(req, 12, smb_maxcnt);
3717 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
3718 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
3720 nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt);
3721 saved_errno = errno;
3723 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3725 if (nread < 0) {
3726 reply_nterror(req, map_nt_error_from_unix(saved_errno));
3727 return;
3730 setup_readX_header(req, (char *)req->outbuf, nread);
3732 DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
3733 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3734 return;
3736 strict_unlock:
3737 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3738 TALLOC_FREE(req->outbuf);
3739 return;
3742 /****************************************************************************
3743 Reply to a read and X.
3744 ****************************************************************************/
3746 void reply_read_and_X(struct smb_request *req)
3748 struct smbd_server_connection *sconn = req->sconn;
3749 connection_struct *conn = req->conn;
3750 files_struct *fsp;
3751 off_t startpos;
3752 size_t smb_maxcnt;
3753 bool big_readX = False;
3754 #if 0
3755 size_t smb_mincnt = SVAL(req->vwv+6, 0);
3756 #endif
3758 START_PROFILE(SMBreadX);
3760 if ((req->wct != 10) && (req->wct != 12)) {
3761 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3762 return;
3765 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
3766 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3767 smb_maxcnt = SVAL(req->vwv+5, 0);
3769 /* If it's an IPC, pass off the pipe handler. */
3770 if (IS_IPC(conn)) {
3771 reply_pipe_read_and_X(req);
3772 END_PROFILE(SMBreadX);
3773 return;
3776 if (!check_fsp(conn, req, fsp)) {
3777 END_PROFILE(SMBreadX);
3778 return;
3781 if (!CHECK_READ(fsp,req)) {
3782 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3783 END_PROFILE(SMBreadX);
3784 return;
3787 if ((sconn->smb1.unix_info.client_cap_low & CIFS_UNIX_LARGE_READ_CAP) ||
3788 (get_remote_arch() == RA_SAMBA)) {
3790 * This is Samba only behavior (up to Samba 3.6)!
3792 * Windows 2008 R2 ignores the upper_size,
3793 * so we do unless unix extentions are active
3794 * or "smbclient" is talking to us.
3796 size_t upper_size = SVAL(req->vwv+7, 0);
3797 smb_maxcnt |= (upper_size<<16);
3798 if (upper_size > 1) {
3799 /* Can't do this on a chained packet. */
3800 if ((CVAL(req->vwv+0, 0) != 0xFF)) {
3801 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3802 END_PROFILE(SMBreadX);
3803 return;
3805 /* We currently don't do this on signed or sealed data. */
3806 if (srv_is_signing_active(req->sconn) ||
3807 is_encrypted_packet(req->sconn, req->inbuf)) {
3808 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3809 END_PROFILE(SMBreadX);
3810 return;
3812 /* Is there room in the reply for this data ? */
3813 if (smb_maxcnt > (0xFFFFFF - (smb_size -4 + 12*2))) {
3814 reply_nterror(req,
3815 NT_STATUS_INVALID_PARAMETER);
3816 END_PROFILE(SMBreadX);
3817 return;
3819 big_readX = True;
3823 if (req->wct == 12) {
3825 * This is a large offset (64 bit) read.
3827 startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
3831 if (!big_readX) {
3832 NTSTATUS status = schedule_aio_read_and_X(conn,
3833 req,
3834 fsp,
3835 startpos,
3836 smb_maxcnt);
3837 if (NT_STATUS_IS_OK(status)) {
3838 /* Read scheduled - we're done. */
3839 goto out;
3841 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
3842 /* Real error - report to client. */
3843 END_PROFILE(SMBreadX);
3844 reply_nterror(req, status);
3845 return;
3847 /* NT_STATUS_RETRY - fall back to sync read. */
3850 smbd_lock_socket(req->sconn);
3851 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
3852 smbd_unlock_socket(req->sconn);
3854 out:
3855 END_PROFILE(SMBreadX);
3856 return;
3859 /****************************************************************************
3860 Error replies to writebraw must have smb_wct == 1. Fix this up.
3861 ****************************************************************************/
3863 void error_to_writebrawerr(struct smb_request *req)
3865 uint8 *old_outbuf = req->outbuf;
3867 reply_outbuf(req, 1, 0);
3869 memcpy(req->outbuf, old_outbuf, smb_size);
3870 TALLOC_FREE(old_outbuf);
3873 /****************************************************************************
3874 Read 4 bytes of a smb packet and return the smb length of the packet.
3875 Store the result in the buffer. This version of the function will
3876 never return a session keepalive (length of zero).
3877 Timeout is in milliseconds.
3878 ****************************************************************************/
3880 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
3881 size_t *len)
3883 uint8_t msgtype = NBSSkeepalive;
3885 while (msgtype == NBSSkeepalive) {
3886 NTSTATUS status;
3888 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
3889 len);
3890 if (!NT_STATUS_IS_OK(status)) {
3891 char addr[INET6_ADDRSTRLEN];
3892 /* Try and give an error message
3893 * saying what client failed. */
3894 DEBUG(0, ("read_fd_with_timeout failed for "
3895 "client %s read error = %s.\n",
3896 get_peer_addr(fd,addr,sizeof(addr)),
3897 nt_errstr(status)));
3898 return status;
3901 msgtype = CVAL(inbuf, 0);
3904 DEBUG(10,("read_smb_length: got smb length of %lu\n",
3905 (unsigned long)len));
3907 return NT_STATUS_OK;
3910 /****************************************************************************
3911 Reply to a writebraw (core+ or LANMAN1.0 protocol).
3912 ****************************************************************************/
3914 void reply_writebraw(struct smb_request *req)
3916 connection_struct *conn = req->conn;
3917 char *buf = NULL;
3918 ssize_t nwritten=0;
3919 ssize_t total_written=0;
3920 size_t numtowrite=0;
3921 size_t tcount;
3922 off_t startpos;
3923 const char *data=NULL;
3924 bool write_through;
3925 files_struct *fsp;
3926 struct lock_struct lock;
3927 NTSTATUS status;
3929 START_PROFILE(SMBwritebraw);
3932 * If we ever reply with an error, it must have the SMB command
3933 * type of SMBwritec, not SMBwriteBraw, as this tells the client
3934 * we're finished.
3936 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
3938 if (srv_is_signing_active(req->sconn)) {
3939 END_PROFILE(SMBwritebraw);
3940 exit_server_cleanly("reply_writebraw: SMB signing is active - "
3941 "raw reads/writes are disallowed.");
3944 if (req->wct < 12) {
3945 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3946 error_to_writebrawerr(req);
3947 END_PROFILE(SMBwritebraw);
3948 return;
3951 if (req->sconn->smb1.echo_handler.trusted_fde) {
3952 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
3953 "'async smb echo handler = yes'\n"));
3954 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3955 error_to_writebrawerr(req);
3956 END_PROFILE(SMBwritebraw);
3957 return;
3960 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3961 if (!check_fsp(conn, req, fsp)) {
3962 error_to_writebrawerr(req);
3963 END_PROFILE(SMBwritebraw);
3964 return;
3967 if (!CHECK_WRITE(fsp)) {
3968 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3969 error_to_writebrawerr(req);
3970 END_PROFILE(SMBwritebraw);
3971 return;
3974 tcount = IVAL(req->vwv+1, 0);
3975 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3976 write_through = BITSETW(req->vwv+7,0);
3978 /* We have to deal with slightly different formats depending
3979 on whether we are using the core+ or lanman1.0 protocol */
3981 if(get_Protocol() <= PROTOCOL_COREPLUS) {
3982 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
3983 data = smb_buf_const(req->inbuf);
3984 } else {
3985 numtowrite = SVAL(req->vwv+10, 0);
3986 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
3989 /* Ensure we don't write bytes past the end of this packet. */
3990 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
3991 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3992 error_to_writebrawerr(req);
3993 END_PROFILE(SMBwritebraw);
3994 return;
3997 if (!fsp->print_file) {
3998 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3999 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4000 &lock);
4002 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4003 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4004 error_to_writebrawerr(req);
4005 END_PROFILE(SMBwritebraw);
4006 return;
4010 if (numtowrite>0) {
4011 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4014 DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d "
4015 "wrote=%d sync=%d\n",
4016 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4017 (int)nwritten, (int)write_through));
4019 if (nwritten < (ssize_t)numtowrite) {
4020 reply_nterror(req, NT_STATUS_DISK_FULL);
4021 error_to_writebrawerr(req);
4022 goto strict_unlock;
4025 total_written = nwritten;
4027 /* Allocate a buffer of 64k + length. */
4028 buf = talloc_array(NULL, char, 65540);
4029 if (!buf) {
4030 reply_nterror(req, NT_STATUS_NO_MEMORY);
4031 error_to_writebrawerr(req);
4032 goto strict_unlock;
4035 /* Return a SMBwritebraw message to the redirector to tell
4036 * it to send more bytes */
4038 memcpy(buf, req->inbuf, smb_size);
4039 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4040 SCVAL(buf,smb_com,SMBwritebraw);
4041 SSVALS(buf,smb_vwv0,0xFFFF);
4042 show_msg(buf);
4043 if (!srv_send_smb(req->sconn,
4044 buf,
4045 false, 0, /* no signing */
4046 IS_CONN_ENCRYPTED(conn),
4047 &req->pcd)) {
4048 exit_server_cleanly("reply_writebraw: srv_send_smb "
4049 "failed.");
4052 /* Now read the raw data into the buffer and write it */
4053 status = read_smb_length(req->sconn->sock, buf, SMB_SECONDARY_WAIT,
4054 &numtowrite);
4055 if (!NT_STATUS_IS_OK(status)) {
4056 exit_server_cleanly("secondary writebraw failed");
4059 /* Set up outbuf to return the correct size */
4060 reply_outbuf(req, 1, 0);
4062 if (numtowrite != 0) {
4064 if (numtowrite > 0xFFFF) {
4065 DEBUG(0,("reply_writebraw: Oversize secondary write "
4066 "raw requested (%u). Terminating\n",
4067 (unsigned int)numtowrite ));
4068 exit_server_cleanly("secondary writebraw failed");
4071 if (tcount > nwritten+numtowrite) {
4072 DEBUG(3,("reply_writebraw: Client overestimated the "
4073 "write %d %d %d\n",
4074 (int)tcount,(int)nwritten,(int)numtowrite));
4077 status = read_data(req->sconn->sock, buf+4, numtowrite);
4079 if (!NT_STATUS_IS_OK(status)) {
4080 char addr[INET6_ADDRSTRLEN];
4081 /* Try and give an error message
4082 * saying what client failed. */
4083 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4084 "raw read failed (%s) for client %s. "
4085 "Terminating\n", nt_errstr(status),
4086 get_peer_addr(req->sconn->sock, addr,
4087 sizeof(addr))));
4088 exit_server_cleanly("secondary writebraw failed");
4091 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4092 if (nwritten == -1) {
4093 TALLOC_FREE(buf);
4094 reply_nterror(req, map_nt_error_from_unix(errno));
4095 error_to_writebrawerr(req);
4096 goto strict_unlock;
4099 if (nwritten < (ssize_t)numtowrite) {
4100 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4101 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4104 if (nwritten > 0) {
4105 total_written += nwritten;
4109 TALLOC_FREE(buf);
4110 SSVAL(req->outbuf,smb_vwv0,total_written);
4112 status = sync_file(conn, fsp, write_through);
4113 if (!NT_STATUS_IS_OK(status)) {
4114 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4115 fsp_str_dbg(fsp), nt_errstr(status)));
4116 reply_nterror(req, status);
4117 error_to_writebrawerr(req);
4118 goto strict_unlock;
4121 DEBUG(3,("reply_writebraw: secondart write %s start=%.0f num=%d "
4122 "wrote=%d\n",
4123 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4124 (int)total_written));
4126 if (!fsp->print_file) {
4127 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4130 /* We won't return a status if write through is not selected - this
4131 * follows what WfWg does */
4132 END_PROFILE(SMBwritebraw);
4134 if (!write_through && total_written==tcount) {
4136 #if RABBIT_PELLET_FIX
4138 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4139 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4140 * JRA.
4142 if (!send_keepalive(req->sconn->sock)) {
4143 exit_server_cleanly("reply_writebraw: send of "
4144 "keepalive failed");
4146 #endif
4147 TALLOC_FREE(req->outbuf);
4149 return;
4151 strict_unlock:
4152 if (!fsp->print_file) {
4153 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4156 END_PROFILE(SMBwritebraw);
4157 return;
4160 #undef DBGC_CLASS
4161 #define DBGC_CLASS DBGC_LOCKING
4163 /****************************************************************************
4164 Reply to a writeunlock (core+).
4165 ****************************************************************************/
4167 void reply_writeunlock(struct smb_request *req)
4169 connection_struct *conn = req->conn;
4170 ssize_t nwritten = -1;
4171 size_t numtowrite;
4172 off_t startpos;
4173 const char *data;
4174 NTSTATUS status = NT_STATUS_OK;
4175 files_struct *fsp;
4176 struct lock_struct lock;
4177 int saved_errno = 0;
4179 START_PROFILE(SMBwriteunlock);
4181 if (req->wct < 5) {
4182 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4183 END_PROFILE(SMBwriteunlock);
4184 return;
4187 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4189 if (!check_fsp(conn, req, fsp)) {
4190 END_PROFILE(SMBwriteunlock);
4191 return;
4194 if (!CHECK_WRITE(fsp)) {
4195 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4196 END_PROFILE(SMBwriteunlock);
4197 return;
4200 numtowrite = SVAL(req->vwv+1, 0);
4201 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4202 data = (const char *)req->buf + 3;
4204 if (!fsp->print_file && numtowrite > 0) {
4205 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4206 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4207 &lock);
4209 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4210 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4211 END_PROFILE(SMBwriteunlock);
4212 return;
4216 /* The special X/Open SMB protocol handling of
4217 zero length writes is *NOT* done for
4218 this call */
4219 if(numtowrite == 0) {
4220 nwritten = 0;
4221 } else {
4222 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4223 saved_errno = errno;
4226 status = sync_file(conn, fsp, False /* write through */);
4227 if (!NT_STATUS_IS_OK(status)) {
4228 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4229 fsp_str_dbg(fsp), nt_errstr(status)));
4230 reply_nterror(req, status);
4231 goto strict_unlock;
4234 if(nwritten < 0) {
4235 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4236 goto strict_unlock;
4239 if((nwritten < numtowrite) && (numtowrite != 0)) {
4240 reply_nterror(req, NT_STATUS_DISK_FULL);
4241 goto strict_unlock;
4244 if (numtowrite && !fsp->print_file) {
4245 status = do_unlock(req->sconn->msg_ctx,
4246 fsp,
4247 (uint64_t)req->smbpid,
4248 (uint64_t)numtowrite,
4249 (uint64_t)startpos,
4250 WINDOWS_LOCK);
4252 if (NT_STATUS_V(status)) {
4253 reply_nterror(req, status);
4254 goto strict_unlock;
4258 reply_outbuf(req, 1, 0);
4260 SSVAL(req->outbuf,smb_vwv0,nwritten);
4262 DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
4263 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4265 strict_unlock:
4266 if (numtowrite && !fsp->print_file) {
4267 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4270 END_PROFILE(SMBwriteunlock);
4271 return;
4274 #undef DBGC_CLASS
4275 #define DBGC_CLASS DBGC_ALL
4277 /****************************************************************************
4278 Reply to a write.
4279 ****************************************************************************/
4281 void reply_write(struct smb_request *req)
4283 connection_struct *conn = req->conn;
4284 size_t numtowrite;
4285 ssize_t nwritten = -1;
4286 off_t startpos;
4287 const char *data;
4288 files_struct *fsp;
4289 struct lock_struct lock;
4290 NTSTATUS status;
4291 int saved_errno = 0;
4293 START_PROFILE(SMBwrite);
4295 if (req->wct < 5) {
4296 END_PROFILE(SMBwrite);
4297 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4298 return;
4301 /* If it's an IPC, pass off the pipe handler. */
4302 if (IS_IPC(conn)) {
4303 reply_pipe_write(req);
4304 END_PROFILE(SMBwrite);
4305 return;
4308 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4310 if (!check_fsp(conn, req, fsp)) {
4311 END_PROFILE(SMBwrite);
4312 return;
4315 if (!CHECK_WRITE(fsp)) {
4316 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4317 END_PROFILE(SMBwrite);
4318 return;
4321 numtowrite = SVAL(req->vwv+1, 0);
4322 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4323 data = (const char *)req->buf + 3;
4325 if (!fsp->print_file) {
4326 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4327 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4328 &lock);
4330 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4331 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4332 END_PROFILE(SMBwrite);
4333 return;
4338 * X/Open SMB protocol says that if smb_vwv1 is
4339 * zero then the file size should be extended or
4340 * truncated to the size given in smb_vwv[2-3].
4343 if(numtowrite == 0) {
4345 * This is actually an allocate call, and set EOF. JRA.
4347 nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
4348 if (nwritten < 0) {
4349 reply_nterror(req, NT_STATUS_DISK_FULL);
4350 goto strict_unlock;
4352 nwritten = vfs_set_filelen(fsp, (off_t)startpos);
4353 if (nwritten < 0) {
4354 reply_nterror(req, NT_STATUS_DISK_FULL);
4355 goto strict_unlock;
4357 trigger_write_time_update_immediate(fsp);
4358 } else {
4359 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4362 status = sync_file(conn, fsp, False);
4363 if (!NT_STATUS_IS_OK(status)) {
4364 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4365 fsp_str_dbg(fsp), nt_errstr(status)));
4366 reply_nterror(req, status);
4367 goto strict_unlock;
4370 if(nwritten < 0) {
4371 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4372 goto strict_unlock;
4375 if((nwritten == 0) && (numtowrite != 0)) {
4376 reply_nterror(req, NT_STATUS_DISK_FULL);
4377 goto strict_unlock;
4380 reply_outbuf(req, 1, 0);
4382 SSVAL(req->outbuf,smb_vwv0,nwritten);
4384 if (nwritten < (ssize_t)numtowrite) {
4385 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4386 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4389 DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4391 strict_unlock:
4392 if (!fsp->print_file) {
4393 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4396 END_PROFILE(SMBwrite);
4397 return;
4400 /****************************************************************************
4401 Ensure a buffer is a valid writeX for recvfile purposes.
4402 ****************************************************************************/
4404 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4405 (2*14) + /* word count (including bcc) */ \
4406 1 /* pad byte */)
4408 bool is_valid_writeX_buffer(struct smbd_server_connection *sconn,
4409 const uint8_t *inbuf)
4411 size_t numtowrite;
4412 connection_struct *conn = NULL;
4413 unsigned int doff = 0;
4414 size_t len = smb_len_large(inbuf);
4415 struct smbXsrv_tcon *tcon;
4416 NTSTATUS status;
4417 NTTIME now = 0;
4419 if (is_encrypted_packet(sconn, inbuf)) {
4420 /* Can't do this on encrypted
4421 * connections. */
4422 return false;
4425 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4426 return false;
4429 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4430 CVAL(inbuf,smb_wct) != 14) {
4431 DEBUG(10,("is_valid_writeX_buffer: chained or "
4432 "invalid word length.\n"));
4433 return false;
4436 status = smb1srv_tcon_lookup(sconn->conn, SVAL(inbuf, smb_tid),
4437 now, &tcon);
4438 if (!NT_STATUS_IS_OK(status)) {
4439 DEBUG(10,("is_valid_writeX_buffer: bad tid\n"));
4440 return false;
4442 conn = tcon->compat;
4444 if (IS_IPC(conn)) {
4445 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4446 return false;
4448 if (IS_PRINT(conn)) {
4449 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4450 return false;
4452 doff = SVAL(inbuf,smb_vwv11);
4454 numtowrite = SVAL(inbuf,smb_vwv10);
4456 if (len > doff && len - doff > 0xFFFF) {
4457 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4460 if (numtowrite == 0) {
4461 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4462 return false;
4465 /* Ensure the sizes match up. */
4466 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4467 /* no pad byte...old smbclient :-( */
4468 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4469 (unsigned int)doff,
4470 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4471 return false;
4474 if (len - doff != numtowrite) {
4475 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4476 "len = %u, doff = %u, numtowrite = %u\n",
4477 (unsigned int)len,
4478 (unsigned int)doff,
4479 (unsigned int)numtowrite ));
4480 return false;
4483 DEBUG(10,("is_valid_writeX_buffer: true "
4484 "len = %u, doff = %u, numtowrite = %u\n",
4485 (unsigned int)len,
4486 (unsigned int)doff,
4487 (unsigned int)numtowrite ));
4489 return true;
4492 /****************************************************************************
4493 Reply to a write and X.
4494 ****************************************************************************/
4496 void reply_write_and_X(struct smb_request *req)
4498 connection_struct *conn = req->conn;
4499 files_struct *fsp;
4500 struct lock_struct lock;
4501 off_t startpos;
4502 size_t numtowrite;
4503 bool write_through;
4504 ssize_t nwritten;
4505 unsigned int smb_doff;
4506 unsigned int smblen;
4507 const char *data;
4508 NTSTATUS status;
4509 int saved_errno = 0;
4511 START_PROFILE(SMBwriteX);
4513 if ((req->wct != 12) && (req->wct != 14)) {
4514 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4515 goto out;
4518 numtowrite = SVAL(req->vwv+10, 0);
4519 smb_doff = SVAL(req->vwv+11, 0);
4520 smblen = smb_len(req->inbuf);
4522 if (req->unread_bytes > 0xFFFF ||
4523 (smblen > smb_doff &&
4524 smblen - smb_doff > 0xFFFF)) {
4525 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
4528 if (req->unread_bytes) {
4529 /* Can't do a recvfile write on IPC$ */
4530 if (IS_IPC(conn)) {
4531 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4532 goto out;
4534 if (numtowrite != req->unread_bytes) {
4535 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4536 goto out;
4538 } else {
4539 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4540 smb_doff + numtowrite > smblen) {
4541 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4542 goto out;
4546 /* If it's an IPC, pass off the pipe handler. */
4547 if (IS_IPC(conn)) {
4548 if (req->unread_bytes) {
4549 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4550 goto out;
4552 reply_pipe_write_and_X(req);
4553 goto out;
4556 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4557 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4558 write_through = BITSETW(req->vwv+7,0);
4560 if (!check_fsp(conn, req, fsp)) {
4561 goto out;
4564 if (!CHECK_WRITE(fsp)) {
4565 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4566 goto out;
4569 data = smb_base(req->inbuf) + smb_doff;
4571 if(req->wct == 14) {
4573 * This is a large offset (64 bit) write.
4575 startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
4579 /* X/Open SMB protocol says that, unlike SMBwrite
4580 if the length is zero then NO truncation is
4581 done, just a write of zero. To truncate a file,
4582 use SMBwrite. */
4584 if(numtowrite == 0) {
4585 nwritten = 0;
4586 } else {
4587 if (req->unread_bytes == 0) {
4588 status = schedule_aio_write_and_X(conn,
4589 req,
4590 fsp,
4591 data,
4592 startpos,
4593 numtowrite);
4595 if (NT_STATUS_IS_OK(status)) {
4596 /* write scheduled - we're done. */
4597 goto out;
4599 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4600 /* Real error - report to client. */
4601 reply_nterror(req, status);
4602 goto out;
4604 /* NT_STATUS_RETRY - fall through to sync write. */
4607 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4608 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4609 &lock);
4611 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4612 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4613 goto out;
4616 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4617 saved_errno = errno;
4619 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4622 if(nwritten < 0) {
4623 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4624 goto out;
4627 if((nwritten == 0) && (numtowrite != 0)) {
4628 reply_nterror(req, NT_STATUS_DISK_FULL);
4629 goto out;
4632 reply_outbuf(req, 6, 0);
4633 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
4634 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
4635 SSVAL(req->outbuf,smb_vwv2,nwritten);
4636 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4638 DEBUG(3,("writeX %s num=%d wrote=%d\n",
4639 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4641 status = sync_file(conn, fsp, write_through);
4642 if (!NT_STATUS_IS_OK(status)) {
4643 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4644 fsp_str_dbg(fsp), nt_errstr(status)));
4645 reply_nterror(req, status);
4646 goto out;
4649 END_PROFILE(SMBwriteX);
4650 return;
4652 out:
4653 if (req->unread_bytes) {
4654 /* writeX failed. drain socket. */
4655 if (drain_socket(req->sconn->sock, req->unread_bytes) !=
4656 req->unread_bytes) {
4657 smb_panic("failed to drain pending bytes");
4659 req->unread_bytes = 0;
4662 END_PROFILE(SMBwriteX);
4663 return;
4666 /****************************************************************************
4667 Reply to a lseek.
4668 ****************************************************************************/
4670 void reply_lseek(struct smb_request *req)
4672 connection_struct *conn = req->conn;
4673 off_t startpos;
4674 off_t res= -1;
4675 int mode,umode;
4676 files_struct *fsp;
4678 START_PROFILE(SMBlseek);
4680 if (req->wct < 4) {
4681 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4682 END_PROFILE(SMBlseek);
4683 return;
4686 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4688 if (!check_fsp(conn, req, fsp)) {
4689 return;
4692 flush_write_cache(fsp, SEEK_FLUSH);
4694 mode = SVAL(req->vwv+1, 0) & 3;
4695 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4696 startpos = (off_t)IVALS(req->vwv+2, 0);
4698 switch (mode) {
4699 case 0:
4700 umode = SEEK_SET;
4701 res = startpos;
4702 break;
4703 case 1:
4704 umode = SEEK_CUR;
4705 res = fsp->fh->pos + startpos;
4706 break;
4707 case 2:
4708 umode = SEEK_END;
4709 break;
4710 default:
4711 umode = SEEK_SET;
4712 res = startpos;
4713 break;
4716 if (umode == SEEK_END) {
4717 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
4718 if(errno == EINVAL) {
4719 off_t current_pos = startpos;
4721 if(fsp_stat(fsp) == -1) {
4722 reply_nterror(req,
4723 map_nt_error_from_unix(errno));
4724 END_PROFILE(SMBlseek);
4725 return;
4728 current_pos += fsp->fsp_name->st.st_ex_size;
4729 if(current_pos < 0)
4730 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
4734 if(res == -1) {
4735 reply_nterror(req, map_nt_error_from_unix(errno));
4736 END_PROFILE(SMBlseek);
4737 return;
4741 fsp->fh->pos = res;
4743 reply_outbuf(req, 2, 0);
4744 SIVAL(req->outbuf,smb_vwv0,res);
4746 DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n",
4747 fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode));
4749 END_PROFILE(SMBlseek);
4750 return;
4753 /****************************************************************************
4754 Reply to a flush.
4755 ****************************************************************************/
4757 void reply_flush(struct smb_request *req)
4759 connection_struct *conn = req->conn;
4760 uint16 fnum;
4761 files_struct *fsp;
4763 START_PROFILE(SMBflush);
4765 if (req->wct < 1) {
4766 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4767 return;
4770 fnum = SVAL(req->vwv+0, 0);
4771 fsp = file_fsp(req, fnum);
4773 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
4774 return;
4777 if (!fsp) {
4778 file_sync_all(conn);
4779 } else {
4780 NTSTATUS status = sync_file(conn, fsp, True);
4781 if (!NT_STATUS_IS_OK(status)) {
4782 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
4783 fsp_str_dbg(fsp), nt_errstr(status)));
4784 reply_nterror(req, status);
4785 END_PROFILE(SMBflush);
4786 return;
4790 reply_outbuf(req, 0, 0);
4792 DEBUG(3,("flush\n"));
4793 END_PROFILE(SMBflush);
4794 return;
4797 /****************************************************************************
4798 Reply to a exit.
4799 conn POINTER CAN BE NULL HERE !
4800 ****************************************************************************/
4802 void reply_exit(struct smb_request *req)
4804 START_PROFILE(SMBexit);
4806 file_close_pid(req->sconn, req->smbpid, req->vuid);
4808 reply_outbuf(req, 0, 0);
4810 DEBUG(3,("exit\n"));
4812 END_PROFILE(SMBexit);
4813 return;
4816 struct reply_close_state {
4817 files_struct *fsp;
4818 struct smb_request *smbreq;
4821 static void do_smb1_close(struct tevent_req *req);
4823 void reply_close(struct smb_request *req)
4825 connection_struct *conn = req->conn;
4826 NTSTATUS status = NT_STATUS_OK;
4827 files_struct *fsp = NULL;
4828 START_PROFILE(SMBclose);
4830 if (req->wct < 3) {
4831 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4832 END_PROFILE(SMBclose);
4833 return;
4836 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4839 * We can only use check_fsp if we know it's not a directory.
4842 if (!check_fsp_open(conn, req, fsp)) {
4843 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
4844 END_PROFILE(SMBclose);
4845 return;
4848 DEBUG(3, ("Close %s fd=%d %s (numopen=%d)\n",
4849 fsp->is_directory ? "directory" : "file",
4850 fsp->fh->fd, fsp_fnum_dbg(fsp),
4851 conn->num_files_open));
4853 if (!fsp->is_directory) {
4854 time_t t;
4857 * Take care of any time sent in the close.
4860 t = srv_make_unix_date3(req->vwv+1);
4861 set_close_write_time(fsp, convert_time_t_to_timespec(t));
4864 if (fsp->num_aio_requests != 0) {
4866 struct reply_close_state *state;
4868 DEBUG(10, ("closing with aio %u requests pending\n",
4869 fsp->num_aio_requests));
4872 * We depend on the aio_extra destructor to take care of this
4873 * close request once fsp->num_aio_request drops to 0.
4876 fsp->deferred_close = tevent_wait_send(
4877 fsp, fsp->conn->sconn->ev_ctx);
4878 if (fsp->deferred_close == NULL) {
4879 status = NT_STATUS_NO_MEMORY;
4880 goto done;
4883 state = talloc(fsp, struct reply_close_state);
4884 if (state == NULL) {
4885 TALLOC_FREE(fsp->deferred_close);
4886 status = NT_STATUS_NO_MEMORY;
4887 goto done;
4889 state->fsp = fsp;
4890 state->smbreq = talloc_move(fsp, &req);
4891 tevent_req_set_callback(fsp->deferred_close, do_smb1_close,
4892 state);
4893 END_PROFILE(SMBclose);
4894 return;
4898 * close_file() returns the unix errno if an error was detected on
4899 * close - normally this is due to a disk full error. If not then it
4900 * was probably an I/O error.
4903 status = close_file(req, fsp, NORMAL_CLOSE);
4904 done:
4905 if (!NT_STATUS_IS_OK(status)) {
4906 reply_nterror(req, status);
4907 END_PROFILE(SMBclose);
4908 return;
4911 reply_outbuf(req, 0, 0);
4912 END_PROFILE(SMBclose);
4913 return;
4916 static void do_smb1_close(struct tevent_req *req)
4918 struct reply_close_state *state = tevent_req_callback_data(
4919 req, struct reply_close_state);
4920 struct smb_request *smbreq;
4921 NTSTATUS status;
4922 int ret;
4924 ret = tevent_wait_recv(req);
4925 TALLOC_FREE(req);
4926 if (ret != 0) {
4927 DEBUG(10, ("tevent_wait_recv returned %s\n",
4928 strerror(ret)));
4930 * Continue anyway, this should never happen
4935 * fsp->smb2_close_request right now is a talloc grandchild of
4936 * fsp. When we close_file(fsp), it would go with it. No chance to
4937 * reply...
4939 smbreq = talloc_move(talloc_tos(), &state->smbreq);
4941 status = close_file(smbreq, state->fsp, NORMAL_CLOSE);
4942 if (NT_STATUS_IS_OK(status)) {
4943 reply_outbuf(smbreq, 0, 0);
4944 } else {
4945 reply_nterror(smbreq, status);
4947 if (!srv_send_smb(smbreq->sconn,
4948 (char *)smbreq->outbuf,
4949 true,
4950 smbreq->seqnum+1,
4951 IS_CONN_ENCRYPTED(smbreq->conn)||smbreq->encrypted,
4952 NULL)) {
4953 exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
4954 "failed.");
4956 TALLOC_FREE(smbreq);
4959 /****************************************************************************
4960 Reply to a writeclose (Core+ protocol).
4961 ****************************************************************************/
4963 void reply_writeclose(struct smb_request *req)
4965 connection_struct *conn = req->conn;
4966 size_t numtowrite;
4967 ssize_t nwritten = -1;
4968 NTSTATUS close_status = NT_STATUS_OK;
4969 off_t startpos;
4970 const char *data;
4971 struct timespec mtime;
4972 files_struct *fsp;
4973 struct lock_struct lock;
4975 START_PROFILE(SMBwriteclose);
4977 if (req->wct < 6) {
4978 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4979 END_PROFILE(SMBwriteclose);
4980 return;
4983 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4985 if (!check_fsp(conn, req, fsp)) {
4986 END_PROFILE(SMBwriteclose);
4987 return;
4989 if (!CHECK_WRITE(fsp)) {
4990 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4991 END_PROFILE(SMBwriteclose);
4992 return;
4995 numtowrite = SVAL(req->vwv+1, 0);
4996 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4997 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
4998 data = (const char *)req->buf + 1;
5000 if (!fsp->print_file) {
5001 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5002 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5003 &lock);
5005 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
5006 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5007 END_PROFILE(SMBwriteclose);
5008 return;
5012 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5014 set_close_write_time(fsp, mtime);
5017 * More insanity. W2K only closes the file if writelen > 0.
5018 * JRA.
5021 if (numtowrite) {
5022 DEBUG(3,("reply_writeclose: zero length write doesn't close "
5023 "file %s\n", fsp_str_dbg(fsp)));
5024 close_status = close_file(req, fsp, NORMAL_CLOSE);
5027 DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
5028 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
5029 conn->num_files_open));
5031 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
5032 reply_nterror(req, NT_STATUS_DISK_FULL);
5033 goto strict_unlock;
5036 if(!NT_STATUS_IS_OK(close_status)) {
5037 reply_nterror(req, close_status);
5038 goto strict_unlock;
5041 reply_outbuf(req, 1, 0);
5043 SSVAL(req->outbuf,smb_vwv0,nwritten);
5045 strict_unlock:
5046 if (numtowrite && !fsp->print_file) {
5047 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
5050 END_PROFILE(SMBwriteclose);
5051 return;
5054 #undef DBGC_CLASS
5055 #define DBGC_CLASS DBGC_LOCKING
5057 /****************************************************************************
5058 Reply to a lock.
5059 ****************************************************************************/
5061 void reply_lock(struct smb_request *req)
5063 connection_struct *conn = req->conn;
5064 uint64_t count,offset;
5065 NTSTATUS status;
5066 files_struct *fsp;
5067 struct byte_range_lock *br_lck = NULL;
5069 START_PROFILE(SMBlock);
5071 if (req->wct < 5) {
5072 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5073 END_PROFILE(SMBlock);
5074 return;
5077 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5079 if (!check_fsp(conn, req, fsp)) {
5080 END_PROFILE(SMBlock);
5081 return;
5084 count = (uint64_t)IVAL(req->vwv+1, 0);
5085 offset = (uint64_t)IVAL(req->vwv+3, 0);
5087 DEBUG(3,("lock fd=%d %s offset=%.0f count=%.0f\n",
5088 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count));
5090 br_lck = do_lock(req->sconn->msg_ctx,
5091 fsp,
5092 (uint64_t)req->smbpid,
5093 count,
5094 offset,
5095 WRITE_LOCK,
5096 WINDOWS_LOCK,
5097 False, /* Non-blocking lock. */
5098 &status,
5099 NULL,
5100 NULL);
5102 TALLOC_FREE(br_lck);
5104 if (NT_STATUS_V(status)) {
5105 reply_nterror(req, status);
5106 END_PROFILE(SMBlock);
5107 return;
5110 reply_outbuf(req, 0, 0);
5112 END_PROFILE(SMBlock);
5113 return;
5116 /****************************************************************************
5117 Reply to a unlock.
5118 ****************************************************************************/
5120 void reply_unlock(struct smb_request *req)
5122 connection_struct *conn = req->conn;
5123 uint64_t count,offset;
5124 NTSTATUS status;
5125 files_struct *fsp;
5127 START_PROFILE(SMBunlock);
5129 if (req->wct < 5) {
5130 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5131 END_PROFILE(SMBunlock);
5132 return;
5135 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5137 if (!check_fsp(conn, req, fsp)) {
5138 END_PROFILE(SMBunlock);
5139 return;
5142 count = (uint64_t)IVAL(req->vwv+1, 0);
5143 offset = (uint64_t)IVAL(req->vwv+3, 0);
5145 status = do_unlock(req->sconn->msg_ctx,
5146 fsp,
5147 (uint64_t)req->smbpid,
5148 count,
5149 offset,
5150 WINDOWS_LOCK);
5152 if (NT_STATUS_V(status)) {
5153 reply_nterror(req, status);
5154 END_PROFILE(SMBunlock);
5155 return;
5158 DEBUG( 3, ( "unlock fd=%d %s offset=%.0f count=%.0f\n",
5159 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count ) );
5161 reply_outbuf(req, 0, 0);
5163 END_PROFILE(SMBunlock);
5164 return;
5167 #undef DBGC_CLASS
5168 #define DBGC_CLASS DBGC_ALL
5170 /****************************************************************************
5171 Reply to a tdis.
5172 conn POINTER CAN BE NULL HERE !
5173 ****************************************************************************/
5175 void reply_tdis(struct smb_request *req)
5177 NTSTATUS status;
5178 connection_struct *conn = req->conn;
5179 struct smbXsrv_tcon *tcon;
5181 START_PROFILE(SMBtdis);
5183 if (!conn) {
5184 DEBUG(4,("Invalid connection in tdis\n"));
5185 reply_force_doserror(req, ERRSRV, ERRinvnid);
5186 END_PROFILE(SMBtdis);
5187 return;
5190 tcon = conn->tcon;
5191 req->conn = NULL;
5194 * TODO: cancel all outstanding requests on the tcon
5196 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
5197 if (!NT_STATUS_IS_OK(status)) {
5198 DEBUG(0, ("reply_tdis: "
5199 "smbXsrv_tcon_disconnect() failed: %s\n",
5200 nt_errstr(status)));
5202 * If we hit this case, there is something completely
5203 * wrong, so we better disconnect the transport connection.
5205 END_PROFILE(SMBtdis);
5206 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
5207 return;
5210 TALLOC_FREE(tcon);
5212 reply_outbuf(req, 0, 0);
5213 END_PROFILE(SMBtdis);
5214 return;
5217 /****************************************************************************
5218 Reply to a echo.
5219 conn POINTER CAN BE NULL HERE !
5220 ****************************************************************************/
5222 void reply_echo(struct smb_request *req)
5224 connection_struct *conn = req->conn;
5225 struct smb_perfcount_data local_pcd;
5226 struct smb_perfcount_data *cur_pcd;
5227 int smb_reverb;
5228 int seq_num;
5230 START_PROFILE(SMBecho);
5232 smb_init_perfcount_data(&local_pcd);
5234 if (req->wct < 1) {
5235 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5236 END_PROFILE(SMBecho);
5237 return;
5240 smb_reverb = SVAL(req->vwv+0, 0);
5242 reply_outbuf(req, 1, req->buflen);
5244 /* copy any incoming data back out */
5245 if (req->buflen > 0) {
5246 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5249 if (smb_reverb > 100) {
5250 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5251 smb_reverb = 100;
5254 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5256 /* this makes sure we catch the request pcd */
5257 if (seq_num == smb_reverb) {
5258 cur_pcd = &req->pcd;
5259 } else {
5260 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5261 cur_pcd = &local_pcd;
5264 SSVAL(req->outbuf,smb_vwv0,seq_num);
5266 show_msg((char *)req->outbuf);
5267 if (!srv_send_smb(req->sconn,
5268 (char *)req->outbuf,
5269 true, req->seqnum+1,
5270 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5271 cur_pcd))
5272 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5275 DEBUG(3,("echo %d times\n", smb_reverb));
5277 TALLOC_FREE(req->outbuf);
5279 END_PROFILE(SMBecho);
5280 return;
5283 /****************************************************************************
5284 Reply to a printopen.
5285 ****************************************************************************/
5287 void reply_printopen(struct smb_request *req)
5289 connection_struct *conn = req->conn;
5290 files_struct *fsp;
5291 NTSTATUS status;
5293 START_PROFILE(SMBsplopen);
5295 if (req->wct < 2) {
5296 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5297 END_PROFILE(SMBsplopen);
5298 return;
5301 if (!CAN_PRINT(conn)) {
5302 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5303 END_PROFILE(SMBsplopen);
5304 return;
5307 status = file_new(req, conn, &fsp);
5308 if(!NT_STATUS_IS_OK(status)) {
5309 reply_nterror(req, status);
5310 END_PROFILE(SMBsplopen);
5311 return;
5314 /* Open for exclusive use, write only. */
5315 status = print_spool_open(fsp, NULL, req->vuid);
5317 if (!NT_STATUS_IS_OK(status)) {
5318 file_free(req, fsp);
5319 reply_nterror(req, status);
5320 END_PROFILE(SMBsplopen);
5321 return;
5324 reply_outbuf(req, 1, 0);
5325 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5327 DEBUG(3,("openprint fd=%d %s\n",
5328 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5330 END_PROFILE(SMBsplopen);
5331 return;
5334 /****************************************************************************
5335 Reply to a printclose.
5336 ****************************************************************************/
5338 void reply_printclose(struct smb_request *req)
5340 connection_struct *conn = req->conn;
5341 files_struct *fsp;
5342 NTSTATUS status;
5344 START_PROFILE(SMBsplclose);
5346 if (req->wct < 1) {
5347 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5348 END_PROFILE(SMBsplclose);
5349 return;
5352 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5354 if (!check_fsp(conn, req, fsp)) {
5355 END_PROFILE(SMBsplclose);
5356 return;
5359 if (!CAN_PRINT(conn)) {
5360 reply_force_doserror(req, ERRSRV, ERRerror);
5361 END_PROFILE(SMBsplclose);
5362 return;
5365 DEBUG(3,("printclose fd=%d %s\n",
5366 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5368 status = close_file(req, fsp, NORMAL_CLOSE);
5370 if(!NT_STATUS_IS_OK(status)) {
5371 reply_nterror(req, status);
5372 END_PROFILE(SMBsplclose);
5373 return;
5376 reply_outbuf(req, 0, 0);
5378 END_PROFILE(SMBsplclose);
5379 return;
5382 /****************************************************************************
5383 Reply to a printqueue.
5384 ****************************************************************************/
5386 void reply_printqueue(struct smb_request *req)
5388 connection_struct *conn = req->conn;
5389 int max_count;
5390 int start_index;
5392 START_PROFILE(SMBsplretq);
5394 if (req->wct < 2) {
5395 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5396 END_PROFILE(SMBsplretq);
5397 return;
5400 max_count = SVAL(req->vwv+0, 0);
5401 start_index = SVAL(req->vwv+1, 0);
5403 /* we used to allow the client to get the cnum wrong, but that
5404 is really quite gross and only worked when there was only
5405 one printer - I think we should now only accept it if they
5406 get it right (tridge) */
5407 if (!CAN_PRINT(conn)) {
5408 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5409 END_PROFILE(SMBsplretq);
5410 return;
5413 reply_outbuf(req, 2, 3);
5414 SSVAL(req->outbuf,smb_vwv0,0);
5415 SSVAL(req->outbuf,smb_vwv1,0);
5416 SCVAL(smb_buf(req->outbuf),0,1);
5417 SSVAL(smb_buf(req->outbuf),1,0);
5419 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5420 start_index, max_count));
5423 TALLOC_CTX *mem_ctx = talloc_tos();
5424 NTSTATUS status;
5425 WERROR werr;
5426 const char *sharename = lp_servicename(mem_ctx, SNUM(conn));
5427 struct rpc_pipe_client *cli = NULL;
5428 struct dcerpc_binding_handle *b = NULL;
5429 struct policy_handle handle;
5430 struct spoolss_DevmodeContainer devmode_ctr;
5431 union spoolss_JobInfo *info;
5432 uint32_t count;
5433 uint32_t num_to_get;
5434 uint32_t first;
5435 uint32_t i;
5437 ZERO_STRUCT(handle);
5439 status = rpc_pipe_open_interface(conn,
5440 &ndr_table_spoolss.syntax_id,
5441 conn->session_info,
5442 conn->sconn->remote_address,
5443 conn->sconn->msg_ctx,
5444 &cli);
5445 if (!NT_STATUS_IS_OK(status)) {
5446 DEBUG(0, ("reply_printqueue: "
5447 "could not connect to spoolss: %s\n",
5448 nt_errstr(status)));
5449 reply_nterror(req, status);
5450 goto out;
5452 b = cli->binding_handle;
5454 ZERO_STRUCT(devmode_ctr);
5456 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5457 sharename,
5458 NULL, devmode_ctr,
5459 SEC_FLAG_MAXIMUM_ALLOWED,
5460 &handle,
5461 &werr);
5462 if (!NT_STATUS_IS_OK(status)) {
5463 reply_nterror(req, status);
5464 goto out;
5466 if (!W_ERROR_IS_OK(werr)) {
5467 reply_nterror(req, werror_to_ntstatus(werr));
5468 goto out;
5471 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5472 &handle,
5473 0, /* firstjob */
5474 0xff, /* numjobs */
5475 2, /* level */
5476 0, /* offered */
5477 &count,
5478 &info);
5479 if (!W_ERROR_IS_OK(werr)) {
5480 reply_nterror(req, werror_to_ntstatus(werr));
5481 goto out;
5484 if (max_count > 0) {
5485 first = start_index;
5486 } else {
5487 first = start_index + max_count + 1;
5490 if (first >= count) {
5491 num_to_get = first;
5492 } else {
5493 num_to_get = first + MIN(ABS(max_count), count - first);
5496 for (i = first; i < num_to_get; i++) {
5497 char blob[28];
5498 char *p = blob;
5499 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
5500 int qstatus;
5501 uint16_t qrapjobid = pjobid_to_rap(sharename,
5502 info[i].info2.job_id);
5504 if (info[i].info2.status == JOB_STATUS_PRINTING) {
5505 qstatus = 2;
5506 } else {
5507 qstatus = 3;
5510 srv_put_dos_date2(p, 0, qtime);
5511 SCVAL(p, 4, qstatus);
5512 SSVAL(p, 5, qrapjobid);
5513 SIVAL(p, 7, info[i].info2.size);
5514 SCVAL(p, 11, 0);
5515 srvstr_push(blob, req->flags2, p+12,
5516 info[i].info2.notify_name, 16, STR_ASCII);
5518 if (message_push_blob(
5519 &req->outbuf,
5520 data_blob_const(
5521 blob, sizeof(blob))) == -1) {
5522 reply_nterror(req, NT_STATUS_NO_MEMORY);
5523 goto out;
5527 if (count > 0) {
5528 SSVAL(req->outbuf,smb_vwv0,count);
5529 SSVAL(req->outbuf,smb_vwv1,
5530 (max_count>0?first+count:first-1));
5531 SCVAL(smb_buf(req->outbuf),0,1);
5532 SSVAL(smb_buf(req->outbuf),1,28*count);
5536 DEBUG(3, ("%u entries returned in queue\n",
5537 (unsigned)count));
5539 out:
5540 if (b && is_valid_policy_hnd(&handle)) {
5541 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5546 END_PROFILE(SMBsplretq);
5547 return;
5550 /****************************************************************************
5551 Reply to a printwrite.
5552 ****************************************************************************/
5554 void reply_printwrite(struct smb_request *req)
5556 connection_struct *conn = req->conn;
5557 int numtowrite;
5558 const char *data;
5559 files_struct *fsp;
5561 START_PROFILE(SMBsplwr);
5563 if (req->wct < 1) {
5564 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5565 END_PROFILE(SMBsplwr);
5566 return;
5569 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5571 if (!check_fsp(conn, req, fsp)) {
5572 END_PROFILE(SMBsplwr);
5573 return;
5576 if (!fsp->print_file) {
5577 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5578 END_PROFILE(SMBsplwr);
5579 return;
5582 if (!CHECK_WRITE(fsp)) {
5583 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5584 END_PROFILE(SMBsplwr);
5585 return;
5588 numtowrite = SVAL(req->buf, 1);
5590 if (req->buflen < numtowrite + 3) {
5591 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5592 END_PROFILE(SMBsplwr);
5593 return;
5596 data = (const char *)req->buf + 3;
5598 if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
5599 reply_nterror(req, map_nt_error_from_unix(errno));
5600 END_PROFILE(SMBsplwr);
5601 return;
5604 DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
5606 END_PROFILE(SMBsplwr);
5607 return;
5610 /****************************************************************************
5611 Reply to a mkdir.
5612 ****************************************************************************/
5614 void reply_mkdir(struct smb_request *req)
5616 connection_struct *conn = req->conn;
5617 struct smb_filename *smb_dname = NULL;
5618 char *directory = NULL;
5619 NTSTATUS status;
5620 TALLOC_CTX *ctx = talloc_tos();
5622 START_PROFILE(SMBmkdir);
5624 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5625 STR_TERMINATE, &status);
5626 if (!NT_STATUS_IS_OK(status)) {
5627 reply_nterror(req, status);
5628 goto out;
5631 status = filename_convert(ctx, conn,
5632 req->flags2 & FLAGS2_DFS_PATHNAMES,
5633 directory,
5635 NULL,
5636 &smb_dname);
5637 if (!NT_STATUS_IS_OK(status)) {
5638 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5639 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5640 ERRSRV, ERRbadpath);
5641 goto out;
5643 reply_nterror(req, status);
5644 goto out;
5647 status = create_directory(conn, req, smb_dname);
5649 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
5651 if (!NT_STATUS_IS_OK(status)) {
5653 if (!use_nt_status()
5654 && NT_STATUS_EQUAL(status,
5655 NT_STATUS_OBJECT_NAME_COLLISION)) {
5657 * Yes, in the DOS error code case we get a
5658 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
5659 * samba4 torture test.
5661 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
5664 reply_nterror(req, status);
5665 goto out;
5668 reply_outbuf(req, 0, 0);
5670 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
5671 out:
5672 TALLOC_FREE(smb_dname);
5673 END_PROFILE(SMBmkdir);
5674 return;
5677 /****************************************************************************
5678 Reply to a rmdir.
5679 ****************************************************************************/
5681 void reply_rmdir(struct smb_request *req)
5683 connection_struct *conn = req->conn;
5684 struct smb_filename *smb_dname = NULL;
5685 char *directory = NULL;
5686 NTSTATUS status;
5687 TALLOC_CTX *ctx = talloc_tos();
5688 files_struct *fsp = NULL;
5689 int info = 0;
5690 struct smbd_server_connection *sconn = req->sconn;
5692 START_PROFILE(SMBrmdir);
5694 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5695 STR_TERMINATE, &status);
5696 if (!NT_STATUS_IS_OK(status)) {
5697 reply_nterror(req, status);
5698 goto out;
5701 status = filename_convert(ctx, conn,
5702 req->flags2 & FLAGS2_DFS_PATHNAMES,
5703 directory,
5705 NULL,
5706 &smb_dname);
5707 if (!NT_STATUS_IS_OK(status)) {
5708 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5709 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5710 ERRSRV, ERRbadpath);
5711 goto out;
5713 reply_nterror(req, status);
5714 goto out;
5717 if (is_ntfs_stream_smb_fname(smb_dname)) {
5718 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
5719 goto out;
5722 status = SMB_VFS_CREATE_FILE(
5723 conn, /* conn */
5724 req, /* req */
5725 0, /* root_dir_fid */
5726 smb_dname, /* fname */
5727 DELETE_ACCESS, /* access_mask */
5728 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5729 FILE_SHARE_DELETE),
5730 FILE_OPEN, /* create_disposition*/
5731 FILE_DIRECTORY_FILE, /* create_options */
5732 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
5733 0, /* oplock_request */
5734 0, /* allocation_size */
5735 0, /* private_flags */
5736 NULL, /* sd */
5737 NULL, /* ea_list */
5738 &fsp, /* result */
5739 &info); /* pinfo */
5741 if (!NT_STATUS_IS_OK(status)) {
5742 if (open_was_deferred(req->sconn, req->mid)) {
5743 /* We have re-scheduled this call. */
5744 goto out;
5746 reply_nterror(req, status);
5747 goto out;
5750 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
5751 if (!NT_STATUS_IS_OK(status)) {
5752 close_file(req, fsp, ERROR_CLOSE);
5753 reply_nterror(req, status);
5754 goto out;
5757 if (!set_delete_on_close(fsp, true,
5758 conn->session_info->security_token,
5759 conn->session_info->unix_token)) {
5760 close_file(req, fsp, ERROR_CLOSE);
5761 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5762 goto out;
5765 status = close_file(req, fsp, NORMAL_CLOSE);
5766 if (!NT_STATUS_IS_OK(status)) {
5767 reply_nterror(req, status);
5768 } else {
5769 reply_outbuf(req, 0, 0);
5772 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
5774 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
5775 out:
5776 TALLOC_FREE(smb_dname);
5777 END_PROFILE(SMBrmdir);
5778 return;
5781 /*******************************************************************
5782 Resolve wildcards in a filename rename.
5783 ********************************************************************/
5785 static bool resolve_wildcards(TALLOC_CTX *ctx,
5786 const char *name1,
5787 const char *name2,
5788 char **pp_newname)
5790 char *name2_copy = NULL;
5791 char *root1 = NULL;
5792 char *root2 = NULL;
5793 char *ext1 = NULL;
5794 char *ext2 = NULL;
5795 char *p,*p2, *pname1, *pname2;
5797 name2_copy = talloc_strdup(ctx, name2);
5798 if (!name2_copy) {
5799 return False;
5802 pname1 = strrchr_m(name1,'/');
5803 pname2 = strrchr_m(name2_copy,'/');
5805 if (!pname1 || !pname2) {
5806 return False;
5809 /* Truncate the copy of name2 at the last '/' */
5810 *pname2 = '\0';
5812 /* Now go past the '/' */
5813 pname1++;
5814 pname2++;
5816 root1 = talloc_strdup(ctx, pname1);
5817 root2 = talloc_strdup(ctx, pname2);
5819 if (!root1 || !root2) {
5820 return False;
5823 p = strrchr_m(root1,'.');
5824 if (p) {
5825 *p = 0;
5826 ext1 = talloc_strdup(ctx, p+1);
5827 } else {
5828 ext1 = talloc_strdup(ctx, "");
5830 p = strrchr_m(root2,'.');
5831 if (p) {
5832 *p = 0;
5833 ext2 = talloc_strdup(ctx, p+1);
5834 } else {
5835 ext2 = talloc_strdup(ctx, "");
5838 if (!ext1 || !ext2) {
5839 return False;
5842 p = root1;
5843 p2 = root2;
5844 while (*p2) {
5845 if (*p2 == '?') {
5846 /* Hmmm. Should this be mb-aware ? */
5847 *p2 = *p;
5848 p2++;
5849 } else if (*p2 == '*') {
5850 *p2 = '\0';
5851 root2 = talloc_asprintf(ctx, "%s%s",
5852 root2,
5854 if (!root2) {
5855 return False;
5857 break;
5858 } else {
5859 p2++;
5861 if (*p) {
5862 p++;
5866 p = ext1;
5867 p2 = ext2;
5868 while (*p2) {
5869 if (*p2 == '?') {
5870 /* Hmmm. Should this be mb-aware ? */
5871 *p2 = *p;
5872 p2++;
5873 } else if (*p2 == '*') {
5874 *p2 = '\0';
5875 ext2 = talloc_asprintf(ctx, "%s%s",
5876 ext2,
5878 if (!ext2) {
5879 return False;
5881 break;
5882 } else {
5883 p2++;
5885 if (*p) {
5886 p++;
5890 if (*ext2) {
5891 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
5892 name2_copy,
5893 root2,
5894 ext2);
5895 } else {
5896 *pp_newname = talloc_asprintf(ctx, "%s/%s",
5897 name2_copy,
5898 root2);
5901 if (!*pp_newname) {
5902 return False;
5905 return True;
5908 /****************************************************************************
5909 Ensure open files have their names updated. Updated to notify other smbd's
5910 asynchronously.
5911 ****************************************************************************/
5913 static void rename_open_files(connection_struct *conn,
5914 struct share_mode_lock *lck,
5915 uint32_t orig_name_hash,
5916 const struct smb_filename *smb_fname_dst)
5918 files_struct *fsp;
5919 bool did_rename = False;
5920 NTSTATUS status;
5921 uint32_t new_name_hash = 0;
5923 for(fsp = file_find_di_first(conn->sconn, lck->data->id); fsp;
5924 fsp = file_find_di_next(fsp)) {
5925 /* fsp_name is a relative path under the fsp. To change this for other
5926 sharepaths we need to manipulate relative paths. */
5927 /* TODO - create the absolute path and manipulate the newname
5928 relative to the sharepath. */
5929 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
5930 continue;
5932 if (fsp->name_hash != orig_name_hash) {
5933 continue;
5935 DEBUG(10, ("rename_open_files: renaming file %s "
5936 "(file_id %s) from %s -> %s\n", fsp_fnum_dbg(fsp),
5937 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
5938 smb_fname_str_dbg(smb_fname_dst)));
5940 status = fsp_set_smb_fname(fsp, smb_fname_dst);
5941 if (NT_STATUS_IS_OK(status)) {
5942 did_rename = True;
5943 new_name_hash = fsp->name_hash;
5947 if (!did_rename) {
5948 DEBUG(10, ("rename_open_files: no open files on file_id %s "
5949 "for %s\n", file_id_string_tos(&lck->data->id),
5950 smb_fname_str_dbg(smb_fname_dst)));
5953 /* Send messages to all smbd's (not ourself) that the name has changed. */
5954 rename_share_filename(conn->sconn->msg_ctx, lck, conn->connectpath,
5955 orig_name_hash, new_name_hash,
5956 smb_fname_dst);
5960 /****************************************************************************
5961 We need to check if the source path is a parent directory of the destination
5962 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
5963 refuse the rename with a sharing violation. Under UNIX the above call can
5964 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
5965 probably need to check that the client is a Windows one before disallowing
5966 this as a UNIX client (one with UNIX extensions) can know the source is a
5967 symlink and make this decision intelligently. Found by an excellent bug
5968 report from <AndyLiebman@aol.com>.
5969 ****************************************************************************/
5971 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
5972 const struct smb_filename *smb_fname_dst)
5974 const char *psrc = smb_fname_src->base_name;
5975 const char *pdst = smb_fname_dst->base_name;
5976 size_t slen;
5978 if (psrc[0] == '.' && psrc[1] == '/') {
5979 psrc += 2;
5981 if (pdst[0] == '.' && pdst[1] == '/') {
5982 pdst += 2;
5984 if ((slen = strlen(psrc)) > strlen(pdst)) {
5985 return False;
5987 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
5991 * Do the notify calls from a rename
5994 static void notify_rename(connection_struct *conn, bool is_dir,
5995 const struct smb_filename *smb_fname_src,
5996 const struct smb_filename *smb_fname_dst)
5998 char *parent_dir_src = NULL;
5999 char *parent_dir_dst = NULL;
6000 uint32 mask;
6002 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
6003 : FILE_NOTIFY_CHANGE_FILE_NAME;
6005 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
6006 &parent_dir_src, NULL) ||
6007 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
6008 &parent_dir_dst, NULL)) {
6009 goto out;
6012 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
6013 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
6014 smb_fname_src->base_name);
6015 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
6016 smb_fname_dst->base_name);
6018 else {
6019 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
6020 smb_fname_src->base_name);
6021 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
6022 smb_fname_dst->base_name);
6025 /* this is a strange one. w2k3 gives an additional event for
6026 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
6027 files, but not directories */
6028 if (!is_dir) {
6029 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6030 FILE_NOTIFY_CHANGE_ATTRIBUTES
6031 |FILE_NOTIFY_CHANGE_CREATION,
6032 smb_fname_dst->base_name);
6034 out:
6035 TALLOC_FREE(parent_dir_src);
6036 TALLOC_FREE(parent_dir_dst);
6039 /****************************************************************************
6040 Returns an error if the parent directory for a filename is open in an
6041 incompatible way.
6042 ****************************************************************************/
6044 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
6045 const struct smb_filename *smb_fname_dst_in)
6047 char *parent_dir = NULL;
6048 struct smb_filename smb_fname_parent;
6049 struct file_id id;
6050 files_struct *fsp = NULL;
6051 int ret;
6053 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
6054 &parent_dir, NULL)) {
6055 return NT_STATUS_NO_MEMORY;
6057 ZERO_STRUCT(smb_fname_parent);
6058 smb_fname_parent.base_name = parent_dir;
6060 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
6061 if (ret == -1) {
6062 return map_nt_error_from_unix(errno);
6066 * We're only checking on this smbd here, mostly good
6067 * enough.. and will pass tests.
6070 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
6071 for (fsp = file_find_di_first(conn->sconn, id); fsp;
6072 fsp = file_find_di_next(fsp)) {
6073 if (fsp->access_mask & DELETE_ACCESS) {
6074 return NT_STATUS_SHARING_VIOLATION;
6077 return NT_STATUS_OK;
6080 /****************************************************************************
6081 Rename an open file - given an fsp.
6082 ****************************************************************************/
6084 NTSTATUS rename_internals_fsp(connection_struct *conn,
6085 files_struct *fsp,
6086 const struct smb_filename *smb_fname_dst_in,
6087 uint32 attrs,
6088 bool replace_if_exists)
6090 TALLOC_CTX *ctx = talloc_tos();
6091 struct smb_filename *smb_fname_dst = NULL;
6092 NTSTATUS status = NT_STATUS_OK;
6093 struct share_mode_lock *lck = NULL;
6094 bool dst_exists, old_is_stream, new_is_stream;
6096 status = check_name(conn, smb_fname_dst_in->base_name);
6097 if (!NT_STATUS_IS_OK(status)) {
6098 return status;
6101 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
6102 if (!NT_STATUS_IS_OK(status)) {
6103 return status;
6106 /* Make a copy of the dst smb_fname structs */
6108 status = copy_smb_filename(ctx, smb_fname_dst_in, &smb_fname_dst);
6109 if (!NT_STATUS_IS_OK(status)) {
6110 goto out;
6114 * Check for special case with case preserving and not
6115 * case sensitive. If the old last component differs from the original
6116 * last component only by case, then we should allow
6117 * the rename (user is trying to change the case of the
6118 * filename).
6120 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
6121 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6122 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
6123 char *last_slash;
6124 char *fname_dst_lcomp_base_mod = NULL;
6125 struct smb_filename *smb_fname_orig_lcomp = NULL;
6128 * Get the last component of the destination name.
6130 last_slash = strrchr_m(smb_fname_dst->base_name, '/');
6131 if (last_slash) {
6132 fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1);
6133 } else {
6134 fname_dst_lcomp_base_mod = talloc_strdup(ctx, smb_fname_dst->base_name);
6136 if (!fname_dst_lcomp_base_mod) {
6137 status = NT_STATUS_NO_MEMORY;
6138 goto out;
6142 * Create an smb_filename struct using the original last
6143 * component of the destination.
6145 status = create_synthetic_smb_fname_split(ctx,
6146 smb_fname_dst->original_lcomp, NULL,
6147 &smb_fname_orig_lcomp);
6148 if (!NT_STATUS_IS_OK(status)) {
6149 TALLOC_FREE(fname_dst_lcomp_base_mod);
6150 goto out;
6153 /* If the base names only differ by case, use original. */
6154 if(!strcsequal(fname_dst_lcomp_base_mod,
6155 smb_fname_orig_lcomp->base_name)) {
6156 char *tmp;
6158 * Replace the modified last component with the
6159 * original.
6161 if (last_slash) {
6162 *last_slash = '\0'; /* Truncate at the '/' */
6163 tmp = talloc_asprintf(smb_fname_dst,
6164 "%s/%s",
6165 smb_fname_dst->base_name,
6166 smb_fname_orig_lcomp->base_name);
6167 } else {
6168 tmp = talloc_asprintf(smb_fname_dst,
6169 "%s",
6170 smb_fname_orig_lcomp->base_name);
6172 if (tmp == NULL) {
6173 status = NT_STATUS_NO_MEMORY;
6174 TALLOC_FREE(fname_dst_lcomp_base_mod);
6175 TALLOC_FREE(smb_fname_orig_lcomp);
6176 goto out;
6178 TALLOC_FREE(smb_fname_dst->base_name);
6179 smb_fname_dst->base_name = tmp;
6182 /* If the stream_names only differ by case, use original. */
6183 if(!strcsequal(smb_fname_dst->stream_name,
6184 smb_fname_orig_lcomp->stream_name)) {
6185 char *tmp = NULL;
6186 /* Use the original stream. */
6187 tmp = talloc_strdup(smb_fname_dst,
6188 smb_fname_orig_lcomp->stream_name);
6189 if (tmp == NULL) {
6190 status = NT_STATUS_NO_MEMORY;
6191 TALLOC_FREE(fname_dst_lcomp_base_mod);
6192 TALLOC_FREE(smb_fname_orig_lcomp);
6193 goto out;
6195 TALLOC_FREE(smb_fname_dst->stream_name);
6196 smb_fname_dst->stream_name = tmp;
6198 TALLOC_FREE(fname_dst_lcomp_base_mod);
6199 TALLOC_FREE(smb_fname_orig_lcomp);
6203 * If the src and dest names are identical - including case,
6204 * don't do the rename, just return success.
6207 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6208 strcsequal(fsp->fsp_name->stream_name,
6209 smb_fname_dst->stream_name)) {
6210 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6211 "- returning success\n",
6212 smb_fname_str_dbg(smb_fname_dst)));
6213 status = NT_STATUS_OK;
6214 goto out;
6217 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6218 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6220 /* Return the correct error code if both names aren't streams. */
6221 if (!old_is_stream && new_is_stream) {
6222 status = NT_STATUS_OBJECT_NAME_INVALID;
6223 goto out;
6226 if (old_is_stream && !new_is_stream) {
6227 status = NT_STATUS_INVALID_PARAMETER;
6228 goto out;
6231 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6233 if(!replace_if_exists && dst_exists) {
6234 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6235 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6236 smb_fname_str_dbg(smb_fname_dst)));
6237 status = NT_STATUS_OBJECT_NAME_COLLISION;
6238 goto out;
6241 if (dst_exists) {
6242 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6243 &smb_fname_dst->st);
6244 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6245 fileid);
6246 /* The file can be open when renaming a stream */
6247 if (dst_fsp && !new_is_stream) {
6248 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6249 status = NT_STATUS_ACCESS_DENIED;
6250 goto out;
6254 /* Ensure we have a valid stat struct for the source. */
6255 status = vfs_stat_fsp(fsp);
6256 if (!NT_STATUS_IS_OK(status)) {
6257 goto out;
6260 status = can_rename(conn, fsp, attrs);
6262 if (!NT_STATUS_IS_OK(status)) {
6263 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6264 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6265 smb_fname_str_dbg(smb_fname_dst)));
6266 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6267 status = NT_STATUS_ACCESS_DENIED;
6268 goto out;
6271 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6272 status = NT_STATUS_ACCESS_DENIED;
6275 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
6278 * We have the file open ourselves, so not being able to get the
6279 * corresponding share mode lock is a fatal error.
6282 SMB_ASSERT(lck != NULL);
6284 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6285 uint32 create_options = fsp->fh->private_options;
6287 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6288 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6289 smb_fname_str_dbg(smb_fname_dst)));
6291 if (!lp_posix_pathnames() &&
6292 (lp_map_archive(SNUM(conn)) ||
6293 lp_store_dos_attributes(SNUM(conn)))) {
6294 /* We must set the archive bit on the newly
6295 renamed file. */
6296 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6297 uint32_t old_dosmode = dos_mode(conn,
6298 smb_fname_dst);
6299 file_set_dosmode(conn,
6300 smb_fname_dst,
6301 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6302 NULL,
6303 true);
6307 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6308 smb_fname_dst);
6310 rename_open_files(conn, lck, fsp->name_hash, smb_fname_dst);
6313 * A rename acts as a new file create w.r.t. allowing an initial delete
6314 * on close, probably because in Windows there is a new handle to the
6315 * new file. If initial delete on close was requested but not
6316 * originally set, we need to set it here. This is probably not 100% correct,
6317 * but will work for the CIFSFS client which in non-posix mode
6318 * depends on these semantics. JRA.
6321 if (create_options & FILE_DELETE_ON_CLOSE) {
6322 status = can_set_delete_on_close(fsp, 0);
6324 if (NT_STATUS_IS_OK(status)) {
6325 /* Note that here we set the *inital* delete on close flag,
6326 * not the regular one. The magic gets handled in close. */
6327 fsp->initial_delete_on_close = True;
6330 TALLOC_FREE(lck);
6331 status = NT_STATUS_OK;
6332 goto out;
6335 TALLOC_FREE(lck);
6337 if (errno == ENOTDIR || errno == EISDIR) {
6338 status = NT_STATUS_OBJECT_NAME_COLLISION;
6339 } else {
6340 status = map_nt_error_from_unix(errno);
6343 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6344 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6345 smb_fname_str_dbg(smb_fname_dst)));
6347 out:
6348 TALLOC_FREE(smb_fname_dst);
6350 return status;
6353 /****************************************************************************
6354 The guts of the rename command, split out so it may be called by the NT SMB
6355 code.
6356 ****************************************************************************/
6358 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6359 connection_struct *conn,
6360 struct smb_request *req,
6361 struct smb_filename *smb_fname_src,
6362 struct smb_filename *smb_fname_dst,
6363 uint32 attrs,
6364 bool replace_if_exists,
6365 bool src_has_wild,
6366 bool dest_has_wild,
6367 uint32_t access_mask)
6369 char *fname_src_dir = NULL;
6370 char *fname_src_mask = NULL;
6371 int count=0;
6372 NTSTATUS status = NT_STATUS_OK;
6373 struct smb_Dir *dir_hnd = NULL;
6374 const char *dname = NULL;
6375 char *talloced = NULL;
6376 long offset = 0;
6377 int create_options = 0;
6378 bool posix_pathnames = lp_posix_pathnames();
6381 * Split the old name into directory and last component
6382 * strings. Note that unix_convert may have stripped off a
6383 * leading ./ from both name and newname if the rename is
6384 * at the root of the share. We need to make sure either both
6385 * name and newname contain a / character or neither of them do
6386 * as this is checked in resolve_wildcards().
6389 /* Split up the directory from the filename/mask. */
6390 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6391 &fname_src_dir, &fname_src_mask);
6392 if (!NT_STATUS_IS_OK(status)) {
6393 status = NT_STATUS_NO_MEMORY;
6394 goto out;
6398 * We should only check the mangled cache
6399 * here if unix_convert failed. This means
6400 * that the path in 'mask' doesn't exist
6401 * on the file system and so we need to look
6402 * for a possible mangle. This patch from
6403 * Tine Smukavec <valentin.smukavec@hermes.si>.
6406 if (!VALID_STAT(smb_fname_src->st) &&
6407 mangle_is_mangled(fname_src_mask, conn->params)) {
6408 char *new_mask = NULL;
6409 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6410 conn->params);
6411 if (new_mask) {
6412 TALLOC_FREE(fname_src_mask);
6413 fname_src_mask = new_mask;
6417 if (!src_has_wild) {
6418 files_struct *fsp;
6421 * Only one file needs to be renamed. Append the mask back
6422 * onto the directory.
6424 TALLOC_FREE(smb_fname_src->base_name);
6425 if (ISDOT(fname_src_dir)) {
6426 /* Ensure we use canonical names on open. */
6427 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6428 "%s",
6429 fname_src_mask);
6430 } else {
6431 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6432 "%s/%s",
6433 fname_src_dir,
6434 fname_src_mask);
6436 if (!smb_fname_src->base_name) {
6437 status = NT_STATUS_NO_MEMORY;
6438 goto out;
6441 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6442 "case_preserve = %d, short case preserve = %d, "
6443 "directory = %s, newname = %s, "
6444 "last_component_dest = %s\n",
6445 conn->case_sensitive, conn->case_preserve,
6446 conn->short_case_preserve,
6447 smb_fname_str_dbg(smb_fname_src),
6448 smb_fname_str_dbg(smb_fname_dst),
6449 smb_fname_dst->original_lcomp));
6451 /* The dest name still may have wildcards. */
6452 if (dest_has_wild) {
6453 char *fname_dst_mod = NULL;
6454 if (!resolve_wildcards(smb_fname_dst,
6455 smb_fname_src->base_name,
6456 smb_fname_dst->base_name,
6457 &fname_dst_mod)) {
6458 DEBUG(6, ("rename_internals: resolve_wildcards "
6459 "%s %s failed\n",
6460 smb_fname_src->base_name,
6461 smb_fname_dst->base_name));
6462 status = NT_STATUS_NO_MEMORY;
6463 goto out;
6465 TALLOC_FREE(smb_fname_dst->base_name);
6466 smb_fname_dst->base_name = fname_dst_mod;
6469 ZERO_STRUCT(smb_fname_src->st);
6470 if (posix_pathnames) {
6471 SMB_VFS_LSTAT(conn, smb_fname_src);
6472 } else {
6473 SMB_VFS_STAT(conn, smb_fname_src);
6476 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6477 create_options |= FILE_DIRECTORY_FILE;
6480 status = SMB_VFS_CREATE_FILE(
6481 conn, /* conn */
6482 req, /* req */
6483 0, /* root_dir_fid */
6484 smb_fname_src, /* fname */
6485 access_mask, /* access_mask */
6486 (FILE_SHARE_READ | /* share_access */
6487 FILE_SHARE_WRITE),
6488 FILE_OPEN, /* create_disposition*/
6489 create_options, /* create_options */
6490 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6491 0, /* oplock_request */
6492 0, /* allocation_size */
6493 0, /* private_flags */
6494 NULL, /* sd */
6495 NULL, /* ea_list */
6496 &fsp, /* result */
6497 NULL); /* pinfo */
6499 if (!NT_STATUS_IS_OK(status)) {
6500 DEBUG(3, ("Could not open rename source %s: %s\n",
6501 smb_fname_str_dbg(smb_fname_src),
6502 nt_errstr(status)));
6503 goto out;
6506 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6507 attrs, replace_if_exists);
6509 close_file(req, fsp, NORMAL_CLOSE);
6511 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
6512 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
6513 smb_fname_str_dbg(smb_fname_dst)));
6515 goto out;
6519 * Wildcards - process each file that matches.
6521 if (strequal(fname_src_mask, "????????.???")) {
6522 TALLOC_FREE(fname_src_mask);
6523 fname_src_mask = talloc_strdup(ctx, "*");
6524 if (!fname_src_mask) {
6525 status = NT_STATUS_NO_MEMORY;
6526 goto out;
6530 status = check_name(conn, fname_src_dir);
6531 if (!NT_STATUS_IS_OK(status)) {
6532 goto out;
6535 dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask,
6536 attrs);
6537 if (dir_hnd == NULL) {
6538 status = map_nt_error_from_unix(errno);
6539 goto out;
6542 status = NT_STATUS_NO_SUCH_FILE;
6544 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
6545 * - gentest fix. JRA
6548 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
6549 &talloced))) {
6550 files_struct *fsp = NULL;
6551 char *destname = NULL;
6552 bool sysdir_entry = False;
6554 /* Quick check for "." and ".." */
6555 if (ISDOT(dname) || ISDOTDOT(dname)) {
6556 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
6557 sysdir_entry = True;
6558 } else {
6559 TALLOC_FREE(talloced);
6560 continue;
6564 if (!is_visible_file(conn, fname_src_dir, dname,
6565 &smb_fname_src->st, false)) {
6566 TALLOC_FREE(talloced);
6567 continue;
6570 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
6571 TALLOC_FREE(talloced);
6572 continue;
6575 if (sysdir_entry) {
6576 status = NT_STATUS_OBJECT_NAME_INVALID;
6577 break;
6580 TALLOC_FREE(smb_fname_src->base_name);
6581 if (ISDOT(fname_src_dir)) {
6582 /* Ensure we use canonical names on open. */
6583 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6584 "%s",
6585 dname);
6586 } else {
6587 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6588 "%s/%s",
6589 fname_src_dir,
6590 dname);
6592 if (!smb_fname_src->base_name) {
6593 status = NT_STATUS_NO_MEMORY;
6594 goto out;
6597 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6598 smb_fname_dst->base_name,
6599 &destname)) {
6600 DEBUG(6, ("resolve_wildcards %s %s failed\n",
6601 smb_fname_src->base_name, destname));
6602 TALLOC_FREE(talloced);
6603 continue;
6605 if (!destname) {
6606 status = NT_STATUS_NO_MEMORY;
6607 goto out;
6610 TALLOC_FREE(smb_fname_dst->base_name);
6611 smb_fname_dst->base_name = destname;
6613 ZERO_STRUCT(smb_fname_src->st);
6614 if (posix_pathnames) {
6615 SMB_VFS_LSTAT(conn, smb_fname_src);
6616 } else {
6617 SMB_VFS_STAT(conn, smb_fname_src);
6620 create_options = 0;
6622 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6623 create_options |= FILE_DIRECTORY_FILE;
6626 status = SMB_VFS_CREATE_FILE(
6627 conn, /* conn */
6628 req, /* req */
6629 0, /* root_dir_fid */
6630 smb_fname_src, /* fname */
6631 access_mask, /* access_mask */
6632 (FILE_SHARE_READ | /* share_access */
6633 FILE_SHARE_WRITE),
6634 FILE_OPEN, /* create_disposition*/
6635 create_options, /* create_options */
6636 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6637 0, /* oplock_request */
6638 0, /* allocation_size */
6639 0, /* private_flags */
6640 NULL, /* sd */
6641 NULL, /* ea_list */
6642 &fsp, /* result */
6643 NULL); /* pinfo */
6645 if (!NT_STATUS_IS_OK(status)) {
6646 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
6647 "returned %s rename %s -> %s\n",
6648 nt_errstr(status),
6649 smb_fname_str_dbg(smb_fname_src),
6650 smb_fname_str_dbg(smb_fname_dst)));
6651 break;
6654 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6655 dname);
6656 if (!smb_fname_dst->original_lcomp) {
6657 status = NT_STATUS_NO_MEMORY;
6658 goto out;
6661 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6662 attrs, replace_if_exists);
6664 close_file(req, fsp, NORMAL_CLOSE);
6666 if (!NT_STATUS_IS_OK(status)) {
6667 DEBUG(3, ("rename_internals_fsp returned %s for "
6668 "rename %s -> %s\n", nt_errstr(status),
6669 smb_fname_str_dbg(smb_fname_src),
6670 smb_fname_str_dbg(smb_fname_dst)));
6671 break;
6674 count++;
6676 DEBUG(3,("rename_internals: doing rename on %s -> "
6677 "%s\n", smb_fname_str_dbg(smb_fname_src),
6678 smb_fname_str_dbg(smb_fname_src)));
6679 TALLOC_FREE(talloced);
6681 TALLOC_FREE(dir_hnd);
6683 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
6684 status = map_nt_error_from_unix(errno);
6687 out:
6688 TALLOC_FREE(talloced);
6689 TALLOC_FREE(fname_src_dir);
6690 TALLOC_FREE(fname_src_mask);
6691 return status;
6694 /****************************************************************************
6695 Reply to a mv.
6696 ****************************************************************************/
6698 void reply_mv(struct smb_request *req)
6700 connection_struct *conn = req->conn;
6701 char *name = NULL;
6702 char *newname = NULL;
6703 const char *p;
6704 uint32 attrs;
6705 NTSTATUS status;
6706 bool src_has_wcard = False;
6707 bool dest_has_wcard = False;
6708 TALLOC_CTX *ctx = talloc_tos();
6709 struct smb_filename *smb_fname_src = NULL;
6710 struct smb_filename *smb_fname_dst = NULL;
6711 uint32_t src_ucf_flags = lp_posix_pathnames() ? UCF_UNIX_NAME_LOOKUP : UCF_COND_ALLOW_WCARD_LCOMP;
6712 uint32_t dst_ucf_flags = UCF_SAVE_LCOMP | (lp_posix_pathnames() ? 0 : UCF_COND_ALLOW_WCARD_LCOMP);
6713 bool stream_rename = false;
6715 START_PROFILE(SMBmv);
6717 if (req->wct < 1) {
6718 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6719 goto out;
6722 attrs = SVAL(req->vwv+0, 0);
6724 p = (const char *)req->buf + 1;
6725 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
6726 &status, &src_has_wcard);
6727 if (!NT_STATUS_IS_OK(status)) {
6728 reply_nterror(req, status);
6729 goto out;
6731 p++;
6732 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
6733 &status, &dest_has_wcard);
6734 if (!NT_STATUS_IS_OK(status)) {
6735 reply_nterror(req, status);
6736 goto out;
6739 if (!lp_posix_pathnames()) {
6740 /* The newname must begin with a ':' if the
6741 name contains a ':'. */
6742 if (strchr_m(name, ':')) {
6743 if (newname[0] != ':') {
6744 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6745 goto out;
6747 stream_rename = true;
6751 status = filename_convert(ctx,
6752 conn,
6753 req->flags2 & FLAGS2_DFS_PATHNAMES,
6754 name,
6755 src_ucf_flags,
6756 &src_has_wcard,
6757 &smb_fname_src);
6759 if (!NT_STATUS_IS_OK(status)) {
6760 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6761 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6762 ERRSRV, ERRbadpath);
6763 goto out;
6765 reply_nterror(req, status);
6766 goto out;
6769 status = filename_convert(ctx,
6770 conn,
6771 req->flags2 & FLAGS2_DFS_PATHNAMES,
6772 newname,
6773 dst_ucf_flags,
6774 &dest_has_wcard,
6775 &smb_fname_dst);
6777 if (!NT_STATUS_IS_OK(status)) {
6778 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6779 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6780 ERRSRV, ERRbadpath);
6781 goto out;
6783 reply_nterror(req, status);
6784 goto out;
6787 if (stream_rename) {
6788 /* smb_fname_dst->base_name must be the same as
6789 smb_fname_src->base_name. */
6790 TALLOC_FREE(smb_fname_dst->base_name);
6791 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
6792 smb_fname_src->base_name);
6793 if (!smb_fname_dst->base_name) {
6794 reply_nterror(req, NT_STATUS_NO_MEMORY);
6795 goto out;
6799 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
6800 smb_fname_str_dbg(smb_fname_dst)));
6802 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
6803 attrs, False, src_has_wcard, dest_has_wcard,
6804 DELETE_ACCESS);
6805 if (!NT_STATUS_IS_OK(status)) {
6806 if (open_was_deferred(req->sconn, req->mid)) {
6807 /* We have re-scheduled this call. */
6808 goto out;
6810 reply_nterror(req, status);
6811 goto out;
6814 reply_outbuf(req, 0, 0);
6815 out:
6816 TALLOC_FREE(smb_fname_src);
6817 TALLOC_FREE(smb_fname_dst);
6818 END_PROFILE(SMBmv);
6819 return;
6822 /*******************************************************************
6823 Copy a file as part of a reply_copy.
6824 ******************************************************************/
6827 * TODO: check error codes on all callers
6830 NTSTATUS copy_file(TALLOC_CTX *ctx,
6831 connection_struct *conn,
6832 struct smb_filename *smb_fname_src,
6833 struct smb_filename *smb_fname_dst,
6834 int ofun,
6835 int count,
6836 bool target_is_directory)
6838 struct smb_filename *smb_fname_dst_tmp = NULL;
6839 off_t ret=-1;
6840 files_struct *fsp1,*fsp2;
6841 uint32 dosattrs;
6842 uint32 new_create_disposition;
6843 NTSTATUS status;
6846 status = copy_smb_filename(ctx, smb_fname_dst, &smb_fname_dst_tmp);
6847 if (!NT_STATUS_IS_OK(status)) {
6848 return status;
6852 * If the target is a directory, extract the last component from the
6853 * src filename and append it to the dst filename
6855 if (target_is_directory) {
6856 const char *p;
6858 /* dest/target can't be a stream if it's a directory. */
6859 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
6861 p = strrchr_m(smb_fname_src->base_name,'/');
6862 if (p) {
6863 p++;
6864 } else {
6865 p = smb_fname_src->base_name;
6867 smb_fname_dst_tmp->base_name =
6868 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
6870 if (!smb_fname_dst_tmp->base_name) {
6871 status = NT_STATUS_NO_MEMORY;
6872 goto out;
6876 status = vfs_file_exist(conn, smb_fname_src);
6877 if (!NT_STATUS_IS_OK(status)) {
6878 goto out;
6881 if (!target_is_directory && count) {
6882 new_create_disposition = FILE_OPEN;
6883 } else {
6884 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
6885 0, ofun,
6886 NULL, NULL,
6887 &new_create_disposition,
6888 NULL,
6889 NULL)) {
6890 status = NT_STATUS_INVALID_PARAMETER;
6891 goto out;
6895 /* Open the src file for reading. */
6896 status = SMB_VFS_CREATE_FILE(
6897 conn, /* conn */
6898 NULL, /* req */
6899 0, /* root_dir_fid */
6900 smb_fname_src, /* fname */
6901 FILE_GENERIC_READ, /* access_mask */
6902 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6903 FILE_OPEN, /* create_disposition*/
6904 0, /* create_options */
6905 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
6906 INTERNAL_OPEN_ONLY, /* oplock_request */
6907 0, /* allocation_size */
6908 0, /* private_flags */
6909 NULL, /* sd */
6910 NULL, /* ea_list */
6911 &fsp1, /* result */
6912 NULL); /* psbuf */
6914 if (!NT_STATUS_IS_OK(status)) {
6915 goto out;
6918 dosattrs = dos_mode(conn, smb_fname_src);
6920 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
6921 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
6924 /* Open the dst file for writing. */
6925 status = SMB_VFS_CREATE_FILE(
6926 conn, /* conn */
6927 NULL, /* req */
6928 0, /* root_dir_fid */
6929 smb_fname_dst, /* fname */
6930 FILE_GENERIC_WRITE, /* access_mask */
6931 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6932 new_create_disposition, /* create_disposition*/
6933 0, /* create_options */
6934 dosattrs, /* file_attributes */
6935 INTERNAL_OPEN_ONLY, /* oplock_request */
6936 0, /* allocation_size */
6937 0, /* private_flags */
6938 NULL, /* sd */
6939 NULL, /* ea_list */
6940 &fsp2, /* result */
6941 NULL); /* psbuf */
6943 if (!NT_STATUS_IS_OK(status)) {
6944 close_file(NULL, fsp1, ERROR_CLOSE);
6945 goto out;
6948 if (ofun & OPENX_FILE_EXISTS_OPEN) {
6949 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
6950 if (ret == -1) {
6951 DEBUG(0, ("error - vfs lseek returned error %s\n",
6952 strerror(errno)));
6953 status = map_nt_error_from_unix(errno);
6954 close_file(NULL, fsp1, ERROR_CLOSE);
6955 close_file(NULL, fsp2, ERROR_CLOSE);
6956 goto out;
6960 /* Do the actual copy. */
6961 if (smb_fname_src->st.st_ex_size) {
6962 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
6963 } else {
6964 ret = 0;
6967 close_file(NULL, fsp1, NORMAL_CLOSE);
6969 /* Ensure the modtime is set correctly on the destination file. */
6970 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
6973 * As we are opening fsp1 read-only we only expect
6974 * an error on close on fsp2 if we are out of space.
6975 * Thus we don't look at the error return from the
6976 * close of fsp1.
6978 status = close_file(NULL, fsp2, NORMAL_CLOSE);
6980 if (!NT_STATUS_IS_OK(status)) {
6981 goto out;
6984 if (ret != (off_t)smb_fname_src->st.st_ex_size) {
6985 status = NT_STATUS_DISK_FULL;
6986 goto out;
6989 status = NT_STATUS_OK;
6991 out:
6992 TALLOC_FREE(smb_fname_dst_tmp);
6993 return status;
6996 /****************************************************************************
6997 Reply to a file copy.
6998 ****************************************************************************/
7000 void reply_copy(struct smb_request *req)
7002 connection_struct *conn = req->conn;
7003 struct smb_filename *smb_fname_src = NULL;
7004 struct smb_filename *smb_fname_dst = NULL;
7005 char *fname_src = NULL;
7006 char *fname_dst = NULL;
7007 char *fname_src_mask = NULL;
7008 char *fname_src_dir = NULL;
7009 const char *p;
7010 int count=0;
7011 int error = ERRnoaccess;
7012 int tid2;
7013 int ofun;
7014 int flags;
7015 bool target_is_directory=False;
7016 bool source_has_wild = False;
7017 bool dest_has_wild = False;
7018 NTSTATUS status;
7019 TALLOC_CTX *ctx = talloc_tos();
7021 START_PROFILE(SMBcopy);
7023 if (req->wct < 3) {
7024 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7025 goto out;
7028 tid2 = SVAL(req->vwv+0, 0);
7029 ofun = SVAL(req->vwv+1, 0);
7030 flags = SVAL(req->vwv+2, 0);
7032 p = (const char *)req->buf;
7033 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
7034 &status, &source_has_wild);
7035 if (!NT_STATUS_IS_OK(status)) {
7036 reply_nterror(req, status);
7037 goto out;
7039 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
7040 &status, &dest_has_wild);
7041 if (!NT_STATUS_IS_OK(status)) {
7042 reply_nterror(req, status);
7043 goto out;
7046 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
7048 if (tid2 != conn->cnum) {
7049 /* can't currently handle inter share copies XXXX */
7050 DEBUG(3,("Rejecting inter-share copy\n"));
7051 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
7052 goto out;
7055 status = filename_convert(ctx, conn,
7056 req->flags2 & FLAGS2_DFS_PATHNAMES,
7057 fname_src,
7058 UCF_COND_ALLOW_WCARD_LCOMP,
7059 &source_has_wild,
7060 &smb_fname_src);
7061 if (!NT_STATUS_IS_OK(status)) {
7062 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7063 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7064 ERRSRV, ERRbadpath);
7065 goto out;
7067 reply_nterror(req, status);
7068 goto out;
7071 status = filename_convert(ctx, conn,
7072 req->flags2 & FLAGS2_DFS_PATHNAMES,
7073 fname_dst,
7074 UCF_COND_ALLOW_WCARD_LCOMP,
7075 &dest_has_wild,
7076 &smb_fname_dst);
7077 if (!NT_STATUS_IS_OK(status)) {
7078 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7079 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7080 ERRSRV, ERRbadpath);
7081 goto out;
7083 reply_nterror(req, status);
7084 goto out;
7087 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
7089 if ((flags&1) && target_is_directory) {
7090 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
7091 goto out;
7094 if ((flags&2) && !target_is_directory) {
7095 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
7096 goto out;
7099 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
7100 /* wants a tree copy! XXXX */
7101 DEBUG(3,("Rejecting tree copy\n"));
7102 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7103 goto out;
7106 /* Split up the directory from the filename/mask. */
7107 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7108 &fname_src_dir, &fname_src_mask);
7109 if (!NT_STATUS_IS_OK(status)) {
7110 reply_nterror(req, NT_STATUS_NO_MEMORY);
7111 goto out;
7115 * We should only check the mangled cache
7116 * here if unix_convert failed. This means
7117 * that the path in 'mask' doesn't exist
7118 * on the file system and so we need to look
7119 * for a possible mangle. This patch from
7120 * Tine Smukavec <valentin.smukavec@hermes.si>.
7122 if (!VALID_STAT(smb_fname_src->st) &&
7123 mangle_is_mangled(fname_src_mask, conn->params)) {
7124 char *new_mask = NULL;
7125 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
7126 &new_mask, conn->params);
7128 /* Use demangled name if one was successfully found. */
7129 if (new_mask) {
7130 TALLOC_FREE(fname_src_mask);
7131 fname_src_mask = new_mask;
7135 if (!source_has_wild) {
7138 * Only one file needs to be copied. Append the mask back onto
7139 * the directory.
7141 TALLOC_FREE(smb_fname_src->base_name);
7142 if (ISDOT(fname_src_dir)) {
7143 /* Ensure we use canonical names on open. */
7144 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7145 "%s",
7146 fname_src_mask);
7147 } else {
7148 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7149 "%s/%s",
7150 fname_src_dir,
7151 fname_src_mask);
7153 if (!smb_fname_src->base_name) {
7154 reply_nterror(req, NT_STATUS_NO_MEMORY);
7155 goto out;
7158 if (dest_has_wild) {
7159 char *fname_dst_mod = NULL;
7160 if (!resolve_wildcards(smb_fname_dst,
7161 smb_fname_src->base_name,
7162 smb_fname_dst->base_name,
7163 &fname_dst_mod)) {
7164 reply_nterror(req, NT_STATUS_NO_MEMORY);
7165 goto out;
7167 TALLOC_FREE(smb_fname_dst->base_name);
7168 smb_fname_dst->base_name = fname_dst_mod;
7171 status = check_name(conn, smb_fname_src->base_name);
7172 if (!NT_STATUS_IS_OK(status)) {
7173 reply_nterror(req, status);
7174 goto out;
7177 status = check_name(conn, smb_fname_dst->base_name);
7178 if (!NT_STATUS_IS_OK(status)) {
7179 reply_nterror(req, status);
7180 goto out;
7183 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7184 ofun, count, target_is_directory);
7186 if(!NT_STATUS_IS_OK(status)) {
7187 reply_nterror(req, status);
7188 goto out;
7189 } else {
7190 count++;
7192 } else {
7193 struct smb_Dir *dir_hnd = NULL;
7194 const char *dname = NULL;
7195 char *talloced = NULL;
7196 long offset = 0;
7199 * There is a wildcard that requires us to actually read the
7200 * src dir and copy each file matching the mask to the dst.
7201 * Right now streams won't be copied, but this could
7202 * presumably be added with a nested loop for reach dir entry.
7204 SMB_ASSERT(!smb_fname_src->stream_name);
7205 SMB_ASSERT(!smb_fname_dst->stream_name);
7207 smb_fname_src->stream_name = NULL;
7208 smb_fname_dst->stream_name = NULL;
7210 if (strequal(fname_src_mask,"????????.???")) {
7211 TALLOC_FREE(fname_src_mask);
7212 fname_src_mask = talloc_strdup(ctx, "*");
7213 if (!fname_src_mask) {
7214 reply_nterror(req, NT_STATUS_NO_MEMORY);
7215 goto out;
7219 status = check_name(conn, fname_src_dir);
7220 if (!NT_STATUS_IS_OK(status)) {
7221 reply_nterror(req, status);
7222 goto out;
7225 dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0);
7226 if (dir_hnd == NULL) {
7227 status = map_nt_error_from_unix(errno);
7228 reply_nterror(req, status);
7229 goto out;
7232 error = ERRbadfile;
7234 /* Iterate over the src dir copying each entry to the dst. */
7235 while ((dname = ReadDirName(dir_hnd, &offset,
7236 &smb_fname_src->st, &talloced))) {
7237 char *destname = NULL;
7239 if (ISDOT(dname) || ISDOTDOT(dname)) {
7240 TALLOC_FREE(talloced);
7241 continue;
7244 if (!is_visible_file(conn, fname_src_dir, dname,
7245 &smb_fname_src->st, false)) {
7246 TALLOC_FREE(talloced);
7247 continue;
7250 if(!mask_match(dname, fname_src_mask,
7251 conn->case_sensitive)) {
7252 TALLOC_FREE(talloced);
7253 continue;
7256 error = ERRnoaccess;
7258 /* Get the src smb_fname struct setup. */
7259 TALLOC_FREE(smb_fname_src->base_name);
7260 if (ISDOT(fname_src_dir)) {
7261 /* Ensure we use canonical names on open. */
7262 smb_fname_src->base_name =
7263 talloc_asprintf(smb_fname_src, "%s",
7264 dname);
7265 } else {
7266 smb_fname_src->base_name =
7267 talloc_asprintf(smb_fname_src, "%s/%s",
7268 fname_src_dir, dname);
7271 if (!smb_fname_src->base_name) {
7272 TALLOC_FREE(dir_hnd);
7273 TALLOC_FREE(talloced);
7274 reply_nterror(req, NT_STATUS_NO_MEMORY);
7275 goto out;
7278 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7279 smb_fname_dst->base_name,
7280 &destname)) {
7281 TALLOC_FREE(talloced);
7282 continue;
7284 if (!destname) {
7285 TALLOC_FREE(dir_hnd);
7286 TALLOC_FREE(talloced);
7287 reply_nterror(req, NT_STATUS_NO_MEMORY);
7288 goto out;
7291 TALLOC_FREE(smb_fname_dst->base_name);
7292 smb_fname_dst->base_name = destname;
7294 status = check_name(conn, smb_fname_src->base_name);
7295 if (!NT_STATUS_IS_OK(status)) {
7296 TALLOC_FREE(dir_hnd);
7297 TALLOC_FREE(talloced);
7298 reply_nterror(req, status);
7299 goto out;
7302 status = check_name(conn, smb_fname_dst->base_name);
7303 if (!NT_STATUS_IS_OK(status)) {
7304 TALLOC_FREE(dir_hnd);
7305 TALLOC_FREE(talloced);
7306 reply_nterror(req, status);
7307 goto out;
7310 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7311 smb_fname_src->base_name,
7312 smb_fname_dst->base_name));
7314 status = copy_file(ctx, conn, smb_fname_src,
7315 smb_fname_dst, ofun, count,
7316 target_is_directory);
7317 if (NT_STATUS_IS_OK(status)) {
7318 count++;
7321 TALLOC_FREE(talloced);
7323 TALLOC_FREE(dir_hnd);
7326 if (count == 0) {
7327 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7328 goto out;
7331 reply_outbuf(req, 1, 0);
7332 SSVAL(req->outbuf,smb_vwv0,count);
7333 out:
7334 TALLOC_FREE(smb_fname_src);
7335 TALLOC_FREE(smb_fname_dst);
7336 TALLOC_FREE(fname_src);
7337 TALLOC_FREE(fname_dst);
7338 TALLOC_FREE(fname_src_mask);
7339 TALLOC_FREE(fname_src_dir);
7341 END_PROFILE(SMBcopy);
7342 return;
7345 #undef DBGC_CLASS
7346 #define DBGC_CLASS DBGC_LOCKING
7348 /****************************************************************************
7349 Get a lock pid, dealing with large count requests.
7350 ****************************************************************************/
7352 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7353 bool large_file_format)
7355 if(!large_file_format)
7356 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7357 else
7358 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7361 /****************************************************************************
7362 Get a lock count, dealing with large count requests.
7363 ****************************************************************************/
7365 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7366 bool large_file_format)
7368 uint64_t count = 0;
7370 if(!large_file_format) {
7371 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7372 } else {
7374 #if defined(HAVE_LONGLONG)
7375 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7376 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7377 #else /* HAVE_LONGLONG */
7380 * NT4.x seems to be broken in that it sends large file (64 bit)
7381 * lockingX calls even if the CAP_LARGE_FILES was *not*
7382 * negotiated. For boxes without large unsigned ints truncate the
7383 * lock count by dropping the top 32 bits.
7386 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
7387 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
7388 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
7389 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
7390 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
7393 count = (uint64_t)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
7394 #endif /* HAVE_LONGLONG */
7397 return count;
7400 #if !defined(HAVE_LONGLONG)
7401 /****************************************************************************
7402 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
7403 ****************************************************************************/
7405 static uint32 map_lock_offset(uint32 high, uint32 low)
7407 unsigned int i;
7408 uint32 mask = 0;
7409 uint32 highcopy = high;
7412 * Try and find out how many significant bits there are in high.
7415 for(i = 0; highcopy; i++)
7416 highcopy >>= 1;
7419 * We use 31 bits not 32 here as POSIX
7420 * lock offsets may not be negative.
7423 mask = (~0) << (31 - i);
7425 if(low & mask)
7426 return 0; /* Fail. */
7428 high <<= (31 - i);
7430 return (high|low);
7432 #endif /* !defined(HAVE_LONGLONG) */
7434 /****************************************************************************
7435 Get a lock offset, dealing with large offset requests.
7436 ****************************************************************************/
7438 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7439 bool large_file_format, bool *err)
7441 uint64_t offset = 0;
7443 *err = False;
7445 if(!large_file_format) {
7446 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7447 } else {
7449 #if defined(HAVE_LONGLONG)
7450 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7451 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7452 #else /* HAVE_LONGLONG */
7455 * NT4.x seems to be broken in that it sends large file (64 bit)
7456 * lockingX calls even if the CAP_LARGE_FILES was *not*
7457 * negotiated. For boxes without large unsigned ints mangle the
7458 * lock offset by mapping the top 32 bits onto the lower 32.
7461 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
7462 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7463 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
7464 uint32 new_low = 0;
7466 if((new_low = map_lock_offset(high, low)) == 0) {
7467 *err = True;
7468 return (uint64_t)-1;
7471 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
7472 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
7473 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
7474 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
7477 offset = (uint64_t)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7478 #endif /* HAVE_LONGLONG */
7481 return offset;
7484 NTSTATUS smbd_do_locking(struct smb_request *req,
7485 files_struct *fsp,
7486 uint8_t type,
7487 int32_t timeout,
7488 uint16_t num_ulocks,
7489 struct smbd_lock_element *ulocks,
7490 uint16_t num_locks,
7491 struct smbd_lock_element *locks,
7492 bool *async)
7494 connection_struct *conn = req->conn;
7495 int i;
7496 NTSTATUS status = NT_STATUS_OK;
7498 *async = false;
7500 /* Data now points at the beginning of the list
7501 of smb_unlkrng structs */
7502 for(i = 0; i < (int)num_ulocks; i++) {
7503 struct smbd_lock_element *e = &ulocks[i];
7505 DEBUG(10,("smbd_do_locking: unlock start=%.0f, len=%.0f for "
7506 "pid %u, file %s\n",
7507 (double)e->offset,
7508 (double)e->count,
7509 (unsigned int)e->smblctx,
7510 fsp_str_dbg(fsp)));
7512 if (e->brltype != UNLOCK_LOCK) {
7513 /* this can only happen with SMB2 */
7514 return NT_STATUS_INVALID_PARAMETER;
7517 status = do_unlock(req->sconn->msg_ctx,
7518 fsp,
7519 e->smblctx,
7520 e->count,
7521 e->offset,
7522 WINDOWS_LOCK);
7524 DEBUG(10, ("smbd_do_locking: unlock returned %s\n",
7525 nt_errstr(status)));
7527 if (!NT_STATUS_IS_OK(status)) {
7528 return status;
7532 /* Setup the timeout in seconds. */
7534 if (!lp_blocking_locks(SNUM(conn))) {
7535 timeout = 0;
7538 /* Data now points at the beginning of the list
7539 of smb_lkrng structs */
7541 for(i = 0; i < (int)num_locks; i++) {
7542 struct smbd_lock_element *e = &locks[i];
7544 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
7545 "%llu, file %s timeout = %d\n",
7546 (double)e->offset,
7547 (double)e->count,
7548 (unsigned long long)e->smblctx,
7549 fsp_str_dbg(fsp),
7550 (int)timeout));
7552 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7553 struct blocking_lock_record *blr = NULL;
7555 if (num_locks > 1) {
7557 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
7558 * if the lock vector contains one entry. When given mutliple cancel
7559 * requests in a single PDU we expect the server to return an
7560 * error. Windows servers seem to accept the request but only
7561 * cancel the first lock.
7562 * JRA - Do what Windows does (tm) :-).
7565 #if 0
7566 /* MS-CIFS (2.2.4.32.1) behavior. */
7567 return NT_STATUS_DOS(ERRDOS,
7568 ERRcancelviolation);
7569 #else
7570 /* Windows behavior. */
7571 if (i != 0) {
7572 DEBUG(10,("smbd_do_locking: ignoring subsequent "
7573 "cancel request\n"));
7574 continue;
7576 #endif
7579 if (lp_blocking_locks(SNUM(conn))) {
7581 /* Schedule a message to ourselves to
7582 remove the blocking lock record and
7583 return the right error. */
7585 blr = blocking_lock_cancel_smb1(fsp,
7586 e->smblctx,
7587 e->offset,
7588 e->count,
7589 WINDOWS_LOCK,
7590 type,
7591 NT_STATUS_FILE_LOCK_CONFLICT);
7592 if (blr == NULL) {
7593 return NT_STATUS_DOS(
7594 ERRDOS,
7595 ERRcancelviolation);
7598 /* Remove a matching pending lock. */
7599 status = do_lock_cancel(fsp,
7600 e->smblctx,
7601 e->count,
7602 e->offset,
7603 WINDOWS_LOCK,
7604 blr);
7605 } else {
7606 bool blocking_lock = timeout ? true : false;
7607 bool defer_lock = false;
7608 struct byte_range_lock *br_lck;
7609 uint64_t block_smblctx;
7611 br_lck = do_lock(req->sconn->msg_ctx,
7612 fsp,
7613 e->smblctx,
7614 e->count,
7615 e->offset,
7616 e->brltype,
7617 WINDOWS_LOCK,
7618 blocking_lock,
7619 &status,
7620 &block_smblctx,
7621 NULL);
7623 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
7624 /* Windows internal resolution for blocking locks seems
7625 to be about 200ms... Don't wait for less than that. JRA. */
7626 if (timeout != -1 && timeout < lp_lock_spin_time()) {
7627 timeout = lp_lock_spin_time();
7629 defer_lock = true;
7632 /* If a lock sent with timeout of zero would fail, and
7633 * this lock has been requested multiple times,
7634 * according to brl_lock_failed() we convert this
7635 * request to a blocking lock with a timeout of between
7636 * 150 - 300 milliseconds.
7638 * If lp_lock_spin_time() has been set to 0, we skip
7639 * this blocking retry and fail immediately.
7641 * Replacement for do_lock_spin(). JRA. */
7643 if (!req->sconn->using_smb2 &&
7644 br_lck && lp_blocking_locks(SNUM(conn)) &&
7645 lp_lock_spin_time() && !blocking_lock &&
7646 NT_STATUS_EQUAL((status),
7647 NT_STATUS_FILE_LOCK_CONFLICT))
7649 defer_lock = true;
7650 timeout = lp_lock_spin_time();
7653 if (br_lck && defer_lock) {
7655 * A blocking lock was requested. Package up
7656 * this smb into a queued request and push it
7657 * onto the blocking lock queue.
7659 if(push_blocking_lock_request(br_lck,
7660 req,
7661 fsp,
7662 timeout,
7664 e->smblctx,
7665 e->brltype,
7666 WINDOWS_LOCK,
7667 e->offset,
7668 e->count,
7669 block_smblctx)) {
7670 TALLOC_FREE(br_lck);
7671 *async = true;
7672 return NT_STATUS_OK;
7676 TALLOC_FREE(br_lck);
7679 if (!NT_STATUS_IS_OK(status)) {
7680 break;
7684 /* If any of the above locks failed, then we must unlock
7685 all of the previous locks (X/Open spec). */
7687 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
7689 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7690 i = -1; /* we want to skip the for loop */
7694 * Ensure we don't do a remove on the lock that just failed,
7695 * as under POSIX rules, if we have a lock already there, we
7696 * will delete it (and we shouldn't) .....
7698 for(i--; i >= 0; i--) {
7699 struct smbd_lock_element *e = &locks[i];
7701 do_unlock(req->sconn->msg_ctx,
7702 fsp,
7703 e->smblctx,
7704 e->count,
7705 e->offset,
7706 WINDOWS_LOCK);
7708 return status;
7711 DEBUG(3, ("smbd_do_locking: %s type=%d num_locks=%d num_ulocks=%d\n",
7712 fsp_fnum_dbg(fsp), (unsigned int)type, num_locks, num_ulocks));
7714 return NT_STATUS_OK;
7717 /****************************************************************************
7718 Reply to a lockingX request.
7719 ****************************************************************************/
7721 void reply_lockingX(struct smb_request *req)
7723 connection_struct *conn = req->conn;
7724 files_struct *fsp;
7725 unsigned char locktype;
7726 unsigned char oplocklevel;
7727 uint16 num_ulocks;
7728 uint16 num_locks;
7729 int32 lock_timeout;
7730 int i;
7731 const uint8_t *data;
7732 bool large_file_format;
7733 bool err;
7734 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
7735 struct smbd_lock_element *ulocks;
7736 struct smbd_lock_element *locks;
7737 bool async = false;
7739 START_PROFILE(SMBlockingX);
7741 if (req->wct < 8) {
7742 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7743 END_PROFILE(SMBlockingX);
7744 return;
7747 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
7748 locktype = CVAL(req->vwv+3, 0);
7749 oplocklevel = CVAL(req->vwv+3, 1);
7750 num_ulocks = SVAL(req->vwv+6, 0);
7751 num_locks = SVAL(req->vwv+7, 0);
7752 lock_timeout = IVAL(req->vwv+4, 0);
7753 large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
7755 if (!check_fsp(conn, req, fsp)) {
7756 END_PROFILE(SMBlockingX);
7757 return;
7760 data = req->buf;
7762 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
7763 /* we don't support these - and CANCEL_LOCK makes w2k
7764 and XP reboot so I don't really want to be
7765 compatible! (tridge) */
7766 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
7767 END_PROFILE(SMBlockingX);
7768 return;
7771 /* Check if this is an oplock break on a file
7772 we have granted an oplock on.
7774 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
7775 /* Client can insist on breaking to none. */
7776 bool break_to_none = (oplocklevel == 0);
7777 bool result;
7779 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
7780 "for %s\n", (unsigned int)oplocklevel,
7781 fsp_fnum_dbg(fsp)));
7784 * Make sure we have granted an exclusive or batch oplock on
7785 * this file.
7788 if (fsp->oplock_type == 0) {
7790 /* The Samba4 nbench simulator doesn't understand
7791 the difference between break to level2 and break
7792 to none from level2 - it sends oplock break
7793 replies in both cases. Don't keep logging an error
7794 message here - just ignore it. JRA. */
7796 DEBUG(5,("reply_lockingX: Error : oplock break from "
7797 "client for %s (oplock=%d) and no "
7798 "oplock granted on this file (%s).\n",
7799 fsp_fnum_dbg(fsp), fsp->oplock_type,
7800 fsp_str_dbg(fsp)));
7802 /* if this is a pure oplock break request then don't
7803 * send a reply */
7804 if (num_locks == 0 && num_ulocks == 0) {
7805 END_PROFILE(SMBlockingX);
7806 return;
7807 } else {
7808 END_PROFILE(SMBlockingX);
7809 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
7810 return;
7814 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
7815 (break_to_none)) {
7816 result = remove_oplock(fsp);
7817 } else {
7818 result = downgrade_oplock(fsp);
7821 if (!result) {
7822 DEBUG(0, ("reply_lockingX: error in removing "
7823 "oplock on file %s\n", fsp_str_dbg(fsp)));
7824 /* Hmmm. Is this panic justified? */
7825 smb_panic("internal tdb error");
7828 reply_to_oplock_break_requests(fsp);
7830 /* if this is a pure oplock break request then don't send a
7831 * reply */
7832 if (num_locks == 0 && num_ulocks == 0) {
7833 /* Sanity check - ensure a pure oplock break is not a
7834 chained request. */
7835 if(CVAL(req->vwv+0, 0) != 0xff)
7836 DEBUG(0,("reply_lockingX: Error : pure oplock "
7837 "break is a chained %d request !\n",
7838 (unsigned int)CVAL(req->vwv+0, 0)));
7839 END_PROFILE(SMBlockingX);
7840 return;
7844 if (req->buflen <
7845 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
7846 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7847 END_PROFILE(SMBlockingX);
7848 return;
7851 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
7852 if (ulocks == NULL) {
7853 reply_nterror(req, NT_STATUS_NO_MEMORY);
7854 END_PROFILE(SMBlockingX);
7855 return;
7858 locks = talloc_array(req, struct smbd_lock_element, num_locks);
7859 if (locks == NULL) {
7860 reply_nterror(req, NT_STATUS_NO_MEMORY);
7861 END_PROFILE(SMBlockingX);
7862 return;
7865 /* Data now points at the beginning of the list
7866 of smb_unlkrng structs */
7867 for(i = 0; i < (int)num_ulocks; i++) {
7868 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
7869 ulocks[i].count = get_lock_count(data, i, large_file_format);
7870 ulocks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7871 ulocks[i].brltype = UNLOCK_LOCK;
7874 * There is no error code marked "stupid client bug".... :-).
7876 if(err) {
7877 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7878 END_PROFILE(SMBlockingX);
7879 return;
7883 /* Now do any requested locks */
7884 data += ((large_file_format ? 20 : 10)*num_ulocks);
7886 /* Data now points at the beginning of the list
7887 of smb_lkrng structs */
7889 for(i = 0; i < (int)num_locks; i++) {
7890 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
7891 locks[i].count = get_lock_count(data, i, large_file_format);
7892 locks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7894 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
7895 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7896 locks[i].brltype = PENDING_READ_LOCK;
7897 } else {
7898 locks[i].brltype = READ_LOCK;
7900 } else {
7901 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7902 locks[i].brltype = PENDING_WRITE_LOCK;
7903 } else {
7904 locks[i].brltype = WRITE_LOCK;
7909 * There is no error code marked "stupid client bug".... :-).
7911 if(err) {
7912 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7913 END_PROFILE(SMBlockingX);
7914 return;
7918 status = smbd_do_locking(req, fsp,
7919 locktype, lock_timeout,
7920 num_ulocks, ulocks,
7921 num_locks, locks,
7922 &async);
7923 if (!NT_STATUS_IS_OK(status)) {
7924 END_PROFILE(SMBlockingX);
7925 reply_nterror(req, status);
7926 return;
7928 if (async) {
7929 END_PROFILE(SMBlockingX);
7930 return;
7933 reply_outbuf(req, 2, 0);
7934 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
7935 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
7937 DEBUG(3, ("lockingX %s type=%d num_locks=%d num_ulocks=%d\n",
7938 fsp_fnum_dbg(fsp), (unsigned int)locktype, num_locks, num_ulocks));
7940 END_PROFILE(SMBlockingX);
7943 #undef DBGC_CLASS
7944 #define DBGC_CLASS DBGC_ALL
7946 /****************************************************************************
7947 Reply to a SMBreadbmpx (read block multiplex) request.
7948 Always reply with an error, if someone has a platform really needs this,
7949 please contact vl@samba.org
7950 ****************************************************************************/
7952 void reply_readbmpx(struct smb_request *req)
7954 START_PROFILE(SMBreadBmpx);
7955 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7956 END_PROFILE(SMBreadBmpx);
7957 return;
7960 /****************************************************************************
7961 Reply to a SMBreadbs (read block multiplex secondary) request.
7962 Always reply with an error, if someone has a platform really needs this,
7963 please contact vl@samba.org
7964 ****************************************************************************/
7966 void reply_readbs(struct smb_request *req)
7968 START_PROFILE(SMBreadBs);
7969 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7970 END_PROFILE(SMBreadBs);
7971 return;
7974 /****************************************************************************
7975 Reply to a SMBsetattrE.
7976 ****************************************************************************/
7978 void reply_setattrE(struct smb_request *req)
7980 connection_struct *conn = req->conn;
7981 struct smb_file_time ft;
7982 files_struct *fsp;
7983 NTSTATUS status;
7985 START_PROFILE(SMBsetattrE);
7986 ZERO_STRUCT(ft);
7988 if (req->wct < 7) {
7989 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7990 goto out;
7993 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
7995 if(!fsp || (fsp->conn != conn)) {
7996 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
7997 goto out;
8001 * Convert the DOS times into unix times.
8004 ft.atime = convert_time_t_to_timespec(
8005 srv_make_unix_date2(req->vwv+3));
8006 ft.mtime = convert_time_t_to_timespec(
8007 srv_make_unix_date2(req->vwv+5));
8008 ft.create_time = convert_time_t_to_timespec(
8009 srv_make_unix_date2(req->vwv+1));
8011 reply_outbuf(req, 0, 0);
8014 * Patch from Ray Frush <frush@engr.colostate.edu>
8015 * Sometimes times are sent as zero - ignore them.
8018 /* Ensure we have a valid stat struct for the source. */
8019 status = vfs_stat_fsp(fsp);
8020 if (!NT_STATUS_IS_OK(status)) {
8021 reply_nterror(req, status);
8022 goto out;
8025 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
8026 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8027 goto out;
8030 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
8031 if (!NT_STATUS_IS_OK(status)) {
8032 reply_nterror(req, status);
8033 goto out;
8036 DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
8037 " createtime=%u\n",
8038 fsp_fnum_dbg(fsp),
8039 (unsigned int)ft.atime.tv_sec,
8040 (unsigned int)ft.mtime.tv_sec,
8041 (unsigned int)ft.create_time.tv_sec
8043 out:
8044 END_PROFILE(SMBsetattrE);
8045 return;
8049 /* Back from the dead for OS/2..... JRA. */
8051 /****************************************************************************
8052 Reply to a SMBwritebmpx (write block multiplex primary) request.
8053 Always reply with an error, if someone has a platform really needs this,
8054 please contact vl@samba.org
8055 ****************************************************************************/
8057 void reply_writebmpx(struct smb_request *req)
8059 START_PROFILE(SMBwriteBmpx);
8060 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8061 END_PROFILE(SMBwriteBmpx);
8062 return;
8065 /****************************************************************************
8066 Reply to a SMBwritebs (write block multiplex secondary) request.
8067 Always reply with an error, if someone has a platform really needs this,
8068 please contact vl@samba.org
8069 ****************************************************************************/
8071 void reply_writebs(struct smb_request *req)
8073 START_PROFILE(SMBwriteBs);
8074 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8075 END_PROFILE(SMBwriteBs);
8076 return;
8079 /****************************************************************************
8080 Reply to a SMBgetattrE.
8081 ****************************************************************************/
8083 void reply_getattrE(struct smb_request *req)
8085 connection_struct *conn = req->conn;
8086 int mode;
8087 files_struct *fsp;
8088 struct timespec create_ts;
8090 START_PROFILE(SMBgetattrE);
8092 if (req->wct < 1) {
8093 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8094 END_PROFILE(SMBgetattrE);
8095 return;
8098 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8100 if(!fsp || (fsp->conn != conn)) {
8101 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8102 END_PROFILE(SMBgetattrE);
8103 return;
8106 /* Do an fstat on this file */
8107 if(fsp_stat(fsp)) {
8108 reply_nterror(req, map_nt_error_from_unix(errno));
8109 END_PROFILE(SMBgetattrE);
8110 return;
8113 mode = dos_mode(conn, fsp->fsp_name);
8116 * Convert the times into dos times. Set create
8117 * date to be last modify date as UNIX doesn't save
8118 * this.
8121 reply_outbuf(req, 11, 0);
8123 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
8124 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
8125 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
8126 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
8127 /* Should we check pending modtime here ? JRA */
8128 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
8129 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
8131 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
8132 SIVAL(req->outbuf, smb_vwv6, 0);
8133 SIVAL(req->outbuf, smb_vwv8, 0);
8134 } else {
8135 uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8136 SIVAL(req->outbuf, smb_vwv6, (uint32)fsp->fsp_name->st.st_ex_size);
8137 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8139 SSVAL(req->outbuf,smb_vwv10, mode);
8141 DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp)));
8143 END_PROFILE(SMBgetattrE);
8144 return;