build: Make install_with_python.sh more portable
[Samba/gebeck_regimport.git] / source3 / smbd / reply.c
blobb511025d8035b3dd85ff64b2082282477398f96b
1 /*
2 Unix SMB/CIFS implementation.
3 Main SMB reply routines
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Andrew Bartlett 2001
6 Copyright (C) Jeremy Allison 1992-2007.
7 Copyright (C) Volker Lendecke 2007
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 This file handles most of the reply_ calls that the server
24 makes to handle specific protocols
27 #include "includes.h"
28 #include "system/filesys.h"
29 #include "printing.h"
30 #include "smbd/smbd.h"
31 #include "smbd/globals.h"
32 #include "fake_file.h"
33 #include "rpc_client/rpc_client.h"
34 #include "../librpc/gen_ndr/ndr_spoolss_c.h"
35 #include "../librpc/gen_ndr/open_files.h"
36 #include "rpc_client/cli_spoolss.h"
37 #include "rpc_client/init_spoolss.h"
38 #include "rpc_server/rpc_ncacn_np.h"
39 #include "libcli/security/security.h"
40 #include "libsmb/nmblib.h"
41 #include "auth.h"
42 #include "smbprofile.h"
43 #include "../lib/tsocket/tsocket.h"
44 #include "lib/tevent_wait.h"
45 #include "libcli/smb/smb_signing.h"
47 /****************************************************************************
48 Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
49 path or anything including wildcards.
50 We're assuming here that '/' is not the second byte in any multibyte char
51 set (a safe assumption). '\\' *may* be the second byte in a multibyte char
52 set.
53 ****************************************************************************/
55 /* Custom version for processing POSIX paths. */
56 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
58 static NTSTATUS check_path_syntax_internal(char *path,
59 bool posix_path,
60 bool *p_last_component_contains_wcard)
62 char *d = path;
63 const char *s = path;
64 NTSTATUS ret = NT_STATUS_OK;
65 bool start_of_name_component = True;
66 bool stream_started = false;
68 *p_last_component_contains_wcard = False;
70 while (*s) {
71 if (stream_started) {
72 switch (*s) {
73 case '/':
74 case '\\':
75 return NT_STATUS_OBJECT_NAME_INVALID;
76 case ':':
77 if (s[1] == '\0') {
78 return NT_STATUS_OBJECT_NAME_INVALID;
80 if (strchr_m(&s[1], ':')) {
81 return NT_STATUS_OBJECT_NAME_INVALID;
83 break;
87 if ((*s == ':') && !posix_path && !stream_started) {
88 if (*p_last_component_contains_wcard) {
89 return NT_STATUS_OBJECT_NAME_INVALID;
91 /* Stream names allow more characters than file names.
92 We're overloading posix_path here to allow a wider
93 range of characters. If stream_started is true this
94 is still a Windows path even if posix_path is true.
95 JRA.
97 stream_started = true;
98 start_of_name_component = false;
99 posix_path = true;
101 if (s[1] == '\0') {
102 return NT_STATUS_OBJECT_NAME_INVALID;
106 if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
108 * Safe to assume is not the second part of a mb char
109 * as this is handled below.
111 /* Eat multiple '/' or '\\' */
112 while (IS_PATH_SEP(*s,posix_path)) {
113 s++;
115 if ((d != path) && (*s != '\0')) {
116 /* We only care about non-leading or trailing '/' or '\\' */
117 *d++ = '/';
120 start_of_name_component = True;
121 /* New component. */
122 *p_last_component_contains_wcard = False;
123 continue;
126 if (start_of_name_component) {
127 if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
128 /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
131 * No mb char starts with '.' so we're safe checking the directory separator here.
134 /* If we just added a '/' - delete it */
135 if ((d > path) && (*(d-1) == '/')) {
136 *(d-1) = '\0';
137 d--;
140 /* Are we at the start ? Can't go back further if so. */
141 if (d <= path) {
142 ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
143 break;
145 /* Go back one level... */
146 /* We know this is safe as '/' cannot be part of a mb sequence. */
147 /* NOTE - if this assumption is invalid we are not in good shape... */
148 /* Decrement d first as d points to the *next* char to write into. */
149 for (d--; d > path; d--) {
150 if (*d == '/')
151 break;
153 s += 2; /* Else go past the .. */
154 /* We're still at the start of a name component, just the previous one. */
155 continue;
157 } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
158 if (posix_path) {
159 /* Eat the '.' */
160 s++;
161 continue;
167 if (!(*s & 0x80)) {
168 if (!posix_path) {
169 if (*s <= 0x1f || *s == '|') {
170 return NT_STATUS_OBJECT_NAME_INVALID;
172 switch (*s) {
173 case '*':
174 case '?':
175 case '<':
176 case '>':
177 case '"':
178 *p_last_component_contains_wcard = True;
179 break;
180 default:
181 break;
184 *d++ = *s++;
185 } else {
186 size_t siz;
187 /* Get the size of the next MB character. */
188 next_codepoint(s,&siz);
189 switch(siz) {
190 case 5:
191 *d++ = *s++;
192 /*fall through*/
193 case 4:
194 *d++ = *s++;
195 /*fall through*/
196 case 3:
197 *d++ = *s++;
198 /*fall through*/
199 case 2:
200 *d++ = *s++;
201 /*fall through*/
202 case 1:
203 *d++ = *s++;
204 break;
205 default:
206 DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
207 *d = '\0';
208 return NT_STATUS_INVALID_PARAMETER;
211 start_of_name_component = False;
214 *d = '\0';
216 return ret;
219 /****************************************************************************
220 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
221 No wildcards allowed.
222 ****************************************************************************/
224 NTSTATUS check_path_syntax(char *path)
226 bool ignore;
227 return check_path_syntax_internal(path, False, &ignore);
230 /****************************************************************************
231 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
232 Wildcards allowed - p_contains_wcard returns true if the last component contained
233 a wildcard.
234 ****************************************************************************/
236 NTSTATUS check_path_syntax_wcard(char *path, bool *p_contains_wcard)
238 return check_path_syntax_internal(path, False, p_contains_wcard);
241 /****************************************************************************
242 Check the path for a POSIX client.
243 We're assuming here that '/' is not the second byte in any multibyte char
244 set (a safe assumption).
245 ****************************************************************************/
247 NTSTATUS check_path_syntax_posix(char *path)
249 bool ignore;
250 return check_path_syntax_internal(path, True, &ignore);
253 /****************************************************************************
254 Pull a string and check the path allowing a wilcard - provide for error return.
255 ****************************************************************************/
257 size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
258 const char *base_ptr,
259 uint16 smb_flags2,
260 char **pp_dest,
261 const char *src,
262 size_t src_len,
263 int flags,
264 NTSTATUS *err,
265 bool *contains_wcard)
267 size_t ret;
269 *pp_dest = NULL;
271 ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
272 src_len, flags);
274 if (!*pp_dest) {
275 *err = NT_STATUS_INVALID_PARAMETER;
276 return ret;
279 *contains_wcard = False;
281 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
283 * For a DFS path the function parse_dfs_path()
284 * will do the path processing, just make a copy.
286 *err = NT_STATUS_OK;
287 return ret;
290 if (lp_posix_pathnames()) {
291 *err = check_path_syntax_posix(*pp_dest);
292 } else {
293 *err = check_path_syntax_wcard(*pp_dest, contains_wcard);
296 return ret;
299 /****************************************************************************
300 Pull a string and check the path - provide for error return.
301 ****************************************************************************/
303 size_t srvstr_get_path(TALLOC_CTX *ctx,
304 const char *base_ptr,
305 uint16 smb_flags2,
306 char **pp_dest,
307 const char *src,
308 size_t src_len,
309 int flags,
310 NTSTATUS *err)
312 bool ignore;
313 return srvstr_get_path_wcard(ctx, base_ptr, smb_flags2, pp_dest, src,
314 src_len, flags, err, &ignore);
317 size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req,
318 char **pp_dest, const char *src, int flags,
319 NTSTATUS *err, bool *contains_wcard)
321 return srvstr_get_path_wcard(mem_ctx, (const char *)req->inbuf, req->flags2,
322 pp_dest, src, smbreq_bufrem(req, src),
323 flags, err, contains_wcard);
326 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
327 char **pp_dest, const char *src, int flags,
328 NTSTATUS *err)
330 bool ignore;
331 return srvstr_get_path_req_wcard(mem_ctx, req, pp_dest, src,
332 flags, err, &ignore);
335 /****************************************************************************
336 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
337 ****************************************************************************/
339 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
340 files_struct *fsp)
342 if ((fsp == NULL) || (conn == NULL)) {
343 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
344 return False;
346 if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
347 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
348 return False;
350 return True;
353 /****************************************************************************
354 Check if we have a correct fsp pointing to a file.
355 ****************************************************************************/
357 bool check_fsp(connection_struct *conn, struct smb_request *req,
358 files_struct *fsp)
360 if (!check_fsp_open(conn, req, fsp)) {
361 return False;
363 if (fsp->is_directory) {
364 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
365 return False;
367 if (fsp->fh->fd == -1) {
368 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
369 return False;
371 fsp->num_smb_operations++;
372 return True;
375 /****************************************************************************
376 Check if we have a correct fsp pointing to a quota fake file. Replacement for
377 the CHECK_NTQUOTA_HANDLE_OK macro.
378 ****************************************************************************/
380 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
381 files_struct *fsp)
383 if (!check_fsp_open(conn, req, fsp)) {
384 return false;
387 if (fsp->is_directory) {
388 return false;
391 if (fsp->fake_file_handle == NULL) {
392 return false;
395 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
396 return false;
399 if (fsp->fake_file_handle->private_data == NULL) {
400 return false;
403 return true;
406 static bool netbios_session_retarget(struct smbd_server_connection *sconn,
407 const char *name, int name_type)
409 char *trim_name;
410 char *trim_name_type;
411 const char *retarget_parm;
412 char *retarget;
413 char *p;
414 int retarget_type = 0x20;
415 int retarget_port = NBT_SMB_PORT;
416 struct sockaddr_storage retarget_addr;
417 struct sockaddr_in *in_addr;
418 bool ret = false;
419 uint8_t outbuf[10];
421 if (get_socket_port(sconn->sock) != NBT_SMB_PORT) {
422 return false;
425 trim_name = talloc_strdup(talloc_tos(), name);
426 if (trim_name == NULL) {
427 goto fail;
429 trim_char(trim_name, ' ', ' ');
431 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
432 name_type);
433 if (trim_name_type == NULL) {
434 goto fail;
437 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
438 trim_name_type, NULL);
439 if (retarget_parm == NULL) {
440 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
441 trim_name, NULL);
443 if (retarget_parm == NULL) {
444 goto fail;
447 retarget = talloc_strdup(trim_name, retarget_parm);
448 if (retarget == NULL) {
449 goto fail;
452 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
454 p = strchr(retarget, ':');
455 if (p != NULL) {
456 *p++ = '\0';
457 retarget_port = atoi(p);
460 p = strchr_m(retarget, '#');
461 if (p != NULL) {
462 *p++ = '\0';
463 if (sscanf(p, "%x", &retarget_type) != 1) {
464 goto fail;
468 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
469 if (!ret) {
470 DEBUG(10, ("could not resolve %s\n", retarget));
471 goto fail;
474 if (retarget_addr.ss_family != AF_INET) {
475 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
476 goto fail;
479 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
481 _smb_setlen(outbuf, 6);
482 SCVAL(outbuf, 0, 0x84);
483 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
484 *(uint16_t *)(outbuf+8) = htons(retarget_port);
486 if (!srv_send_smb(sconn, (char *)outbuf, false, 0, false,
487 NULL)) {
488 exit_server_cleanly("netbios_session_retarget: srv_send_smb "
489 "failed.");
492 ret = true;
493 fail:
494 TALLOC_FREE(trim_name);
495 return ret;
498 static void reply_called_name_not_present(char *outbuf)
500 smb_setlen(outbuf, 1);
501 SCVAL(outbuf, 0, 0x83);
502 SCVAL(outbuf, 4, 0x82);
505 /****************************************************************************
506 Reply to a (netbios-level) special message.
507 ****************************************************************************/
509 void reply_special(struct smbd_server_connection *sconn, char *inbuf, size_t inbuf_size)
511 int msg_type = CVAL(inbuf,0);
512 int msg_flags = CVAL(inbuf,1);
514 * We only really use 4 bytes of the outbuf, but for the smb_setlen
515 * calculation & friends (srv_send_smb uses that) we need the full smb
516 * header.
518 char outbuf[smb_size];
520 memset(outbuf, '\0', sizeof(outbuf));
522 smb_setlen(outbuf,0);
524 switch (msg_type) {
525 case NBSSrequest: /* session request */
527 /* inbuf_size is guarenteed to be at least 4. */
528 fstring name1,name2;
529 int name_type1, name_type2;
530 int name_len1, name_len2;
532 *name1 = *name2 = 0;
534 if (sconn->nbt.got_session) {
535 exit_server_cleanly("multiple session request not permitted");
538 SCVAL(outbuf,0,NBSSpositive);
539 SCVAL(outbuf,3,0);
541 /* inbuf_size is guaranteed to be at least 4. */
542 name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
543 if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
544 DEBUG(0,("Invalid name length in session request\n"));
545 reply_called_name_not_present(outbuf);
546 break;
548 name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
549 if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
550 DEBUG(0,("Invalid name length in session request\n"));
551 reply_called_name_not_present(outbuf);
552 break;
555 name_type1 = name_extract((unsigned char *)inbuf,
556 inbuf_size,(unsigned int)4,name1);
557 name_type2 = name_extract((unsigned char *)inbuf,
558 inbuf_size,(unsigned int)(4 + name_len1),name2);
560 if (name_type1 == -1 || name_type2 == -1) {
561 DEBUG(0,("Invalid name type in session request\n"));
562 reply_called_name_not_present(outbuf);
563 break;
566 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
567 name1, name_type1, name2, name_type2));
569 if (netbios_session_retarget(sconn, name1, name_type1)) {
570 exit_server_cleanly("retargeted client");
574 * Windows NT/2k uses "*SMBSERVER" and XP uses
575 * "*SMBSERV" arrggg!!!
577 if (strequal(name1, "*SMBSERVER ")
578 || strequal(name1, "*SMBSERV ")) {
579 char *raddr;
581 raddr = tsocket_address_inet_addr_string(sconn->remote_address,
582 talloc_tos());
583 if (raddr == NULL) {
584 exit_server_cleanly("could not allocate raddr");
587 fstrcpy(name1, raddr);
590 set_local_machine_name(name1, True);
591 set_remote_machine_name(name2, True);
593 if (is_ipaddress(sconn->remote_hostname)) {
594 char *p = discard_const_p(char, sconn->remote_hostname);
596 talloc_free(p);
598 sconn->remote_hostname = talloc_strdup(sconn,
599 get_remote_machine_name());
600 if (sconn->remote_hostname == NULL) {
601 exit_server_cleanly("could not copy remote name");
603 sconn->conn->remote_hostname = sconn->remote_hostname;
606 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
607 get_local_machine_name(), get_remote_machine_name(),
608 name_type2));
610 if (name_type2 == 'R') {
611 /* We are being asked for a pathworks session ---
612 no thanks! */
613 reply_called_name_not_present(outbuf);
614 break;
617 reload_services(sconn, conn_snum_used, true);
618 reopen_logs();
620 sconn->nbt.got_session = true;
621 break;
624 case 0x89: /* session keepalive request
625 (some old clients produce this?) */
626 SCVAL(outbuf,0,NBSSkeepalive);
627 SCVAL(outbuf,3,0);
628 break;
630 case NBSSpositive: /* positive session response */
631 case NBSSnegative: /* negative session response */
632 case NBSSretarget: /* retarget session response */
633 DEBUG(0,("Unexpected session response\n"));
634 break;
636 case NBSSkeepalive: /* session keepalive */
637 default:
638 return;
641 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
642 msg_type, msg_flags));
644 srv_send_smb(sconn, outbuf, false, 0, false, NULL);
646 if (CVAL(outbuf, 0) != 0x82) {
647 exit_server_cleanly("invalid netbios session");
649 return;
652 /****************************************************************************
653 Reply to a tcon.
654 conn POINTER CAN BE NULL HERE !
655 ****************************************************************************/
657 void reply_tcon(struct smb_request *req)
659 connection_struct *conn = req->conn;
660 const char *service;
661 char *service_buf = NULL;
662 char *password = NULL;
663 char *dev = NULL;
664 int pwlen=0;
665 NTSTATUS nt_status;
666 const char *p;
667 TALLOC_CTX *ctx = talloc_tos();
668 struct smbd_server_connection *sconn = req->sconn;
669 NTTIME now = timeval_to_nttime(&req->request_time);
671 START_PROFILE(SMBtcon);
673 if (req->buflen < 4) {
674 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
675 END_PROFILE(SMBtcon);
676 return;
679 p = (const char *)req->buf + 1;
680 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
681 p += 1;
682 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
683 p += pwlen+1;
684 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
685 p += 1;
687 if (service_buf == NULL || password == NULL || dev == NULL) {
688 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
689 END_PROFILE(SMBtcon);
690 return;
692 p = strrchr_m(service_buf,'\\');
693 if (p) {
694 service = p+1;
695 } else {
696 service = service_buf;
699 conn = make_connection(sconn, now, service, dev,
700 req->vuid,&nt_status);
701 req->conn = conn;
703 if (!conn) {
704 reply_nterror(req, nt_status);
705 END_PROFILE(SMBtcon);
706 return;
709 reply_outbuf(req, 2, 0);
710 SSVAL(req->outbuf,smb_vwv0,sconn->smb1.negprot.max_recv);
711 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
712 SSVAL(req->outbuf,smb_tid,conn->cnum);
714 DEBUG(3,("tcon service=%s cnum=%d\n",
715 service, conn->cnum));
717 END_PROFILE(SMBtcon);
718 return;
721 /****************************************************************************
722 Reply to a tcon and X.
723 conn POINTER CAN BE NULL HERE !
724 ****************************************************************************/
726 void reply_tcon_and_X(struct smb_request *req)
728 connection_struct *conn = req->conn;
729 const char *service = NULL;
730 TALLOC_CTX *ctx = talloc_tos();
731 /* what the cleint thinks the device is */
732 char *client_devicetype = NULL;
733 /* what the server tells the client the share represents */
734 const char *server_devicetype;
735 NTSTATUS nt_status;
736 int passlen;
737 char *path = NULL;
738 const char *p, *q;
739 uint16_t tcon_flags;
740 struct smbXsrv_session *session = NULL;
741 NTTIME now = timeval_to_nttime(&req->request_time);
742 bool session_key_updated = false;
743 uint16_t optional_support = 0;
744 struct smbd_server_connection *sconn = req->sconn;
746 START_PROFILE(SMBtconX);
748 if (req->wct < 4) {
749 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
750 END_PROFILE(SMBtconX);
751 return;
754 passlen = SVAL(req->vwv+3, 0);
755 tcon_flags = SVAL(req->vwv+2, 0);
757 /* we might have to close an old one */
758 if ((tcon_flags & TCONX_FLAG_DISCONNECT_TID) && conn) {
759 struct smbXsrv_tcon *tcon;
760 NTSTATUS status;
762 tcon = conn->tcon;
763 req->conn = NULL;
764 conn = NULL;
767 * TODO: cancel all outstanding requests on the tcon
769 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
770 if (!NT_STATUS_IS_OK(status)) {
771 DEBUG(0, ("reply_tcon_and_X: "
772 "smbXsrv_tcon_disconnect() failed: %s\n",
773 nt_errstr(status)));
775 * If we hit this case, there is something completely
776 * wrong, so we better disconnect the transport connection.
778 END_PROFILE(SMBtconX);
779 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
780 return;
783 TALLOC_FREE(tcon);
786 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
787 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
788 END_PROFILE(SMBtconX);
789 return;
792 if (sconn->smb1.negprot.encrypted_passwords) {
793 p = (const char *)req->buf + passlen;
794 } else {
795 p = (const char *)req->buf + passlen + 1;
798 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
800 if (path == NULL) {
801 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
802 END_PROFILE(SMBtconX);
803 return;
807 * the service name can be either: \\server\share
808 * or share directly like on the DELL PowerVault 705
810 if (*path=='\\') {
811 q = strchr_m(path+2,'\\');
812 if (!q) {
813 reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
814 END_PROFILE(SMBtconX);
815 return;
817 service = q+1;
818 } else {
819 service = path;
822 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
823 &client_devicetype, p,
824 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
826 if (client_devicetype == NULL) {
827 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
828 END_PROFILE(SMBtconX);
829 return;
832 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
834 nt_status = smb1srv_session_lookup(req->sconn->conn,
835 req->vuid, now, &session);
836 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_USER_SESSION_DELETED)) {
837 reply_force_doserror(req, ERRSRV, ERRbaduid);
838 END_PROFILE(SMBtconX);
839 return;
841 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
842 reply_nterror(req, nt_status);
843 END_PROFILE(SMBtconX);
844 return;
846 if (!NT_STATUS_IS_OK(nt_status)) {
847 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
848 END_PROFILE(SMBtconX);
849 return;
852 if (session->global->auth_session_info == NULL) {
853 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
854 END_PROFILE(SMBtconX);
855 return;
859 * If there is no application key defined yet
860 * we create one.
862 * This means we setup the application key on the
863 * first tcon that happens via the given session.
865 * Once the application key is defined, it does not
866 * change any more.
868 if (session->global->application_key.length == 0 &&
869 session->global->signing_key.length > 0)
871 struct smbXsrv_session *x = session;
872 struct auth_session_info *session_info =
873 session->global->auth_session_info;
874 uint8_t session_key[16];
876 ZERO_STRUCT(session_key);
877 memcpy(session_key, x->global->signing_key.data,
878 MIN(x->global->signing_key.length, sizeof(session_key)));
881 * The application key is truncated/padded to 16 bytes
883 x->global->application_key = data_blob_talloc(x->global,
884 session_key,
885 sizeof(session_key));
886 ZERO_STRUCT(session_key);
887 if (x->global->application_key.data == NULL) {
888 reply_nterror(req, NT_STATUS_NO_MEMORY);
889 END_PROFILE(SMBtconX);
890 return;
893 if (tcon_flags & TCONX_FLAG_EXTENDED_SIGNATURES) {
894 smb_key_derivation(x->global->application_key.data,
895 x->global->application_key.length,
896 x->global->application_key.data);
897 optional_support |= SMB_EXTENDED_SIGNATURES;
901 * Place the application key into the session_info
903 data_blob_clear_free(&session_info->session_key);
904 session_info->session_key = data_blob_dup_talloc(session_info,
905 x->global->application_key);
906 if (session_info->session_key.data == NULL) {
907 data_blob_clear_free(&x->global->application_key);
908 reply_nterror(req, NT_STATUS_NO_MEMORY);
909 END_PROFILE(SMBtconX);
910 return;
912 session_key_updated = true;
915 conn = make_connection(sconn, now, service, client_devicetype,
916 req->vuid, &nt_status);
917 req->conn =conn;
919 if (!conn) {
920 if (session_key_updated) {
921 struct smbXsrv_session *x = session;
922 struct auth_session_info *session_info =
923 session->global->auth_session_info;
924 data_blob_clear_free(&x->global->application_key);
925 data_blob_clear_free(&session_info->session_key);
927 reply_nterror(req, nt_status);
928 END_PROFILE(SMBtconX);
929 return;
932 if ( IS_IPC(conn) )
933 server_devicetype = "IPC";
934 else if ( IS_PRINT(conn) )
935 server_devicetype = "LPT1:";
936 else
937 server_devicetype = "A:";
939 if (get_Protocol() < PROTOCOL_NT1) {
940 reply_outbuf(req, 2, 0);
941 if (message_push_string(&req->outbuf, server_devicetype,
942 STR_TERMINATE|STR_ASCII) == -1) {
943 reply_nterror(req, NT_STATUS_NO_MEMORY);
944 END_PROFILE(SMBtconX);
945 return;
947 } else {
948 /* NT sets the fstype of IPC$ to the null string */
949 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(ctx, SNUM(conn));
951 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
952 /* Return permissions. */
953 uint32 perm1 = 0;
954 uint32 perm2 = 0;
956 reply_outbuf(req, 7, 0);
958 if (IS_IPC(conn)) {
959 perm1 = FILE_ALL_ACCESS;
960 perm2 = FILE_ALL_ACCESS;
961 } else {
962 perm1 = conn->share_access;
965 SIVAL(req->outbuf, smb_vwv3, perm1);
966 SIVAL(req->outbuf, smb_vwv5, perm2);
967 } else {
968 reply_outbuf(req, 3, 0);
971 if ((message_push_string(&req->outbuf, server_devicetype,
972 STR_TERMINATE|STR_ASCII) == -1)
973 || (message_push_string(&req->outbuf, fstype,
974 STR_TERMINATE) == -1)) {
975 reply_nterror(req, NT_STATUS_NO_MEMORY);
976 END_PROFILE(SMBtconX);
977 return;
980 /* what does setting this bit do? It is set by NT4 and
981 may affect the ability to autorun mounted cdroms */
982 optional_support |= SMB_SUPPORT_SEARCH_BITS;
983 optional_support |=
984 (lp_csc_policy(SNUM(conn)) << SMB_CSC_POLICY_SHIFT);
986 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
987 DEBUG(2,("Serving %s as a Dfs root\n",
988 lp_servicename(ctx, SNUM(conn)) ));
989 optional_support |= SMB_SHARE_IN_DFS;
992 SSVAL(req->outbuf, smb_vwv2, optional_support);
995 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
996 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
998 DEBUG(3,("tconX service=%s \n",
999 service));
1001 /* set the incoming and outgoing tid to the just created one */
1002 SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
1003 SSVAL(req->outbuf,smb_tid,conn->cnum);
1005 END_PROFILE(SMBtconX);
1007 req->tid = conn->cnum;
1010 /****************************************************************************
1011 Reply to an unknown type.
1012 ****************************************************************************/
1014 void reply_unknown_new(struct smb_request *req, uint8 type)
1016 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
1017 smb_fn_name(type), type, type));
1018 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
1019 return;
1022 /****************************************************************************
1023 Reply to an ioctl.
1024 conn POINTER CAN BE NULL HERE !
1025 ****************************************************************************/
1027 void reply_ioctl(struct smb_request *req)
1029 connection_struct *conn = req->conn;
1030 uint16 device;
1031 uint16 function;
1032 uint32 ioctl_code;
1033 int replysize;
1034 char *p;
1036 START_PROFILE(SMBioctl);
1038 if (req->wct < 3) {
1039 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1040 END_PROFILE(SMBioctl);
1041 return;
1044 device = SVAL(req->vwv+1, 0);
1045 function = SVAL(req->vwv+2, 0);
1046 ioctl_code = (device << 16) + function;
1048 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
1050 switch (ioctl_code) {
1051 case IOCTL_QUERY_JOB_INFO:
1052 replysize = 32;
1053 break;
1054 default:
1055 reply_force_doserror(req, ERRSRV, ERRnosupport);
1056 END_PROFILE(SMBioctl);
1057 return;
1060 reply_outbuf(req, 8, replysize+1);
1061 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
1062 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
1063 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
1064 p = smb_buf(req->outbuf);
1065 memset(p, '\0', replysize+1); /* valgrind-safe. */
1066 p += 1; /* Allow for alignment */
1068 switch (ioctl_code) {
1069 case IOCTL_QUERY_JOB_INFO:
1071 files_struct *fsp = file_fsp(
1072 req, SVAL(req->vwv+0, 0));
1073 if (!fsp) {
1074 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
1075 END_PROFILE(SMBioctl);
1076 return;
1078 /* Job number */
1079 SSVAL(p, 0, print_spool_rap_jobid(fsp->print_file));
1081 srvstr_push((char *)req->outbuf, req->flags2, p+2,
1082 lp_netbios_name(), 15,
1083 STR_TERMINATE|STR_ASCII);
1084 if (conn) {
1085 srvstr_push((char *)req->outbuf, req->flags2,
1086 p+18,
1087 lp_servicename(talloc_tos(),
1088 SNUM(conn)),
1089 13, STR_TERMINATE|STR_ASCII);
1090 } else {
1091 memset(p+18, 0, 13);
1093 break;
1097 END_PROFILE(SMBioctl);
1098 return;
1101 /****************************************************************************
1102 Strange checkpath NTSTATUS mapping.
1103 ****************************************************************************/
1105 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
1107 /* Strange DOS error code semantics only for checkpath... */
1108 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
1109 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
1110 /* We need to map to ERRbadpath */
1111 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1114 return status;
1117 /****************************************************************************
1118 Reply to a checkpath.
1119 ****************************************************************************/
1121 void reply_checkpath(struct smb_request *req)
1123 connection_struct *conn = req->conn;
1124 struct smb_filename *smb_fname = NULL;
1125 char *name = NULL;
1126 NTSTATUS status;
1127 TALLOC_CTX *ctx = talloc_tos();
1129 START_PROFILE(SMBcheckpath);
1131 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
1132 STR_TERMINATE, &status);
1134 if (!NT_STATUS_IS_OK(status)) {
1135 status = map_checkpath_error(req->flags2, status);
1136 reply_nterror(req, status);
1137 END_PROFILE(SMBcheckpath);
1138 return;
1141 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1143 status = filename_convert(ctx,
1144 conn,
1145 req->flags2 & FLAGS2_DFS_PATHNAMES,
1146 name,
1148 NULL,
1149 &smb_fname);
1151 if (!NT_STATUS_IS_OK(status)) {
1152 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1153 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1154 ERRSRV, ERRbadpath);
1155 END_PROFILE(SMBcheckpath);
1156 return;
1158 goto path_err;
1161 if (!VALID_STAT(smb_fname->st) &&
1162 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1163 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1164 smb_fname_str_dbg(smb_fname), strerror(errno)));
1165 status = map_nt_error_from_unix(errno);
1166 goto path_err;
1169 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1170 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1171 ERRDOS, ERRbadpath);
1172 goto out;
1175 reply_outbuf(req, 0, 0);
1177 path_err:
1178 /* We special case this - as when a Windows machine
1179 is parsing a path is steps through the components
1180 one at a time - if a component fails it expects
1181 ERRbadpath, not ERRbadfile.
1183 status = map_checkpath_error(req->flags2, status);
1184 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1186 * Windows returns different error codes if
1187 * the parent directory is valid but not the
1188 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1189 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1190 * if the path is invalid.
1192 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1193 ERRDOS, ERRbadpath);
1194 goto out;
1197 reply_nterror(req, status);
1199 out:
1200 TALLOC_FREE(smb_fname);
1201 END_PROFILE(SMBcheckpath);
1202 return;
1205 /****************************************************************************
1206 Reply to a getatr.
1207 ****************************************************************************/
1209 void reply_getatr(struct smb_request *req)
1211 connection_struct *conn = req->conn;
1212 struct smb_filename *smb_fname = NULL;
1213 char *fname = NULL;
1214 int mode=0;
1215 off_t size=0;
1216 time_t mtime=0;
1217 const char *p;
1218 NTSTATUS status;
1219 TALLOC_CTX *ctx = talloc_tos();
1220 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1222 START_PROFILE(SMBgetatr);
1224 p = (const char *)req->buf + 1;
1225 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1226 if (!NT_STATUS_IS_OK(status)) {
1227 reply_nterror(req, status);
1228 goto out;
1231 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1232 under WfWg - weird! */
1233 if (*fname == '\0') {
1234 mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1235 if (!CAN_WRITE(conn)) {
1236 mode |= FILE_ATTRIBUTE_READONLY;
1238 size = 0;
1239 mtime = 0;
1240 } else {
1241 status = filename_convert(ctx,
1242 conn,
1243 req->flags2 & FLAGS2_DFS_PATHNAMES,
1244 fname,
1246 NULL,
1247 &smb_fname);
1248 if (!NT_STATUS_IS_OK(status)) {
1249 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1250 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1251 ERRSRV, ERRbadpath);
1252 goto out;
1254 reply_nterror(req, status);
1255 goto out;
1257 if (!VALID_STAT(smb_fname->st) &&
1258 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1259 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1260 smb_fname_str_dbg(smb_fname),
1261 strerror(errno)));
1262 reply_nterror(req, map_nt_error_from_unix(errno));
1263 goto out;
1266 mode = dos_mode(conn, smb_fname);
1267 size = smb_fname->st.st_ex_size;
1269 if (ask_sharemode) {
1270 struct timespec write_time_ts;
1271 struct file_id fileid;
1273 ZERO_STRUCT(write_time_ts);
1274 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1275 get_file_infos(fileid, 0, NULL, &write_time_ts);
1276 if (!null_timespec(write_time_ts)) {
1277 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1281 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1282 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1283 size = 0;
1287 reply_outbuf(req, 10, 0);
1289 SSVAL(req->outbuf,smb_vwv0,mode);
1290 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1291 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1292 } else {
1293 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1295 SIVAL(req->outbuf,smb_vwv3,(uint32)size);
1297 if (get_Protocol() >= PROTOCOL_NT1) {
1298 SSVAL(req->outbuf, smb_flg2,
1299 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1302 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1303 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1305 out:
1306 TALLOC_FREE(smb_fname);
1307 TALLOC_FREE(fname);
1308 END_PROFILE(SMBgetatr);
1309 return;
1312 /****************************************************************************
1313 Reply to a setatr.
1314 ****************************************************************************/
1316 void reply_setatr(struct smb_request *req)
1318 struct smb_file_time ft;
1319 connection_struct *conn = req->conn;
1320 struct smb_filename *smb_fname = NULL;
1321 char *fname = NULL;
1322 int mode;
1323 time_t mtime;
1324 const char *p;
1325 NTSTATUS status;
1326 TALLOC_CTX *ctx = talloc_tos();
1328 START_PROFILE(SMBsetatr);
1330 ZERO_STRUCT(ft);
1332 if (req->wct < 2) {
1333 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1334 goto out;
1337 p = (const char *)req->buf + 1;
1338 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1339 if (!NT_STATUS_IS_OK(status)) {
1340 reply_nterror(req, status);
1341 goto out;
1344 status = filename_convert(ctx,
1345 conn,
1346 req->flags2 & FLAGS2_DFS_PATHNAMES,
1347 fname,
1349 NULL,
1350 &smb_fname);
1351 if (!NT_STATUS_IS_OK(status)) {
1352 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1353 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1354 ERRSRV, ERRbadpath);
1355 goto out;
1357 reply_nterror(req, status);
1358 goto out;
1361 if (smb_fname->base_name[0] == '.' &&
1362 smb_fname->base_name[1] == '\0') {
1364 * Not sure here is the right place to catch this
1365 * condition. Might be moved to somewhere else later -- vl
1367 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1368 goto out;
1371 mode = SVAL(req->vwv+0, 0);
1372 mtime = srv_make_unix_date3(req->vwv+1);
1374 if (mode != FILE_ATTRIBUTE_NORMAL) {
1375 if (VALID_STAT_OF_DIR(smb_fname->st))
1376 mode |= FILE_ATTRIBUTE_DIRECTORY;
1377 else
1378 mode &= ~FILE_ATTRIBUTE_DIRECTORY;
1380 status = check_access(conn, NULL, smb_fname,
1381 FILE_WRITE_ATTRIBUTES);
1382 if (!NT_STATUS_IS_OK(status)) {
1383 reply_nterror(req, status);
1384 goto out;
1387 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1388 false) != 0) {
1389 reply_nterror(req, map_nt_error_from_unix(errno));
1390 goto out;
1394 ft.mtime = convert_time_t_to_timespec(mtime);
1395 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1396 if (!NT_STATUS_IS_OK(status)) {
1397 reply_nterror(req, status);
1398 goto out;
1401 reply_outbuf(req, 0, 0);
1403 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1404 mode));
1405 out:
1406 TALLOC_FREE(smb_fname);
1407 END_PROFILE(SMBsetatr);
1408 return;
1411 /****************************************************************************
1412 Reply to a dskattr.
1413 ****************************************************************************/
1415 void reply_dskattr(struct smb_request *req)
1417 connection_struct *conn = req->conn;
1418 uint64_t dfree,dsize,bsize;
1419 START_PROFILE(SMBdskattr);
1421 if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (uint64_t)-1) {
1422 reply_nterror(req, map_nt_error_from_unix(errno));
1423 END_PROFILE(SMBdskattr);
1424 return;
1427 reply_outbuf(req, 5, 0);
1429 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1430 double total_space, free_space;
1431 /* we need to scale this to a number that DOS6 can handle. We
1432 use floating point so we can handle large drives on systems
1433 that don't have 64 bit integers
1435 we end up displaying a maximum of 2G to DOS systems
1437 total_space = dsize * (double)bsize;
1438 free_space = dfree * (double)bsize;
1440 dsize = (uint64_t)((total_space+63*512) / (64*512));
1441 dfree = (uint64_t)((free_space+63*512) / (64*512));
1443 if (dsize > 0xFFFF) dsize = 0xFFFF;
1444 if (dfree > 0xFFFF) dfree = 0xFFFF;
1446 SSVAL(req->outbuf,smb_vwv0,dsize);
1447 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1448 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1449 SSVAL(req->outbuf,smb_vwv3,dfree);
1450 } else {
1451 SSVAL(req->outbuf,smb_vwv0,dsize);
1452 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1453 SSVAL(req->outbuf,smb_vwv2,512);
1454 SSVAL(req->outbuf,smb_vwv3,dfree);
1457 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1459 END_PROFILE(SMBdskattr);
1460 return;
1464 * Utility function to split the filename from the directory.
1466 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1467 char **fname_dir_out,
1468 char **fname_mask_out)
1470 const char *p = NULL;
1471 char *fname_dir = NULL;
1472 char *fname_mask = NULL;
1474 p = strrchr_m(fname_in, '/');
1475 if (!p) {
1476 fname_dir = talloc_strdup(ctx, ".");
1477 fname_mask = talloc_strdup(ctx, fname_in);
1478 } else {
1479 fname_dir = talloc_strndup(ctx, fname_in,
1480 PTR_DIFF(p, fname_in));
1481 fname_mask = talloc_strdup(ctx, p+1);
1484 if (!fname_dir || !fname_mask) {
1485 TALLOC_FREE(fname_dir);
1486 TALLOC_FREE(fname_mask);
1487 return NT_STATUS_NO_MEMORY;
1490 *fname_dir_out = fname_dir;
1491 *fname_mask_out = fname_mask;
1492 return NT_STATUS_OK;
1495 /****************************************************************************
1496 Reply to a search.
1497 Can be called from SMBsearch, SMBffirst or SMBfunique.
1498 ****************************************************************************/
1500 void reply_search(struct smb_request *req)
1502 connection_struct *conn = req->conn;
1503 char *path = NULL;
1504 const char *mask = NULL;
1505 char *directory = NULL;
1506 struct smb_filename *smb_fname = NULL;
1507 char *fname = NULL;
1508 off_t size;
1509 uint32 mode;
1510 struct timespec date;
1511 uint32 dirtype;
1512 unsigned int numentries = 0;
1513 unsigned int maxentries = 0;
1514 bool finished = False;
1515 const char *p;
1516 int status_len;
1517 char status[21];
1518 int dptr_num= -1;
1519 bool check_descend = False;
1520 bool expect_close = False;
1521 NTSTATUS nt_status;
1522 bool mask_contains_wcard = False;
1523 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1524 TALLOC_CTX *ctx = talloc_tos();
1525 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1526 struct dptr_struct *dirptr = NULL;
1527 struct smbd_server_connection *sconn = req->sconn;
1529 START_PROFILE(SMBsearch);
1531 if (req->wct < 2) {
1532 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1533 goto out;
1536 if (lp_posix_pathnames()) {
1537 reply_unknown_new(req, req->cmd);
1538 goto out;
1541 /* If we were called as SMBffirst then we must expect close. */
1542 if(req->cmd == SMBffirst) {
1543 expect_close = True;
1546 reply_outbuf(req, 1, 3);
1547 maxentries = SVAL(req->vwv+0, 0);
1548 dirtype = SVAL(req->vwv+1, 0);
1549 p = (const char *)req->buf + 1;
1550 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1551 &nt_status, &mask_contains_wcard);
1552 if (!NT_STATUS_IS_OK(nt_status)) {
1553 reply_nterror(req, nt_status);
1554 goto out;
1557 p++;
1558 status_len = SVAL(p, 0);
1559 p += 2;
1561 /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1563 if (status_len == 0) {
1564 nt_status = filename_convert(ctx, conn,
1565 req->flags2 & FLAGS2_DFS_PATHNAMES,
1566 path,
1567 UCF_ALWAYS_ALLOW_WCARD_LCOMP,
1568 &mask_contains_wcard,
1569 &smb_fname);
1570 if (!NT_STATUS_IS_OK(nt_status)) {
1571 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1572 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1573 ERRSRV, ERRbadpath);
1574 goto out;
1576 reply_nterror(req, nt_status);
1577 goto out;
1580 directory = smb_fname->base_name;
1582 p = strrchr_m(directory,'/');
1583 if ((p != NULL) && (*directory != '/')) {
1584 mask = p + 1;
1585 directory = talloc_strndup(ctx, directory,
1586 PTR_DIFF(p, directory));
1587 } else {
1588 mask = directory;
1589 directory = talloc_strdup(ctx,".");
1592 if (!directory) {
1593 reply_nterror(req, NT_STATUS_NO_MEMORY);
1594 goto out;
1597 memset((char *)status,'\0',21);
1598 SCVAL(status,0,(dirtype & 0x1F));
1600 nt_status = dptr_create(conn,
1601 NULL, /* req */
1602 NULL, /* fsp */
1603 directory,
1604 True,
1605 expect_close,
1606 req->smbpid,
1607 mask,
1608 mask_contains_wcard,
1609 dirtype,
1610 &dirptr);
1611 if (!NT_STATUS_IS_OK(nt_status)) {
1612 reply_nterror(req, nt_status);
1613 goto out;
1615 dptr_num = dptr_dnum(dirptr);
1616 } else {
1617 int status_dirtype;
1618 const char *dirpath;
1620 memcpy(status,p,21);
1621 status_dirtype = CVAL(status,0) & 0x1F;
1622 if (status_dirtype != (dirtype & 0x1F)) {
1623 dirtype = status_dirtype;
1626 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1627 if (!dirptr) {
1628 goto SearchEmpty;
1630 dirpath = dptr_path(sconn, dptr_num);
1631 directory = talloc_strdup(ctx, dirpath);
1632 if (!directory) {
1633 reply_nterror(req, NT_STATUS_NO_MEMORY);
1634 goto out;
1637 mask = dptr_wcard(sconn, dptr_num);
1638 if (!mask) {
1639 goto SearchEmpty;
1642 * For a 'continue' search we have no string. So
1643 * check from the initial saved string.
1645 mask_contains_wcard = ms_has_wild(mask);
1646 dirtype = dptr_attr(sconn, dptr_num);
1649 DEBUG(4,("dptr_num is %d\n",dptr_num));
1651 /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
1652 dptr_init_search_op(dirptr);
1654 if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1655 char buf[DIR_STRUCT_SIZE];
1656 memcpy(buf,status,21);
1657 if (!make_dir_struct(ctx,buf,"???????????",volume_label(ctx, SNUM(conn)),
1658 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1659 reply_nterror(req, NT_STATUS_NO_MEMORY);
1660 goto out;
1662 dptr_fill(sconn, buf+12,dptr_num);
1663 if (dptr_zero(buf+12) && (status_len==0)) {
1664 numentries = 1;
1665 } else {
1666 numentries = 0;
1668 if (message_push_blob(&req->outbuf,
1669 data_blob_const(buf, sizeof(buf)))
1670 == -1) {
1671 reply_nterror(req, NT_STATUS_NO_MEMORY);
1672 goto out;
1674 } else {
1675 unsigned int i;
1676 maxentries = MIN(
1677 maxentries,
1678 ((BUFFER_SIZE -
1679 ((uint8 *)smb_buf(req->outbuf) + 3 - req->outbuf))
1680 /DIR_STRUCT_SIZE));
1682 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1683 directory,lp_dontdescend(ctx, SNUM(conn))));
1684 if (in_list(directory, lp_dontdescend(ctx, SNUM(conn)),True)) {
1685 check_descend = True;
1688 for (i=numentries;(i<maxentries) && !finished;i++) {
1689 finished = !get_dir_entry(ctx,
1690 dirptr,
1691 mask,
1692 dirtype,
1693 &fname,
1694 &size,
1695 &mode,
1696 &date,
1697 check_descend,
1698 ask_sharemode);
1699 if (!finished) {
1700 char buf[DIR_STRUCT_SIZE];
1701 memcpy(buf,status,21);
1702 if (!make_dir_struct(ctx,
1703 buf,
1704 mask,
1705 fname,
1706 size,
1707 mode,
1708 convert_timespec_to_time_t(date),
1709 !allow_long_path_components)) {
1710 reply_nterror(req, NT_STATUS_NO_MEMORY);
1711 goto out;
1713 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1714 break;
1716 if (message_push_blob(&req->outbuf,
1717 data_blob_const(buf, sizeof(buf)))
1718 == -1) {
1719 reply_nterror(req, NT_STATUS_NO_MEMORY);
1720 goto out;
1722 numentries++;
1727 SearchEmpty:
1729 /* If we were called as SMBffirst with smb_search_id == NULL
1730 and no entries were found then return error and close dirptr
1731 (X/Open spec) */
1733 if (numentries == 0) {
1734 dptr_close(sconn, &dptr_num);
1735 } else if(expect_close && status_len == 0) {
1736 /* Close the dptr - we know it's gone */
1737 dptr_close(sconn, &dptr_num);
1740 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1741 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1742 dptr_close(sconn, &dptr_num);
1745 if ((numentries == 0) && !mask_contains_wcard) {
1746 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1747 goto out;
1750 SSVAL(req->outbuf,smb_vwv0,numentries);
1751 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1752 SCVAL(smb_buf(req->outbuf),0,5);
1753 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1755 /* The replies here are never long name. */
1756 SSVAL(req->outbuf, smb_flg2,
1757 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1758 if (!allow_long_path_components) {
1759 SSVAL(req->outbuf, smb_flg2,
1760 SVAL(req->outbuf, smb_flg2)
1761 & (~FLAGS2_LONG_PATH_COMPONENTS));
1764 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
1765 SSVAL(req->outbuf, smb_flg2,
1766 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
1768 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
1769 smb_fn_name(req->cmd),
1770 mask,
1771 directory,
1772 dirtype,
1773 numentries,
1774 maxentries ));
1775 out:
1776 TALLOC_FREE(directory);
1777 TALLOC_FREE(smb_fname);
1778 END_PROFILE(SMBsearch);
1779 return;
1782 /****************************************************************************
1783 Reply to a fclose (stop directory search).
1784 ****************************************************************************/
1786 void reply_fclose(struct smb_request *req)
1788 int status_len;
1789 char status[21];
1790 int dptr_num= -2;
1791 const char *p;
1792 char *path = NULL;
1793 NTSTATUS err;
1794 bool path_contains_wcard = False;
1795 TALLOC_CTX *ctx = talloc_tos();
1796 struct smbd_server_connection *sconn = req->sconn;
1798 START_PROFILE(SMBfclose);
1800 if (lp_posix_pathnames()) {
1801 reply_unknown_new(req, req->cmd);
1802 END_PROFILE(SMBfclose);
1803 return;
1806 p = (const char *)req->buf + 1;
1807 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1808 &err, &path_contains_wcard);
1809 if (!NT_STATUS_IS_OK(err)) {
1810 reply_nterror(req, err);
1811 END_PROFILE(SMBfclose);
1812 return;
1814 p++;
1815 status_len = SVAL(p,0);
1816 p += 2;
1818 if (status_len == 0) {
1819 reply_force_doserror(req, ERRSRV, ERRsrverror);
1820 END_PROFILE(SMBfclose);
1821 return;
1824 memcpy(status,p,21);
1826 if(dptr_fetch(sconn, status+12,&dptr_num)) {
1827 /* Close the dptr - we know it's gone */
1828 dptr_close(sconn, &dptr_num);
1831 reply_outbuf(req, 1, 0);
1832 SSVAL(req->outbuf,smb_vwv0,0);
1834 DEBUG(3,("search close\n"));
1836 END_PROFILE(SMBfclose);
1837 return;
1840 /****************************************************************************
1841 Reply to an open.
1842 ****************************************************************************/
1844 void reply_open(struct smb_request *req)
1846 connection_struct *conn = req->conn;
1847 struct smb_filename *smb_fname = NULL;
1848 char *fname = NULL;
1849 uint32 fattr=0;
1850 off_t size = 0;
1851 time_t mtime=0;
1852 int info;
1853 files_struct *fsp;
1854 int oplock_request;
1855 int deny_mode;
1856 uint32 dos_attr;
1857 uint32 access_mask;
1858 uint32 share_mode;
1859 uint32 create_disposition;
1860 uint32 create_options = 0;
1861 uint32_t private_flags = 0;
1862 NTSTATUS status;
1863 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1864 TALLOC_CTX *ctx = talloc_tos();
1866 START_PROFILE(SMBopen);
1868 if (req->wct < 2) {
1869 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1870 goto out;
1873 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1874 deny_mode = SVAL(req->vwv+0, 0);
1875 dos_attr = SVAL(req->vwv+1, 0);
1877 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
1878 STR_TERMINATE, &status);
1879 if (!NT_STATUS_IS_OK(status)) {
1880 reply_nterror(req, status);
1881 goto out;
1884 status = filename_convert(ctx,
1885 conn,
1886 req->flags2 & FLAGS2_DFS_PATHNAMES,
1887 fname,
1889 NULL,
1890 &smb_fname);
1891 if (!NT_STATUS_IS_OK(status)) {
1892 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1893 reply_botherror(req,
1894 NT_STATUS_PATH_NOT_COVERED,
1895 ERRSRV, ERRbadpath);
1896 goto out;
1898 reply_nterror(req, status);
1899 goto out;
1902 if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode,
1903 OPENX_FILE_EXISTS_OPEN, &access_mask,
1904 &share_mode, &create_disposition,
1905 &create_options, &private_flags)) {
1906 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1907 goto out;
1910 status = SMB_VFS_CREATE_FILE(
1911 conn, /* conn */
1912 req, /* req */
1913 0, /* root_dir_fid */
1914 smb_fname, /* fname */
1915 access_mask, /* access_mask */
1916 share_mode, /* share_access */
1917 create_disposition, /* create_disposition*/
1918 create_options, /* create_options */
1919 dos_attr, /* file_attributes */
1920 oplock_request, /* oplock_request */
1921 0, /* allocation_size */
1922 private_flags,
1923 NULL, /* sd */
1924 NULL, /* ea_list */
1925 &fsp, /* result */
1926 &info); /* pinfo */
1928 if (!NT_STATUS_IS_OK(status)) {
1929 if (open_was_deferred(req->sconn, req->mid)) {
1930 /* We have re-scheduled this call. */
1931 goto out;
1933 reply_openerror(req, status);
1934 goto out;
1937 size = smb_fname->st.st_ex_size;
1938 fattr = dos_mode(conn, smb_fname);
1940 /* Deal with other possible opens having a modified
1941 write time. JRA. */
1942 if (ask_sharemode) {
1943 struct timespec write_time_ts;
1945 ZERO_STRUCT(write_time_ts);
1946 get_file_infos(fsp->file_id, 0, NULL, &write_time_ts);
1947 if (!null_timespec(write_time_ts)) {
1948 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1952 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1954 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
1955 DEBUG(3,("attempt to open a directory %s\n",
1956 fsp_str_dbg(fsp)));
1957 close_file(req, fsp, ERROR_CLOSE);
1958 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
1959 ERRDOS, ERRnoaccess);
1960 goto out;
1963 reply_outbuf(req, 7, 0);
1964 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
1965 SSVAL(req->outbuf,smb_vwv1,fattr);
1966 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1967 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
1968 } else {
1969 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
1971 SIVAL(req->outbuf,smb_vwv4,(uint32)size);
1972 SSVAL(req->outbuf,smb_vwv6,deny_mode);
1974 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1975 SCVAL(req->outbuf,smb_flg,
1976 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1979 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1980 SCVAL(req->outbuf,smb_flg,
1981 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1983 out:
1984 TALLOC_FREE(smb_fname);
1985 END_PROFILE(SMBopen);
1986 return;
1989 /****************************************************************************
1990 Reply to an open and X.
1991 ****************************************************************************/
1993 void reply_open_and_X(struct smb_request *req)
1995 connection_struct *conn = req->conn;
1996 struct smb_filename *smb_fname = NULL;
1997 char *fname = NULL;
1998 uint16 open_flags;
1999 int deny_mode;
2000 uint32 smb_attr;
2001 /* Breakout the oplock request bits so we can set the
2002 reply bits separately. */
2003 int ex_oplock_request;
2004 int core_oplock_request;
2005 int oplock_request;
2006 #if 0
2007 int smb_sattr = SVAL(req->vwv+4, 0);
2008 uint32 smb_time = make_unix_date3(req->vwv+6);
2009 #endif
2010 int smb_ofun;
2011 uint32 fattr=0;
2012 int mtime=0;
2013 int smb_action = 0;
2014 files_struct *fsp;
2015 NTSTATUS status;
2016 uint64_t allocation_size;
2017 ssize_t retval = -1;
2018 uint32 access_mask;
2019 uint32 share_mode;
2020 uint32 create_disposition;
2021 uint32 create_options = 0;
2022 uint32_t private_flags = 0;
2023 TALLOC_CTX *ctx = talloc_tos();
2025 START_PROFILE(SMBopenX);
2027 if (req->wct < 15) {
2028 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2029 goto out;
2032 open_flags = SVAL(req->vwv+2, 0);
2033 deny_mode = SVAL(req->vwv+3, 0);
2034 smb_attr = SVAL(req->vwv+5, 0);
2035 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
2036 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2037 oplock_request = ex_oplock_request | core_oplock_request;
2038 smb_ofun = SVAL(req->vwv+8, 0);
2039 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
2041 /* If it's an IPC, pass off the pipe handler. */
2042 if (IS_IPC(conn)) {
2043 if (lp_nt_pipe_support()) {
2044 reply_open_pipe_and_X(conn, req);
2045 } else {
2046 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
2048 goto out;
2051 /* XXXX we need to handle passed times, sattr and flags */
2052 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
2053 STR_TERMINATE, &status);
2054 if (!NT_STATUS_IS_OK(status)) {
2055 reply_nterror(req, status);
2056 goto out;
2059 status = filename_convert(ctx,
2060 conn,
2061 req->flags2 & FLAGS2_DFS_PATHNAMES,
2062 fname,
2064 NULL,
2065 &smb_fname);
2066 if (!NT_STATUS_IS_OK(status)) {
2067 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2068 reply_botherror(req,
2069 NT_STATUS_PATH_NOT_COVERED,
2070 ERRSRV, ERRbadpath);
2071 goto out;
2073 reply_nterror(req, status);
2074 goto out;
2077 if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode,
2078 smb_ofun,
2079 &access_mask, &share_mode,
2080 &create_disposition,
2081 &create_options,
2082 &private_flags)) {
2083 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2084 goto out;
2087 status = SMB_VFS_CREATE_FILE(
2088 conn, /* conn */
2089 req, /* req */
2090 0, /* root_dir_fid */
2091 smb_fname, /* fname */
2092 access_mask, /* access_mask */
2093 share_mode, /* share_access */
2094 create_disposition, /* create_disposition*/
2095 create_options, /* create_options */
2096 smb_attr, /* file_attributes */
2097 oplock_request, /* oplock_request */
2098 0, /* allocation_size */
2099 private_flags,
2100 NULL, /* sd */
2101 NULL, /* ea_list */
2102 &fsp, /* result */
2103 &smb_action); /* pinfo */
2105 if (!NT_STATUS_IS_OK(status)) {
2106 if (open_was_deferred(req->sconn, req->mid)) {
2107 /* We have re-scheduled this call. */
2108 goto out;
2110 reply_openerror(req, status);
2111 goto out;
2114 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2115 if the file is truncated or created. */
2116 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2117 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2118 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2119 close_file(req, fsp, ERROR_CLOSE);
2120 reply_nterror(req, NT_STATUS_DISK_FULL);
2121 goto out;
2123 retval = vfs_set_filelen(fsp, (off_t)allocation_size);
2124 if (retval < 0) {
2125 close_file(req, fsp, ERROR_CLOSE);
2126 reply_nterror(req, NT_STATUS_DISK_FULL);
2127 goto out;
2129 status = vfs_stat_fsp(fsp);
2130 if (!NT_STATUS_IS_OK(status)) {
2131 close_file(req, fsp, ERROR_CLOSE);
2132 reply_nterror(req, status);
2133 goto out;
2137 fattr = dos_mode(conn, fsp->fsp_name);
2138 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2139 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2140 close_file(req, fsp, ERROR_CLOSE);
2141 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2142 goto out;
2145 /* If the caller set the extended oplock request bit
2146 and we granted one (by whatever means) - set the
2147 correct bit for extended oplock reply.
2150 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2151 smb_action |= EXTENDED_OPLOCK_GRANTED;
2154 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2155 smb_action |= EXTENDED_OPLOCK_GRANTED;
2158 /* If the caller set the core oplock request bit
2159 and we granted one (by whatever means) - set the
2160 correct bit for core oplock reply.
2163 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2164 reply_outbuf(req, 19, 0);
2165 } else {
2166 reply_outbuf(req, 15, 0);
2169 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2170 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2172 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2173 SCVAL(req->outbuf, smb_flg,
2174 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2177 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2178 SCVAL(req->outbuf, smb_flg,
2179 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2182 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2183 SSVAL(req->outbuf,smb_vwv3,fattr);
2184 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2185 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2186 } else {
2187 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2189 SIVAL(req->outbuf,smb_vwv6,(uint32)fsp->fsp_name->st.st_ex_size);
2190 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2191 SSVAL(req->outbuf,smb_vwv11,smb_action);
2193 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2194 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2197 out:
2198 TALLOC_FREE(smb_fname);
2199 END_PROFILE(SMBopenX);
2200 return;
2203 /****************************************************************************
2204 Reply to a SMBulogoffX.
2205 ****************************************************************************/
2207 void reply_ulogoffX(struct smb_request *req)
2209 struct smbd_server_connection *sconn = req->sconn;
2210 struct user_struct *vuser;
2211 struct smbXsrv_session *session = NULL;
2212 NTSTATUS status;
2214 START_PROFILE(SMBulogoffX);
2216 vuser = get_valid_user_struct(sconn, req->vuid);
2218 if(vuser == NULL) {
2219 DEBUG(3,("ulogoff, vuser id %llu does not map to user.\n",
2220 (unsigned long long)req->vuid));
2222 req->vuid = UID_FIELD_INVALID;
2223 reply_force_doserror(req, ERRSRV, ERRbaduid);
2224 END_PROFILE(SMBulogoffX);
2225 return;
2228 session = vuser->session;
2229 vuser = NULL;
2232 * TODO: cancel all outstanding requests on the session
2234 status = smbXsrv_session_logoff(session);
2235 if (!NT_STATUS_IS_OK(status)) {
2236 DEBUG(0, ("reply_ulogoff: "
2237 "smbXsrv_session_logoff() failed: %s\n",
2238 nt_errstr(status)));
2240 * If we hit this case, there is something completely
2241 * wrong, so we better disconnect the transport connection.
2243 END_PROFILE(SMBulogoffX);
2244 exit_server(__location__ ": smbXsrv_session_logoff failed");
2245 return;
2248 TALLOC_FREE(session);
2250 reply_outbuf(req, 2, 0);
2251 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2252 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2254 DEBUG(3, ("ulogoffX vuid=%llu\n",
2255 (unsigned long long)req->vuid));
2257 END_PROFILE(SMBulogoffX);
2258 req->vuid = UID_FIELD_INVALID;
2261 /****************************************************************************
2262 Reply to a mknew or a create.
2263 ****************************************************************************/
2265 void reply_mknew(struct smb_request *req)
2267 connection_struct *conn = req->conn;
2268 struct smb_filename *smb_fname = NULL;
2269 char *fname = NULL;
2270 uint32 fattr = 0;
2271 struct smb_file_time ft;
2272 files_struct *fsp;
2273 int oplock_request = 0;
2274 NTSTATUS status;
2275 uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2276 uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2277 uint32 create_disposition;
2278 uint32 create_options = 0;
2279 TALLOC_CTX *ctx = talloc_tos();
2281 START_PROFILE(SMBcreate);
2282 ZERO_STRUCT(ft);
2284 if (req->wct < 3) {
2285 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2286 goto out;
2289 fattr = SVAL(req->vwv+0, 0);
2290 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2292 /* mtime. */
2293 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2295 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2296 STR_TERMINATE, &status);
2297 if (!NT_STATUS_IS_OK(status)) {
2298 reply_nterror(req, status);
2299 goto out;
2302 status = filename_convert(ctx,
2303 conn,
2304 req->flags2 & FLAGS2_DFS_PATHNAMES,
2305 fname,
2307 NULL,
2308 &smb_fname);
2309 if (!NT_STATUS_IS_OK(status)) {
2310 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2311 reply_botherror(req,
2312 NT_STATUS_PATH_NOT_COVERED,
2313 ERRSRV, ERRbadpath);
2314 goto out;
2316 reply_nterror(req, status);
2317 goto out;
2320 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2321 DEBUG(0,("Attempt to create file (%s) with volid set - "
2322 "please report this\n",
2323 smb_fname_str_dbg(smb_fname)));
2326 if(req->cmd == SMBmknew) {
2327 /* We should fail if file exists. */
2328 create_disposition = FILE_CREATE;
2329 } else {
2330 /* Create if file doesn't exist, truncate if it does. */
2331 create_disposition = FILE_OVERWRITE_IF;
2334 status = SMB_VFS_CREATE_FILE(
2335 conn, /* conn */
2336 req, /* req */
2337 0, /* root_dir_fid */
2338 smb_fname, /* fname */
2339 access_mask, /* access_mask */
2340 share_mode, /* share_access */
2341 create_disposition, /* create_disposition*/
2342 create_options, /* create_options */
2343 fattr, /* file_attributes */
2344 oplock_request, /* oplock_request */
2345 0, /* allocation_size */
2346 0, /* private_flags */
2347 NULL, /* sd */
2348 NULL, /* ea_list */
2349 &fsp, /* result */
2350 NULL); /* pinfo */
2352 if (!NT_STATUS_IS_OK(status)) {
2353 if (open_was_deferred(req->sconn, req->mid)) {
2354 /* We have re-scheduled this call. */
2355 goto out;
2357 reply_openerror(req, status);
2358 goto out;
2361 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2362 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2363 if (!NT_STATUS_IS_OK(status)) {
2364 END_PROFILE(SMBcreate);
2365 goto out;
2368 reply_outbuf(req, 1, 0);
2369 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2371 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2372 SCVAL(req->outbuf,smb_flg,
2373 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2376 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2377 SCVAL(req->outbuf,smb_flg,
2378 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2381 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2382 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2383 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2384 (unsigned int)fattr));
2386 out:
2387 TALLOC_FREE(smb_fname);
2388 END_PROFILE(SMBcreate);
2389 return;
2392 /****************************************************************************
2393 Reply to a create temporary file.
2394 ****************************************************************************/
2396 void reply_ctemp(struct smb_request *req)
2398 connection_struct *conn = req->conn;
2399 struct smb_filename *smb_fname = NULL;
2400 char *fname = NULL;
2401 uint32 fattr;
2402 files_struct *fsp;
2403 int oplock_request;
2404 int tmpfd;
2405 char *s;
2406 NTSTATUS status;
2407 TALLOC_CTX *ctx = talloc_tos();
2409 START_PROFILE(SMBctemp);
2411 if (req->wct < 3) {
2412 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2413 goto out;
2416 fattr = SVAL(req->vwv+0, 0);
2417 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2419 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
2420 STR_TERMINATE, &status);
2421 if (!NT_STATUS_IS_OK(status)) {
2422 reply_nterror(req, status);
2423 goto out;
2425 if (*fname) {
2426 fname = talloc_asprintf(ctx,
2427 "%s/TMXXXXXX",
2428 fname);
2429 } else {
2430 fname = talloc_strdup(ctx, "TMXXXXXX");
2433 if (!fname) {
2434 reply_nterror(req, NT_STATUS_NO_MEMORY);
2435 goto out;
2438 status = filename_convert(ctx, conn,
2439 req->flags2 & FLAGS2_DFS_PATHNAMES,
2440 fname,
2442 NULL,
2443 &smb_fname);
2444 if (!NT_STATUS_IS_OK(status)) {
2445 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2446 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2447 ERRSRV, ERRbadpath);
2448 goto out;
2450 reply_nterror(req, status);
2451 goto out;
2454 tmpfd = mkstemp(smb_fname->base_name);
2455 if (tmpfd == -1) {
2456 reply_nterror(req, map_nt_error_from_unix(errno));
2457 goto out;
2460 SMB_VFS_STAT(conn, smb_fname);
2462 /* We should fail if file does not exist. */
2463 status = SMB_VFS_CREATE_FILE(
2464 conn, /* conn */
2465 req, /* req */
2466 0, /* root_dir_fid */
2467 smb_fname, /* fname */
2468 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2469 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2470 FILE_OPEN, /* create_disposition*/
2471 0, /* create_options */
2472 fattr, /* file_attributes */
2473 oplock_request, /* oplock_request */
2474 0, /* allocation_size */
2475 0, /* private_flags */
2476 NULL, /* sd */
2477 NULL, /* ea_list */
2478 &fsp, /* result */
2479 NULL); /* pinfo */
2481 /* close fd from mkstemp() */
2482 close(tmpfd);
2484 if (!NT_STATUS_IS_OK(status)) {
2485 if (open_was_deferred(req->sconn, req->mid)) {
2486 /* We have re-scheduled this call. */
2487 goto out;
2489 reply_openerror(req, status);
2490 goto out;
2493 reply_outbuf(req, 1, 0);
2494 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2496 /* the returned filename is relative to the directory */
2497 s = strrchr_m(fsp->fsp_name->base_name, '/');
2498 if (!s) {
2499 s = fsp->fsp_name->base_name;
2500 } else {
2501 s++;
2504 #if 0
2505 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2506 thing in the byte section. JRA */
2507 SSVALS(p, 0, -1); /* what is this? not in spec */
2508 #endif
2509 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2510 == -1) {
2511 reply_nterror(req, NT_STATUS_NO_MEMORY);
2512 goto out;
2515 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2516 SCVAL(req->outbuf, smb_flg,
2517 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2520 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2521 SCVAL(req->outbuf, smb_flg,
2522 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2525 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2526 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2527 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2528 out:
2529 TALLOC_FREE(smb_fname);
2530 END_PROFILE(SMBctemp);
2531 return;
2534 /*******************************************************************
2535 Check if a user is allowed to rename a file.
2536 ********************************************************************/
2538 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2539 uint16 dirtype)
2541 if (!CAN_WRITE(conn)) {
2542 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2545 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
2546 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2547 /* Only bother to read the DOS attribute if we might deny the
2548 rename on the grounds of attribute missmatch. */
2549 uint32_t fmode = dos_mode(conn, fsp->fsp_name);
2550 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2551 return NT_STATUS_NO_SUCH_FILE;
2555 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2556 if (fsp->posix_open) {
2557 return NT_STATUS_OK;
2560 /* If no pathnames are open below this
2561 directory, allow the rename. */
2563 if (file_find_subpath(fsp)) {
2564 return NT_STATUS_ACCESS_DENIED;
2566 return NT_STATUS_OK;
2569 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2570 return NT_STATUS_OK;
2573 return NT_STATUS_ACCESS_DENIED;
2576 /*******************************************************************
2577 * unlink a file with all relevant access checks
2578 *******************************************************************/
2580 static NTSTATUS do_unlink(connection_struct *conn,
2581 struct smb_request *req,
2582 struct smb_filename *smb_fname,
2583 uint32 dirtype)
2585 uint32 fattr;
2586 files_struct *fsp;
2587 uint32 dirtype_orig = dirtype;
2588 NTSTATUS status;
2589 int ret;
2590 bool posix_paths = lp_posix_pathnames();
2592 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2593 smb_fname_str_dbg(smb_fname),
2594 dirtype));
2596 if (!CAN_WRITE(conn)) {
2597 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2600 if (posix_paths) {
2601 ret = SMB_VFS_LSTAT(conn, smb_fname);
2602 } else {
2603 ret = SMB_VFS_STAT(conn, smb_fname);
2605 if (ret != 0) {
2606 return map_nt_error_from_unix(errno);
2609 fattr = dos_mode(conn, smb_fname);
2611 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2612 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
2615 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
2616 if (!dirtype) {
2617 return NT_STATUS_NO_SUCH_FILE;
2620 if (!dir_check_ftype(conn, fattr, dirtype)) {
2621 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2622 return NT_STATUS_FILE_IS_A_DIRECTORY;
2624 return NT_STATUS_NO_SUCH_FILE;
2627 if (dirtype_orig & 0x8000) {
2628 /* These will never be set for POSIX. */
2629 return NT_STATUS_NO_SUCH_FILE;
2632 #if 0
2633 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2634 return NT_STATUS_FILE_IS_A_DIRECTORY;
2637 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2638 return NT_STATUS_NO_SUCH_FILE;
2641 if (dirtype & 0xFF00) {
2642 /* These will never be set for POSIX. */
2643 return NT_STATUS_NO_SUCH_FILE;
2646 dirtype &= 0xFF;
2647 if (!dirtype) {
2648 return NT_STATUS_NO_SUCH_FILE;
2651 /* Can't delete a directory. */
2652 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2653 return NT_STATUS_FILE_IS_A_DIRECTORY;
2655 #endif
2657 #if 0 /* JRATEST */
2658 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
2659 return NT_STATUS_OBJECT_NAME_INVALID;
2660 #endif /* JRATEST */
2662 /* On open checks the open itself will check the share mode, so
2663 don't do it here as we'll get it wrong. */
2665 status = SMB_VFS_CREATE_FILE
2666 (conn, /* conn */
2667 req, /* req */
2668 0, /* root_dir_fid */
2669 smb_fname, /* fname */
2670 DELETE_ACCESS, /* access_mask */
2671 FILE_SHARE_NONE, /* share_access */
2672 FILE_OPEN, /* create_disposition*/
2673 FILE_NON_DIRECTORY_FILE, /* create_options */
2674 /* file_attributes */
2675 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2676 FILE_ATTRIBUTE_NORMAL,
2677 0, /* oplock_request */
2678 0, /* allocation_size */
2679 0, /* private_flags */
2680 NULL, /* sd */
2681 NULL, /* ea_list */
2682 &fsp, /* result */
2683 NULL); /* pinfo */
2685 if (!NT_STATUS_IS_OK(status)) {
2686 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2687 nt_errstr(status)));
2688 return status;
2691 status = can_set_delete_on_close(fsp, fattr);
2692 if (!NT_STATUS_IS_OK(status)) {
2693 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2694 "(%s)\n",
2695 smb_fname_str_dbg(smb_fname),
2696 nt_errstr(status)));
2697 close_file(req, fsp, NORMAL_CLOSE);
2698 return status;
2701 /* The set is across all open files on this dev/inode pair. */
2702 if (!set_delete_on_close(fsp, True,
2703 conn->session_info->security_token,
2704 conn->session_info->unix_token)) {
2705 close_file(req, fsp, NORMAL_CLOSE);
2706 return NT_STATUS_ACCESS_DENIED;
2709 return close_file(req, fsp, NORMAL_CLOSE);
2712 /****************************************************************************
2713 The guts of the unlink command, split out so it may be called by the NT SMB
2714 code.
2715 ****************************************************************************/
2717 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2718 uint32 dirtype, struct smb_filename *smb_fname,
2719 bool has_wild)
2721 char *fname_dir = NULL;
2722 char *fname_mask = NULL;
2723 int count=0;
2724 NTSTATUS status = NT_STATUS_OK;
2725 TALLOC_CTX *ctx = talloc_tos();
2727 /* Split up the directory from the filename/mask. */
2728 status = split_fname_dir_mask(ctx, smb_fname->base_name,
2729 &fname_dir, &fname_mask);
2730 if (!NT_STATUS_IS_OK(status)) {
2731 goto out;
2735 * We should only check the mangled cache
2736 * here if unix_convert failed. This means
2737 * that the path in 'mask' doesn't exist
2738 * on the file system and so we need to look
2739 * for a possible mangle. This patch from
2740 * Tine Smukavec <valentin.smukavec@hermes.si>.
2743 if (!VALID_STAT(smb_fname->st) &&
2744 mangle_is_mangled(fname_mask, conn->params)) {
2745 char *new_mask = NULL;
2746 mangle_lookup_name_from_8_3(ctx, fname_mask,
2747 &new_mask, conn->params);
2748 if (new_mask) {
2749 TALLOC_FREE(fname_mask);
2750 fname_mask = new_mask;
2754 if (!has_wild) {
2757 * Only one file needs to be unlinked. Append the mask back
2758 * onto the directory.
2760 TALLOC_FREE(smb_fname->base_name);
2761 if (ISDOT(fname_dir)) {
2762 /* Ensure we use canonical names on open. */
2763 smb_fname->base_name = talloc_asprintf(smb_fname,
2764 "%s",
2765 fname_mask);
2766 } else {
2767 smb_fname->base_name = talloc_asprintf(smb_fname,
2768 "%s/%s",
2769 fname_dir,
2770 fname_mask);
2772 if (!smb_fname->base_name) {
2773 status = NT_STATUS_NO_MEMORY;
2774 goto out;
2776 if (dirtype == 0) {
2777 dirtype = FILE_ATTRIBUTE_NORMAL;
2780 status = check_name(conn, smb_fname->base_name);
2781 if (!NT_STATUS_IS_OK(status)) {
2782 goto out;
2785 status = do_unlink(conn, req, smb_fname, dirtype);
2786 if (!NT_STATUS_IS_OK(status)) {
2787 goto out;
2790 count++;
2791 } else {
2792 struct smb_Dir *dir_hnd = NULL;
2793 long offset = 0;
2794 const char *dname = NULL;
2795 char *talloced = NULL;
2797 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
2798 status = NT_STATUS_OBJECT_NAME_INVALID;
2799 goto out;
2802 if (strequal(fname_mask,"????????.???")) {
2803 TALLOC_FREE(fname_mask);
2804 fname_mask = talloc_strdup(ctx, "*");
2805 if (!fname_mask) {
2806 status = NT_STATUS_NO_MEMORY;
2807 goto out;
2811 status = check_name(conn, fname_dir);
2812 if (!NT_STATUS_IS_OK(status)) {
2813 goto out;
2816 dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask,
2817 dirtype);
2818 if (dir_hnd == NULL) {
2819 status = map_nt_error_from_unix(errno);
2820 goto out;
2823 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2824 the pattern matches against the long name, otherwise the short name
2825 We don't implement this yet XXXX
2828 status = NT_STATUS_NO_SUCH_FILE;
2830 while ((dname = ReadDirName(dir_hnd, &offset,
2831 &smb_fname->st, &talloced))) {
2832 TALLOC_CTX *frame = talloc_stackframe();
2834 if (!is_visible_file(conn, fname_dir, dname,
2835 &smb_fname->st, true)) {
2836 TALLOC_FREE(frame);
2837 TALLOC_FREE(talloced);
2838 continue;
2841 /* Quick check for "." and ".." */
2842 if (ISDOT(dname) || ISDOTDOT(dname)) {
2843 TALLOC_FREE(frame);
2844 TALLOC_FREE(talloced);
2845 continue;
2848 if(!mask_match(dname, fname_mask,
2849 conn->case_sensitive)) {
2850 TALLOC_FREE(frame);
2851 TALLOC_FREE(talloced);
2852 continue;
2855 TALLOC_FREE(smb_fname->base_name);
2856 if (ISDOT(fname_dir)) {
2857 /* Ensure we use canonical names on open. */
2858 smb_fname->base_name =
2859 talloc_asprintf(smb_fname, "%s",
2860 dname);
2861 } else {
2862 smb_fname->base_name =
2863 talloc_asprintf(smb_fname, "%s/%s",
2864 fname_dir, dname);
2867 if (!smb_fname->base_name) {
2868 TALLOC_FREE(dir_hnd);
2869 status = NT_STATUS_NO_MEMORY;
2870 TALLOC_FREE(frame);
2871 TALLOC_FREE(talloced);
2872 goto out;
2875 status = check_name(conn, smb_fname->base_name);
2876 if (!NT_STATUS_IS_OK(status)) {
2877 TALLOC_FREE(dir_hnd);
2878 TALLOC_FREE(frame);
2879 TALLOC_FREE(talloced);
2880 goto out;
2883 status = do_unlink(conn, req, smb_fname, dirtype);
2884 if (!NT_STATUS_IS_OK(status)) {
2885 TALLOC_FREE(frame);
2886 TALLOC_FREE(talloced);
2887 continue;
2890 count++;
2891 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
2892 smb_fname->base_name));
2894 TALLOC_FREE(frame);
2895 TALLOC_FREE(talloced);
2897 TALLOC_FREE(dir_hnd);
2900 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
2901 status = map_nt_error_from_unix(errno);
2904 out:
2905 TALLOC_FREE(fname_dir);
2906 TALLOC_FREE(fname_mask);
2907 return status;
2910 /****************************************************************************
2911 Reply to a unlink
2912 ****************************************************************************/
2914 void reply_unlink(struct smb_request *req)
2916 connection_struct *conn = req->conn;
2917 char *name = NULL;
2918 struct smb_filename *smb_fname = NULL;
2919 uint32 dirtype;
2920 NTSTATUS status;
2921 bool path_contains_wcard = False;
2922 TALLOC_CTX *ctx = talloc_tos();
2924 START_PROFILE(SMBunlink);
2926 if (req->wct < 1) {
2927 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2928 goto out;
2931 dirtype = SVAL(req->vwv+0, 0);
2933 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
2934 STR_TERMINATE, &status,
2935 &path_contains_wcard);
2936 if (!NT_STATUS_IS_OK(status)) {
2937 reply_nterror(req, status);
2938 goto out;
2941 status = filename_convert(ctx, conn,
2942 req->flags2 & FLAGS2_DFS_PATHNAMES,
2943 name,
2944 UCF_COND_ALLOW_WCARD_LCOMP,
2945 &path_contains_wcard,
2946 &smb_fname);
2947 if (!NT_STATUS_IS_OK(status)) {
2948 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2949 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2950 ERRSRV, ERRbadpath);
2951 goto out;
2953 reply_nterror(req, status);
2954 goto out;
2957 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
2959 status = unlink_internals(conn, req, dirtype, smb_fname,
2960 path_contains_wcard);
2961 if (!NT_STATUS_IS_OK(status)) {
2962 if (open_was_deferred(req->sconn, req->mid)) {
2963 /* We have re-scheduled this call. */
2964 goto out;
2966 reply_nterror(req, status);
2967 goto out;
2970 reply_outbuf(req, 0, 0);
2971 out:
2972 TALLOC_FREE(smb_fname);
2973 END_PROFILE(SMBunlink);
2974 return;
2977 /****************************************************************************
2978 Fail for readbraw.
2979 ****************************************************************************/
2981 static void fail_readraw(void)
2983 const char *errstr = talloc_asprintf(talloc_tos(),
2984 "FAIL ! reply_readbraw: socket write fail (%s)",
2985 strerror(errno));
2986 if (!errstr) {
2987 errstr = "";
2989 exit_server_cleanly(errstr);
2992 /****************************************************************************
2993 Fake (read/write) sendfile. Returns -1 on read or write fail.
2994 ****************************************************************************/
2996 ssize_t fake_sendfile(files_struct *fsp, off_t startpos, size_t nread)
2998 size_t bufsize;
2999 size_t tosend = nread;
3000 char *buf;
3002 if (nread == 0) {
3003 return 0;
3006 bufsize = MIN(nread, 65536);
3008 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
3009 return -1;
3012 while (tosend > 0) {
3013 ssize_t ret;
3014 size_t cur_read;
3016 if (tosend > bufsize) {
3017 cur_read = bufsize;
3018 } else {
3019 cur_read = tosend;
3021 ret = read_file(fsp,buf,startpos,cur_read);
3022 if (ret == -1) {
3023 SAFE_FREE(buf);
3024 return -1;
3027 /* If we had a short read, fill with zeros. */
3028 if (ret < cur_read) {
3029 memset(buf + ret, '\0', cur_read - ret);
3032 if (write_data(fsp->conn->sconn->sock, buf, cur_read)
3033 != cur_read) {
3034 char addr[INET6_ADDRSTRLEN];
3036 * Try and give an error message saying what
3037 * client failed.
3039 DEBUG(0, ("write_data failed for client %s. "
3040 "Error %s\n",
3041 get_peer_addr(fsp->conn->sconn->sock, addr,
3042 sizeof(addr)),
3043 strerror(errno)));
3044 SAFE_FREE(buf);
3045 return -1;
3047 tosend -= cur_read;
3048 startpos += cur_read;
3051 SAFE_FREE(buf);
3052 return (ssize_t)nread;
3055 /****************************************************************************
3056 Deal with the case of sendfile reading less bytes from the file than
3057 requested. Fill with zeros (all we can do).
3058 ****************************************************************************/
3060 void sendfile_short_send(files_struct *fsp,
3061 ssize_t nread,
3062 size_t headersize,
3063 size_t smb_maxcnt)
3065 #define SHORT_SEND_BUFSIZE 1024
3066 if (nread < headersize) {
3067 DEBUG(0,("sendfile_short_send: sendfile failed to send "
3068 "header for file %s (%s). Terminating\n",
3069 fsp_str_dbg(fsp), strerror(errno)));
3070 exit_server_cleanly("sendfile_short_send failed");
3073 nread -= headersize;
3075 if (nread < smb_maxcnt) {
3076 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
3077 if (!buf) {
3078 exit_server_cleanly("sendfile_short_send: "
3079 "malloc failed");
3082 DEBUG(0,("sendfile_short_send: filling truncated file %s "
3083 "with zeros !\n", fsp_str_dbg(fsp)));
3085 while (nread < smb_maxcnt) {
3087 * We asked for the real file size and told sendfile
3088 * to not go beyond the end of the file. But it can
3089 * happen that in between our fstat call and the
3090 * sendfile call the file was truncated. This is very
3091 * bad because we have already announced the larger
3092 * number of bytes to the client.
3094 * The best we can do now is to send 0-bytes, just as
3095 * a read from a hole in a sparse file would do.
3097 * This should happen rarely enough that I don't care
3098 * about efficiency here :-)
3100 size_t to_write;
3102 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
3103 if (write_data(fsp->conn->sconn->sock, buf, to_write)
3104 != to_write) {
3105 char addr[INET6_ADDRSTRLEN];
3107 * Try and give an error message saying what
3108 * client failed.
3110 DEBUG(0, ("write_data failed for client %s. "
3111 "Error %s\n",
3112 get_peer_addr(
3113 fsp->conn->sconn->sock, addr,
3114 sizeof(addr)),
3115 strerror(errno)));
3116 exit_server_cleanly("sendfile_short_send: "
3117 "write_data failed");
3119 nread += to_write;
3121 SAFE_FREE(buf);
3125 /****************************************************************************
3126 Return a readbraw error (4 bytes of zero).
3127 ****************************************************************************/
3129 static void reply_readbraw_error(struct smbd_server_connection *sconn)
3131 char header[4];
3133 SIVAL(header,0,0);
3135 smbd_lock_socket(sconn);
3136 if (write_data(sconn->sock,header,4) != 4) {
3137 char addr[INET6_ADDRSTRLEN];
3139 * Try and give an error message saying what
3140 * client failed.
3142 DEBUG(0, ("write_data failed for client %s. "
3143 "Error %s\n",
3144 get_peer_addr(sconn->sock, addr, sizeof(addr)),
3145 strerror(errno)));
3147 fail_readraw();
3149 smbd_unlock_socket(sconn);
3152 /****************************************************************************
3153 Use sendfile in readbraw.
3154 ****************************************************************************/
3156 static void send_file_readbraw(connection_struct *conn,
3157 struct smb_request *req,
3158 files_struct *fsp,
3159 off_t startpos,
3160 size_t nread,
3161 ssize_t mincount)
3163 struct smbd_server_connection *sconn = req->sconn;
3164 char *outbuf = NULL;
3165 ssize_t ret=0;
3168 * We can only use sendfile on a non-chained packet
3169 * but we can use on a non-oplocked file. tridge proved this
3170 * on a train in Germany :-). JRA.
3171 * reply_readbraw has already checked the length.
3174 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3175 (fsp->wcp == NULL) &&
3176 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3177 ssize_t sendfile_read = -1;
3178 char header[4];
3179 DATA_BLOB header_blob;
3181 _smb_setlen(header,nread);
3182 header_blob = data_blob_const(header, 4);
3184 sendfile_read = SMB_VFS_SENDFILE(sconn->sock, fsp,
3185 &header_blob, startpos,
3186 nread);
3187 if (sendfile_read == -1) {
3188 /* Returning ENOSYS means no data at all was sent.
3189 * Do this as a normal read. */
3190 if (errno == ENOSYS) {
3191 goto normal_readbraw;
3195 * Special hack for broken Linux with no working sendfile. If we
3196 * return EINTR we sent the header but not the rest of the data.
3197 * Fake this up by doing read/write calls.
3199 if (errno == EINTR) {
3200 /* Ensure we don't do this again. */
3201 set_use_sendfile(SNUM(conn), False);
3202 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3204 if (fake_sendfile(fsp, startpos, nread) == -1) {
3205 DEBUG(0,("send_file_readbraw: "
3206 "fake_sendfile failed for "
3207 "file %s (%s).\n",
3208 fsp_str_dbg(fsp),
3209 strerror(errno)));
3210 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3212 return;
3215 DEBUG(0,("send_file_readbraw: sendfile failed for "
3216 "file %s (%s). Terminating\n",
3217 fsp_str_dbg(fsp), strerror(errno)));
3218 exit_server_cleanly("send_file_readbraw sendfile failed");
3219 } else if (sendfile_read == 0) {
3221 * Some sendfile implementations return 0 to indicate
3222 * that there was a short read, but nothing was
3223 * actually written to the socket. In this case,
3224 * fallback to the normal read path so the header gets
3225 * the correct byte count.
3227 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3228 "bytes falling back to the normal read: "
3229 "%s\n", fsp_str_dbg(fsp)));
3230 goto normal_readbraw;
3233 /* Deal with possible short send. */
3234 if (sendfile_read != 4+nread) {
3235 sendfile_short_send(fsp, sendfile_read, 4, nread);
3237 return;
3240 normal_readbraw:
3242 outbuf = talloc_array(NULL, char, nread+4);
3243 if (!outbuf) {
3244 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3245 (unsigned)(nread+4)));
3246 reply_readbraw_error(sconn);
3247 return;
3250 if (nread > 0) {
3251 ret = read_file(fsp,outbuf+4,startpos,nread);
3252 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3253 if (ret < mincount)
3254 ret = 0;
3255 #else
3256 if (ret < nread)
3257 ret = 0;
3258 #endif
3261 _smb_setlen(outbuf,ret);
3262 if (write_data(sconn->sock, outbuf, 4+ret) != 4+ret) {
3263 char addr[INET6_ADDRSTRLEN];
3265 * Try and give an error message saying what
3266 * client failed.
3268 DEBUG(0, ("write_data failed for client %s. "
3269 "Error %s\n",
3270 get_peer_addr(fsp->conn->sconn->sock, addr,
3271 sizeof(addr)),
3272 strerror(errno)));
3274 fail_readraw();
3277 TALLOC_FREE(outbuf);
3280 /****************************************************************************
3281 Reply to a readbraw (core+ protocol).
3282 ****************************************************************************/
3284 void reply_readbraw(struct smb_request *req)
3286 connection_struct *conn = req->conn;
3287 struct smbd_server_connection *sconn = req->sconn;
3288 ssize_t maxcount,mincount;
3289 size_t nread = 0;
3290 off_t startpos;
3291 files_struct *fsp;
3292 struct lock_struct lock;
3293 off_t size = 0;
3295 START_PROFILE(SMBreadbraw);
3297 if (srv_is_signing_active(sconn) ||
3298 is_encrypted_packet(sconn, req->inbuf)) {
3299 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3300 "raw reads/writes are disallowed.");
3303 if (req->wct < 8) {
3304 reply_readbraw_error(sconn);
3305 END_PROFILE(SMBreadbraw);
3306 return;
3309 if (sconn->smb1.echo_handler.trusted_fde) {
3310 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3311 "'async smb echo handler = yes'\n"));
3312 reply_readbraw_error(sconn);
3313 END_PROFILE(SMBreadbraw);
3314 return;
3318 * Special check if an oplock break has been issued
3319 * and the readraw request croses on the wire, we must
3320 * return a zero length response here.
3323 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3326 * We have to do a check_fsp by hand here, as
3327 * we must always return 4 zero bytes on error,
3328 * not a NTSTATUS.
3331 if (!fsp || !conn || conn != fsp->conn ||
3332 req->vuid != fsp->vuid ||
3333 fsp->is_directory || fsp->fh->fd == -1) {
3335 * fsp could be NULL here so use the value from the packet. JRA.
3337 DEBUG(3,("reply_readbraw: fnum %d not valid "
3338 "- cache prime?\n",
3339 (int)SVAL(req->vwv+0, 0)));
3340 reply_readbraw_error(sconn);
3341 END_PROFILE(SMBreadbraw);
3342 return;
3345 /* Do a "by hand" version of CHECK_READ. */
3346 if (!(fsp->can_read ||
3347 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3348 (fsp->access_mask & FILE_EXECUTE)))) {
3349 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3350 (int)SVAL(req->vwv+0, 0)));
3351 reply_readbraw_error(sconn);
3352 END_PROFILE(SMBreadbraw);
3353 return;
3356 flush_write_cache(fsp, READRAW_FLUSH);
3358 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3359 if(req->wct == 10) {
3361 * This is a large offset (64 bit) read.
3364 startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32);
3366 if(startpos < 0) {
3367 DEBUG(0,("reply_readbraw: negative 64 bit "
3368 "readraw offset (%.0f) !\n",
3369 (double)startpos ));
3370 reply_readbraw_error(sconn);
3371 END_PROFILE(SMBreadbraw);
3372 return;
3376 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3377 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3379 /* ensure we don't overrun the packet size */
3380 maxcount = MIN(65535,maxcount);
3382 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3383 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3384 &lock);
3386 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3387 reply_readbraw_error(sconn);
3388 END_PROFILE(SMBreadbraw);
3389 return;
3392 if (fsp_stat(fsp) == 0) {
3393 size = fsp->fsp_name->st.st_ex_size;
3396 if (startpos >= size) {
3397 nread = 0;
3398 } else {
3399 nread = MIN(maxcount,(size - startpos));
3402 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3403 if (nread < mincount)
3404 nread = 0;
3405 #endif
3407 DEBUG( 3, ( "reply_readbraw: %s start=%.0f max=%lu "
3408 "min=%lu nread=%lu\n",
3409 fsp_fnum_dbg(fsp), (double)startpos,
3410 (unsigned long)maxcount,
3411 (unsigned long)mincount,
3412 (unsigned long)nread ) );
3414 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3416 DEBUG(5,("reply_readbraw finished\n"));
3418 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3420 END_PROFILE(SMBreadbraw);
3421 return;
3424 #undef DBGC_CLASS
3425 #define DBGC_CLASS DBGC_LOCKING
3427 /****************************************************************************
3428 Reply to a lockread (core+ protocol).
3429 ****************************************************************************/
3431 void reply_lockread(struct smb_request *req)
3433 connection_struct *conn = req->conn;
3434 ssize_t nread = -1;
3435 char *data;
3436 off_t startpos;
3437 size_t numtoread;
3438 NTSTATUS status;
3439 files_struct *fsp;
3440 struct byte_range_lock *br_lck = NULL;
3441 char *p = NULL;
3442 struct smbd_server_connection *sconn = req->sconn;
3444 START_PROFILE(SMBlockread);
3446 if (req->wct < 5) {
3447 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3448 END_PROFILE(SMBlockread);
3449 return;
3452 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3454 if (!check_fsp(conn, req, fsp)) {
3455 END_PROFILE(SMBlockread);
3456 return;
3459 if (!CHECK_READ(fsp,req)) {
3460 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3461 END_PROFILE(SMBlockread);
3462 return;
3465 numtoread = SVAL(req->vwv+1, 0);
3466 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3468 numtoread = MIN(BUFFER_SIZE - (smb_size + 3*2 + 3), numtoread);
3470 reply_outbuf(req, 5, numtoread + 3);
3472 data = smb_buf(req->outbuf) + 3;
3475 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3476 * protocol request that predates the read/write lock concept.
3477 * Thus instead of asking for a read lock here we need to ask
3478 * for a write lock. JRA.
3479 * Note that the requested lock size is unaffected by max_recv.
3482 br_lck = do_lock(req->sconn->msg_ctx,
3483 fsp,
3484 (uint64_t)req->smbpid,
3485 (uint64_t)numtoread,
3486 (uint64_t)startpos,
3487 WRITE_LOCK,
3488 WINDOWS_LOCK,
3489 False, /* Non-blocking lock. */
3490 &status,
3491 NULL,
3492 NULL);
3493 TALLOC_FREE(br_lck);
3495 if (NT_STATUS_V(status)) {
3496 reply_nterror(req, status);
3497 END_PROFILE(SMBlockread);
3498 return;
3502 * However the requested READ size IS affected by max_recv. Insanity.... JRA.
3505 if (numtoread > sconn->smb1.negprot.max_recv) {
3506 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \
3507 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3508 (unsigned int)numtoread,
3509 (unsigned int)sconn->smb1.negprot.max_recv));
3510 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3512 nread = read_file(fsp,data,startpos,numtoread);
3514 if (nread < 0) {
3515 reply_nterror(req, map_nt_error_from_unix(errno));
3516 END_PROFILE(SMBlockread);
3517 return;
3520 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3522 SSVAL(req->outbuf,smb_vwv0,nread);
3523 SSVAL(req->outbuf,smb_vwv5,nread+3);
3524 p = smb_buf(req->outbuf);
3525 SCVAL(p,0,0); /* pad byte. */
3526 SSVAL(p,1,nread);
3528 DEBUG(3,("lockread %s num=%d nread=%d\n",
3529 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3531 END_PROFILE(SMBlockread);
3532 return;
3535 #undef DBGC_CLASS
3536 #define DBGC_CLASS DBGC_ALL
3538 /****************************************************************************
3539 Reply to a read.
3540 ****************************************************************************/
3542 void reply_read(struct smb_request *req)
3544 connection_struct *conn = req->conn;
3545 size_t numtoread;
3546 ssize_t nread = 0;
3547 char *data;
3548 off_t startpos;
3549 int outsize = 0;
3550 files_struct *fsp;
3551 struct lock_struct lock;
3552 struct smbd_server_connection *sconn = req->sconn;
3554 START_PROFILE(SMBread);
3556 if (req->wct < 3) {
3557 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3558 END_PROFILE(SMBread);
3559 return;
3562 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3564 if (!check_fsp(conn, req, fsp)) {
3565 END_PROFILE(SMBread);
3566 return;
3569 if (!CHECK_READ(fsp,req)) {
3570 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3571 END_PROFILE(SMBread);
3572 return;
3575 numtoread = SVAL(req->vwv+1, 0);
3576 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3578 numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
3581 * The requested read size cannot be greater than max_recv. JRA.
3583 if (numtoread > sconn->smb1.negprot.max_recv) {
3584 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \
3585 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3586 (unsigned int)numtoread,
3587 (unsigned int)sconn->smb1.negprot.max_recv));
3588 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3591 reply_outbuf(req, 5, numtoread+3);
3593 data = smb_buf(req->outbuf) + 3;
3595 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3596 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3597 &lock);
3599 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3600 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3601 END_PROFILE(SMBread);
3602 return;
3605 if (numtoread > 0)
3606 nread = read_file(fsp,data,startpos,numtoread);
3608 if (nread < 0) {
3609 reply_nterror(req, map_nt_error_from_unix(errno));
3610 goto strict_unlock;
3613 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3615 SSVAL(req->outbuf,smb_vwv0,nread);
3616 SSVAL(req->outbuf,smb_vwv5,nread+3);
3617 SCVAL(smb_buf(req->outbuf),0,1);
3618 SSVAL(smb_buf(req->outbuf),1,nread);
3620 DEBUG(3, ("read %s num=%d nread=%d\n",
3621 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3623 strict_unlock:
3624 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3626 END_PROFILE(SMBread);
3627 return;
3630 /****************************************************************************
3631 Setup readX header.
3632 ****************************************************************************/
3634 static int setup_readX_header(struct smb_request *req, char *outbuf,
3635 size_t smb_maxcnt)
3637 int outsize;
3639 outsize = srv_set_message(outbuf,12,smb_maxcnt,False);
3641 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3643 SCVAL(outbuf,smb_vwv0,0xFF);
3644 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3645 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3646 SSVAL(outbuf,smb_vwv6,
3647 (smb_wct - 4) /* offset from smb header to wct */
3648 + 1 /* the wct field */
3649 + 12 * sizeof(uint16_t) /* vwv */
3650 + 2); /* the buflen field */
3651 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3652 SSVAL(outbuf,smb_vwv11,smb_maxcnt);
3653 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3654 _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
3655 return outsize;
3658 /****************************************************************************
3659 Reply to a read and X - possibly using sendfile.
3660 ****************************************************************************/
3662 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3663 files_struct *fsp, off_t startpos,
3664 size_t smb_maxcnt)
3666 ssize_t nread = -1;
3667 struct lock_struct lock;
3668 int saved_errno = 0;
3670 if(fsp_stat(fsp) == -1) {
3671 reply_nterror(req, map_nt_error_from_unix(errno));
3672 return;
3675 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3676 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3677 &lock);
3679 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3680 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3681 return;
3684 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3685 (startpos > fsp->fsp_name->st.st_ex_size)
3686 || (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3688 * We already know that we would do a short read, so don't
3689 * try the sendfile() path.
3691 goto nosendfile_read;
3695 * We can only use sendfile on a non-chained packet
3696 * but we can use on a non-oplocked file. tridge proved this
3697 * on a train in Germany :-). JRA.
3700 if (!req_is_in_chain(req) &&
3701 !is_encrypted_packet(req->sconn, req->inbuf) &&
3702 (fsp->base_fsp == NULL) &&
3703 (fsp->wcp == NULL) &&
3704 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3705 uint8 headerbuf[smb_size + 12 * 2];
3706 DATA_BLOB header;
3709 * Set up the packet header before send. We
3710 * assume here the sendfile will work (get the
3711 * correct amount of data).
3714 header = data_blob_const(headerbuf, sizeof(headerbuf));
3716 construct_reply_common_req(req, (char *)headerbuf);
3717 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3719 nread = SMB_VFS_SENDFILE(req->sconn->sock, fsp, &header,
3720 startpos, smb_maxcnt);
3721 if (nread == -1) {
3722 /* Returning ENOSYS means no data at all was sent.
3723 Do this as a normal read. */
3724 if (errno == ENOSYS) {
3725 goto normal_read;
3729 * Special hack for broken Linux with no working sendfile. If we
3730 * return EINTR we sent the header but not the rest of the data.
3731 * Fake this up by doing read/write calls.
3734 if (errno == EINTR) {
3735 /* Ensure we don't do this again. */
3736 set_use_sendfile(SNUM(conn), False);
3737 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3738 nread = fake_sendfile(fsp, startpos,
3739 smb_maxcnt);
3740 if (nread == -1) {
3741 DEBUG(0,("send_file_readX: "
3742 "fake_sendfile failed for "
3743 "file %s (%s).\n",
3744 fsp_str_dbg(fsp),
3745 strerror(errno)));
3746 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3748 DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
3749 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3750 /* No outbuf here means successful sendfile. */
3751 goto strict_unlock;
3754 DEBUG(0,("send_file_readX: sendfile failed for file "
3755 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3756 strerror(errno)));
3757 exit_server_cleanly("send_file_readX sendfile failed");
3758 } else if (nread == 0) {
3760 * Some sendfile implementations return 0 to indicate
3761 * that there was a short read, but nothing was
3762 * actually written to the socket. In this case,
3763 * fallback to the normal read path so the header gets
3764 * the correct byte count.
3766 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
3767 "falling back to the normal read: %s\n",
3768 fsp_str_dbg(fsp)));
3769 goto normal_read;
3772 DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n",
3773 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3775 /* Deal with possible short send. */
3776 if (nread != smb_maxcnt + sizeof(headerbuf)) {
3777 sendfile_short_send(fsp, nread, sizeof(headerbuf), smb_maxcnt);
3779 /* No outbuf here means successful sendfile. */
3780 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
3781 SMB_PERFCOUNT_END(&req->pcd);
3782 goto strict_unlock;
3785 normal_read:
3787 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3788 uint8 headerbuf[smb_size + 2*12];
3790 construct_reply_common_req(req, (char *)headerbuf);
3791 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3793 /* Send out the header. */
3794 if (write_data(req->sconn->sock, (char *)headerbuf,
3795 sizeof(headerbuf)) != sizeof(headerbuf)) {
3797 char addr[INET6_ADDRSTRLEN];
3799 * Try and give an error message saying what
3800 * client failed.
3802 DEBUG(0, ("write_data failed for client %s. "
3803 "Error %s\n",
3804 get_peer_addr(req->sconn->sock, addr,
3805 sizeof(addr)),
3806 strerror(errno)));
3808 DEBUG(0,("send_file_readX: write_data failed for file "
3809 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3810 strerror(errno)));
3811 exit_server_cleanly("send_file_readX sendfile failed");
3813 nread = fake_sendfile(fsp, startpos, smb_maxcnt);
3814 if (nread == -1) {
3815 DEBUG(0,("send_file_readX: fake_sendfile failed for "
3816 "file %s (%s).\n", fsp_str_dbg(fsp),
3817 strerror(errno)));
3818 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3820 goto strict_unlock;
3823 nosendfile_read:
3825 reply_outbuf(req, 12, smb_maxcnt);
3826 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
3827 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
3829 nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt);
3830 saved_errno = errno;
3832 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3834 if (nread < 0) {
3835 reply_nterror(req, map_nt_error_from_unix(saved_errno));
3836 return;
3839 setup_readX_header(req, (char *)req->outbuf, nread);
3841 DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
3842 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3843 return;
3845 strict_unlock:
3846 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3847 TALLOC_FREE(req->outbuf);
3848 return;
3851 /****************************************************************************
3852 Reply to a read and X.
3853 ****************************************************************************/
3855 void reply_read_and_X(struct smb_request *req)
3857 struct smbd_server_connection *sconn = req->sconn;
3858 connection_struct *conn = req->conn;
3859 files_struct *fsp;
3860 off_t startpos;
3861 size_t smb_maxcnt;
3862 bool big_readX = False;
3863 #if 0
3864 size_t smb_mincnt = SVAL(req->vwv+6, 0);
3865 #endif
3867 START_PROFILE(SMBreadX);
3869 if ((req->wct != 10) && (req->wct != 12)) {
3870 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3871 return;
3874 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
3875 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3876 smb_maxcnt = SVAL(req->vwv+5, 0);
3878 /* If it's an IPC, pass off the pipe handler. */
3879 if (IS_IPC(conn)) {
3880 reply_pipe_read_and_X(req);
3881 END_PROFILE(SMBreadX);
3882 return;
3885 if (!check_fsp(conn, req, fsp)) {
3886 END_PROFILE(SMBreadX);
3887 return;
3890 if (!CHECK_READ(fsp,req)) {
3891 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3892 END_PROFILE(SMBreadX);
3893 return;
3896 if ((sconn->smb1.unix_info.client_cap_low & CIFS_UNIX_LARGE_READ_CAP) ||
3897 (get_remote_arch() == RA_SAMBA)) {
3899 * This is Samba only behavior (up to Samba 3.6)!
3901 * Windows 2008 R2 ignores the upper_size,
3902 * so we do unless unix extentions are active
3903 * or "smbclient" is talking to us.
3905 size_t upper_size = SVAL(req->vwv+7, 0);
3906 smb_maxcnt |= (upper_size<<16);
3907 if (upper_size > 1) {
3908 /* Can't do this on a chained packet. */
3909 if ((CVAL(req->vwv+0, 0) != 0xFF)) {
3910 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3911 END_PROFILE(SMBreadX);
3912 return;
3914 /* We currently don't do this on signed or sealed data. */
3915 if (srv_is_signing_active(req->sconn) ||
3916 is_encrypted_packet(req->sconn, req->inbuf)) {
3917 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3918 END_PROFILE(SMBreadX);
3919 return;
3921 /* Is there room in the reply for this data ? */
3922 if (smb_maxcnt > (0xFFFFFF - (smb_size -4 + 12*2))) {
3923 reply_nterror(req,
3924 NT_STATUS_INVALID_PARAMETER);
3925 END_PROFILE(SMBreadX);
3926 return;
3928 big_readX = True;
3932 if (req->wct == 12) {
3934 * This is a large offset (64 bit) read.
3936 startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
3940 if (!big_readX) {
3941 NTSTATUS status = schedule_aio_read_and_X(conn,
3942 req,
3943 fsp,
3944 startpos,
3945 smb_maxcnt);
3946 if (NT_STATUS_IS_OK(status)) {
3947 /* Read scheduled - we're done. */
3948 goto out;
3950 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
3951 /* Real error - report to client. */
3952 END_PROFILE(SMBreadX);
3953 reply_nterror(req, status);
3954 return;
3956 /* NT_STATUS_RETRY - fall back to sync read. */
3959 smbd_lock_socket(req->sconn);
3960 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
3961 smbd_unlock_socket(req->sconn);
3963 out:
3964 END_PROFILE(SMBreadX);
3965 return;
3968 /****************************************************************************
3969 Error replies to writebraw must have smb_wct == 1. Fix this up.
3970 ****************************************************************************/
3972 void error_to_writebrawerr(struct smb_request *req)
3974 uint8 *old_outbuf = req->outbuf;
3976 reply_outbuf(req, 1, 0);
3978 memcpy(req->outbuf, old_outbuf, smb_size);
3979 TALLOC_FREE(old_outbuf);
3982 /****************************************************************************
3983 Read 4 bytes of a smb packet and return the smb length of the packet.
3984 Store the result in the buffer. This version of the function will
3985 never return a session keepalive (length of zero).
3986 Timeout is in milliseconds.
3987 ****************************************************************************/
3989 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
3990 size_t *len)
3992 uint8_t msgtype = NBSSkeepalive;
3994 while (msgtype == NBSSkeepalive) {
3995 NTSTATUS status;
3997 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
3998 len);
3999 if (!NT_STATUS_IS_OK(status)) {
4000 char addr[INET6_ADDRSTRLEN];
4001 /* Try and give an error message
4002 * saying what client failed. */
4003 DEBUG(0, ("read_fd_with_timeout failed for "
4004 "client %s read error = %s.\n",
4005 get_peer_addr(fd,addr,sizeof(addr)),
4006 nt_errstr(status)));
4007 return status;
4010 msgtype = CVAL(inbuf, 0);
4013 DEBUG(10,("read_smb_length: got smb length of %lu\n",
4014 (unsigned long)len));
4016 return NT_STATUS_OK;
4019 /****************************************************************************
4020 Reply to a writebraw (core+ or LANMAN1.0 protocol).
4021 ****************************************************************************/
4023 void reply_writebraw(struct smb_request *req)
4025 connection_struct *conn = req->conn;
4026 char *buf = NULL;
4027 ssize_t nwritten=0;
4028 ssize_t total_written=0;
4029 size_t numtowrite=0;
4030 size_t tcount;
4031 off_t startpos;
4032 const char *data=NULL;
4033 bool write_through;
4034 files_struct *fsp;
4035 struct lock_struct lock;
4036 NTSTATUS status;
4038 START_PROFILE(SMBwritebraw);
4041 * If we ever reply with an error, it must have the SMB command
4042 * type of SMBwritec, not SMBwriteBraw, as this tells the client
4043 * we're finished.
4045 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
4047 if (srv_is_signing_active(req->sconn)) {
4048 END_PROFILE(SMBwritebraw);
4049 exit_server_cleanly("reply_writebraw: SMB signing is active - "
4050 "raw reads/writes are disallowed.");
4053 if (req->wct < 12) {
4054 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4055 error_to_writebrawerr(req);
4056 END_PROFILE(SMBwritebraw);
4057 return;
4060 if (req->sconn->smb1.echo_handler.trusted_fde) {
4061 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
4062 "'async smb echo handler = yes'\n"));
4063 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
4064 error_to_writebrawerr(req);
4065 END_PROFILE(SMBwritebraw);
4066 return;
4069 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4070 if (!check_fsp(conn, req, fsp)) {
4071 error_to_writebrawerr(req);
4072 END_PROFILE(SMBwritebraw);
4073 return;
4076 if (!CHECK_WRITE(fsp)) {
4077 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4078 error_to_writebrawerr(req);
4079 END_PROFILE(SMBwritebraw);
4080 return;
4083 tcount = IVAL(req->vwv+1, 0);
4084 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4085 write_through = BITSETW(req->vwv+7,0);
4087 /* We have to deal with slightly different formats depending
4088 on whether we are using the core+ or lanman1.0 protocol */
4090 if(get_Protocol() <= PROTOCOL_COREPLUS) {
4091 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
4092 data = smb_buf_const(req->inbuf);
4093 } else {
4094 numtowrite = SVAL(req->vwv+10, 0);
4095 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
4098 /* Ensure we don't write bytes past the end of this packet. */
4099 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
4100 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4101 error_to_writebrawerr(req);
4102 END_PROFILE(SMBwritebraw);
4103 return;
4106 if (!fsp->print_file) {
4107 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4108 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4109 &lock);
4111 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4112 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4113 error_to_writebrawerr(req);
4114 END_PROFILE(SMBwritebraw);
4115 return;
4119 if (numtowrite>0) {
4120 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4123 DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d "
4124 "wrote=%d sync=%d\n",
4125 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4126 (int)nwritten, (int)write_through));
4128 if (nwritten < (ssize_t)numtowrite) {
4129 reply_nterror(req, NT_STATUS_DISK_FULL);
4130 error_to_writebrawerr(req);
4131 goto strict_unlock;
4134 total_written = nwritten;
4136 /* Allocate a buffer of 64k + length. */
4137 buf = talloc_array(NULL, char, 65540);
4138 if (!buf) {
4139 reply_nterror(req, NT_STATUS_NO_MEMORY);
4140 error_to_writebrawerr(req);
4141 goto strict_unlock;
4144 /* Return a SMBwritebraw message to the redirector to tell
4145 * it to send more bytes */
4147 memcpy(buf, req->inbuf, smb_size);
4148 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4149 SCVAL(buf,smb_com,SMBwritebraw);
4150 SSVALS(buf,smb_vwv0,0xFFFF);
4151 show_msg(buf);
4152 if (!srv_send_smb(req->sconn,
4153 buf,
4154 false, 0, /* no signing */
4155 IS_CONN_ENCRYPTED(conn),
4156 &req->pcd)) {
4157 exit_server_cleanly("reply_writebraw: srv_send_smb "
4158 "failed.");
4161 /* Now read the raw data into the buffer and write it */
4162 status = read_smb_length(req->sconn->sock, buf, SMB_SECONDARY_WAIT,
4163 &numtowrite);
4164 if (!NT_STATUS_IS_OK(status)) {
4165 exit_server_cleanly("secondary writebraw failed");
4168 /* Set up outbuf to return the correct size */
4169 reply_outbuf(req, 1, 0);
4171 if (numtowrite != 0) {
4173 if (numtowrite > 0xFFFF) {
4174 DEBUG(0,("reply_writebraw: Oversize secondary write "
4175 "raw requested (%u). Terminating\n",
4176 (unsigned int)numtowrite ));
4177 exit_server_cleanly("secondary writebraw failed");
4180 if (tcount > nwritten+numtowrite) {
4181 DEBUG(3,("reply_writebraw: Client overestimated the "
4182 "write %d %d %d\n",
4183 (int)tcount,(int)nwritten,(int)numtowrite));
4186 status = read_data(req->sconn->sock, buf+4, numtowrite);
4188 if (!NT_STATUS_IS_OK(status)) {
4189 char addr[INET6_ADDRSTRLEN];
4190 /* Try and give an error message
4191 * saying what client failed. */
4192 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4193 "raw read failed (%s) for client %s. "
4194 "Terminating\n", nt_errstr(status),
4195 get_peer_addr(req->sconn->sock, addr,
4196 sizeof(addr))));
4197 exit_server_cleanly("secondary writebraw failed");
4200 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4201 if (nwritten == -1) {
4202 TALLOC_FREE(buf);
4203 reply_nterror(req, map_nt_error_from_unix(errno));
4204 error_to_writebrawerr(req);
4205 goto strict_unlock;
4208 if (nwritten < (ssize_t)numtowrite) {
4209 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4210 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4213 if (nwritten > 0) {
4214 total_written += nwritten;
4218 TALLOC_FREE(buf);
4219 SSVAL(req->outbuf,smb_vwv0,total_written);
4221 status = sync_file(conn, fsp, write_through);
4222 if (!NT_STATUS_IS_OK(status)) {
4223 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4224 fsp_str_dbg(fsp), nt_errstr(status)));
4225 reply_nterror(req, status);
4226 error_to_writebrawerr(req);
4227 goto strict_unlock;
4230 DEBUG(3,("reply_writebraw: secondart write %s start=%.0f num=%d "
4231 "wrote=%d\n",
4232 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4233 (int)total_written));
4235 if (!fsp->print_file) {
4236 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4239 /* We won't return a status if write through is not selected - this
4240 * follows what WfWg does */
4241 END_PROFILE(SMBwritebraw);
4243 if (!write_through && total_written==tcount) {
4245 #if RABBIT_PELLET_FIX
4247 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4248 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4249 * JRA.
4251 if (!send_keepalive(req->sconn->sock)) {
4252 exit_server_cleanly("reply_writebraw: send of "
4253 "keepalive failed");
4255 #endif
4256 TALLOC_FREE(req->outbuf);
4258 return;
4260 strict_unlock:
4261 if (!fsp->print_file) {
4262 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4265 END_PROFILE(SMBwritebraw);
4266 return;
4269 #undef DBGC_CLASS
4270 #define DBGC_CLASS DBGC_LOCKING
4272 /****************************************************************************
4273 Reply to a writeunlock (core+).
4274 ****************************************************************************/
4276 void reply_writeunlock(struct smb_request *req)
4278 connection_struct *conn = req->conn;
4279 ssize_t nwritten = -1;
4280 size_t numtowrite;
4281 off_t startpos;
4282 const char *data;
4283 NTSTATUS status = NT_STATUS_OK;
4284 files_struct *fsp;
4285 struct lock_struct lock;
4286 int saved_errno = 0;
4288 START_PROFILE(SMBwriteunlock);
4290 if (req->wct < 5) {
4291 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4292 END_PROFILE(SMBwriteunlock);
4293 return;
4296 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4298 if (!check_fsp(conn, req, fsp)) {
4299 END_PROFILE(SMBwriteunlock);
4300 return;
4303 if (!CHECK_WRITE(fsp)) {
4304 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4305 END_PROFILE(SMBwriteunlock);
4306 return;
4309 numtowrite = SVAL(req->vwv+1, 0);
4310 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4311 data = (const char *)req->buf + 3;
4313 if (!fsp->print_file && numtowrite > 0) {
4314 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4315 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4316 &lock);
4318 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4319 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4320 END_PROFILE(SMBwriteunlock);
4321 return;
4325 /* The special X/Open SMB protocol handling of
4326 zero length writes is *NOT* done for
4327 this call */
4328 if(numtowrite == 0) {
4329 nwritten = 0;
4330 } else {
4331 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4332 saved_errno = errno;
4335 status = sync_file(conn, fsp, False /* write through */);
4336 if (!NT_STATUS_IS_OK(status)) {
4337 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4338 fsp_str_dbg(fsp), nt_errstr(status)));
4339 reply_nterror(req, status);
4340 goto strict_unlock;
4343 if(nwritten < 0) {
4344 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4345 goto strict_unlock;
4348 if((nwritten < numtowrite) && (numtowrite != 0)) {
4349 reply_nterror(req, NT_STATUS_DISK_FULL);
4350 goto strict_unlock;
4353 if (numtowrite && !fsp->print_file) {
4354 status = do_unlock(req->sconn->msg_ctx,
4355 fsp,
4356 (uint64_t)req->smbpid,
4357 (uint64_t)numtowrite,
4358 (uint64_t)startpos,
4359 WINDOWS_LOCK);
4361 if (NT_STATUS_V(status)) {
4362 reply_nterror(req, status);
4363 goto strict_unlock;
4367 reply_outbuf(req, 1, 0);
4369 SSVAL(req->outbuf,smb_vwv0,nwritten);
4371 DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
4372 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4374 strict_unlock:
4375 if (numtowrite && !fsp->print_file) {
4376 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4379 END_PROFILE(SMBwriteunlock);
4380 return;
4383 #undef DBGC_CLASS
4384 #define DBGC_CLASS DBGC_ALL
4386 /****************************************************************************
4387 Reply to a write.
4388 ****************************************************************************/
4390 void reply_write(struct smb_request *req)
4392 connection_struct *conn = req->conn;
4393 size_t numtowrite;
4394 ssize_t nwritten = -1;
4395 off_t startpos;
4396 const char *data;
4397 files_struct *fsp;
4398 struct lock_struct lock;
4399 NTSTATUS status;
4400 int saved_errno = 0;
4402 START_PROFILE(SMBwrite);
4404 if (req->wct < 5) {
4405 END_PROFILE(SMBwrite);
4406 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4407 return;
4410 /* If it's an IPC, pass off the pipe handler. */
4411 if (IS_IPC(conn)) {
4412 reply_pipe_write(req);
4413 END_PROFILE(SMBwrite);
4414 return;
4417 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4419 if (!check_fsp(conn, req, fsp)) {
4420 END_PROFILE(SMBwrite);
4421 return;
4424 if (!CHECK_WRITE(fsp)) {
4425 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4426 END_PROFILE(SMBwrite);
4427 return;
4430 numtowrite = SVAL(req->vwv+1, 0);
4431 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4432 data = (const char *)req->buf + 3;
4434 if (!fsp->print_file) {
4435 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4436 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4437 &lock);
4439 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4440 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4441 END_PROFILE(SMBwrite);
4442 return;
4447 * X/Open SMB protocol says that if smb_vwv1 is
4448 * zero then the file size should be extended or
4449 * truncated to the size given in smb_vwv[2-3].
4452 if(numtowrite == 0) {
4454 * This is actually an allocate call, and set EOF. JRA.
4456 nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
4457 if (nwritten < 0) {
4458 reply_nterror(req, NT_STATUS_DISK_FULL);
4459 goto strict_unlock;
4461 nwritten = vfs_set_filelen(fsp, (off_t)startpos);
4462 if (nwritten < 0) {
4463 reply_nterror(req, NT_STATUS_DISK_FULL);
4464 goto strict_unlock;
4466 trigger_write_time_update_immediate(fsp);
4467 } else {
4468 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4471 status = sync_file(conn, fsp, False);
4472 if (!NT_STATUS_IS_OK(status)) {
4473 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4474 fsp_str_dbg(fsp), nt_errstr(status)));
4475 reply_nterror(req, status);
4476 goto strict_unlock;
4479 if(nwritten < 0) {
4480 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4481 goto strict_unlock;
4484 if((nwritten == 0) && (numtowrite != 0)) {
4485 reply_nterror(req, NT_STATUS_DISK_FULL);
4486 goto strict_unlock;
4489 reply_outbuf(req, 1, 0);
4491 SSVAL(req->outbuf,smb_vwv0,nwritten);
4493 if (nwritten < (ssize_t)numtowrite) {
4494 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4495 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4498 DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4500 strict_unlock:
4501 if (!fsp->print_file) {
4502 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4505 END_PROFILE(SMBwrite);
4506 return;
4509 /****************************************************************************
4510 Ensure a buffer is a valid writeX for recvfile purposes.
4511 ****************************************************************************/
4513 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4514 (2*14) + /* word count (including bcc) */ \
4515 1 /* pad byte */)
4517 bool is_valid_writeX_buffer(struct smbd_server_connection *sconn,
4518 const uint8_t *inbuf)
4520 size_t numtowrite;
4521 connection_struct *conn = NULL;
4522 unsigned int doff = 0;
4523 size_t len = smb_len_large(inbuf);
4524 struct smbXsrv_tcon *tcon;
4525 NTSTATUS status;
4526 NTTIME now = 0;
4528 if (is_encrypted_packet(sconn, inbuf)) {
4529 /* Can't do this on encrypted
4530 * connections. */
4531 return false;
4534 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4535 return false;
4538 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4539 CVAL(inbuf,smb_wct) != 14) {
4540 DEBUG(10,("is_valid_writeX_buffer: chained or "
4541 "invalid word length.\n"));
4542 return false;
4545 status = smb1srv_tcon_lookup(sconn->conn, SVAL(inbuf, smb_tid),
4546 now, &tcon);
4547 if (!NT_STATUS_IS_OK(status)) {
4548 DEBUG(10,("is_valid_writeX_buffer: bad tid\n"));
4549 return false;
4551 conn = tcon->compat;
4553 if (IS_IPC(conn)) {
4554 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4555 return false;
4557 if (IS_PRINT(conn)) {
4558 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4559 return false;
4561 doff = SVAL(inbuf,smb_vwv11);
4563 numtowrite = SVAL(inbuf,smb_vwv10);
4565 if (len > doff && len - doff > 0xFFFF) {
4566 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4569 if (numtowrite == 0) {
4570 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4571 return false;
4574 /* Ensure the sizes match up. */
4575 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4576 /* no pad byte...old smbclient :-( */
4577 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4578 (unsigned int)doff,
4579 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4580 return false;
4583 if (len - doff != numtowrite) {
4584 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4585 "len = %u, doff = %u, numtowrite = %u\n",
4586 (unsigned int)len,
4587 (unsigned int)doff,
4588 (unsigned int)numtowrite ));
4589 return false;
4592 DEBUG(10,("is_valid_writeX_buffer: true "
4593 "len = %u, doff = %u, numtowrite = %u\n",
4594 (unsigned int)len,
4595 (unsigned int)doff,
4596 (unsigned int)numtowrite ));
4598 return true;
4601 /****************************************************************************
4602 Reply to a write and X.
4603 ****************************************************************************/
4605 void reply_write_and_X(struct smb_request *req)
4607 connection_struct *conn = req->conn;
4608 files_struct *fsp;
4609 struct lock_struct lock;
4610 off_t startpos;
4611 size_t numtowrite;
4612 bool write_through;
4613 ssize_t nwritten;
4614 unsigned int smb_doff;
4615 unsigned int smblen;
4616 const char *data;
4617 NTSTATUS status;
4618 int saved_errno = 0;
4620 START_PROFILE(SMBwriteX);
4622 if ((req->wct != 12) && (req->wct != 14)) {
4623 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4624 goto out;
4627 numtowrite = SVAL(req->vwv+10, 0);
4628 smb_doff = SVAL(req->vwv+11, 0);
4629 smblen = smb_len(req->inbuf);
4631 if (req->unread_bytes > 0xFFFF ||
4632 (smblen > smb_doff &&
4633 smblen - smb_doff > 0xFFFF)) {
4634 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
4637 if (req->unread_bytes) {
4638 /* Can't do a recvfile write on IPC$ */
4639 if (IS_IPC(conn)) {
4640 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4641 goto out;
4643 if (numtowrite != req->unread_bytes) {
4644 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4645 goto out;
4647 } else {
4648 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4649 smb_doff + numtowrite > smblen) {
4650 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4651 goto out;
4655 /* If it's an IPC, pass off the pipe handler. */
4656 if (IS_IPC(conn)) {
4657 if (req->unread_bytes) {
4658 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4659 goto out;
4661 reply_pipe_write_and_X(req);
4662 goto out;
4665 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4666 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4667 write_through = BITSETW(req->vwv+7,0);
4669 if (!check_fsp(conn, req, fsp)) {
4670 goto out;
4673 if (!CHECK_WRITE(fsp)) {
4674 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4675 goto out;
4678 data = smb_base(req->inbuf) + smb_doff;
4680 if(req->wct == 14) {
4682 * This is a large offset (64 bit) write.
4684 startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
4688 /* X/Open SMB protocol says that, unlike SMBwrite
4689 if the length is zero then NO truncation is
4690 done, just a write of zero. To truncate a file,
4691 use SMBwrite. */
4693 if(numtowrite == 0) {
4694 nwritten = 0;
4695 } else {
4696 if (req->unread_bytes == 0) {
4697 status = schedule_aio_write_and_X(conn,
4698 req,
4699 fsp,
4700 data,
4701 startpos,
4702 numtowrite);
4704 if (NT_STATUS_IS_OK(status)) {
4705 /* write scheduled - we're done. */
4706 goto out;
4708 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4709 /* Real error - report to client. */
4710 reply_nterror(req, status);
4711 goto out;
4713 /* NT_STATUS_RETRY - fall through to sync write. */
4716 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4717 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4718 &lock);
4720 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4721 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4722 goto out;
4725 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4726 saved_errno = errno;
4728 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4731 if(nwritten < 0) {
4732 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4733 goto out;
4736 if((nwritten == 0) && (numtowrite != 0)) {
4737 reply_nterror(req, NT_STATUS_DISK_FULL);
4738 goto out;
4741 reply_outbuf(req, 6, 0);
4742 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
4743 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
4744 SSVAL(req->outbuf,smb_vwv2,nwritten);
4745 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4747 DEBUG(3,("writeX %s num=%d wrote=%d\n",
4748 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4750 status = sync_file(conn, fsp, write_through);
4751 if (!NT_STATUS_IS_OK(status)) {
4752 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4753 fsp_str_dbg(fsp), nt_errstr(status)));
4754 reply_nterror(req, status);
4755 goto out;
4758 END_PROFILE(SMBwriteX);
4759 return;
4761 out:
4762 if (req->unread_bytes) {
4763 /* writeX failed. drain socket. */
4764 if (drain_socket(req->sconn->sock, req->unread_bytes) !=
4765 req->unread_bytes) {
4766 smb_panic("failed to drain pending bytes");
4768 req->unread_bytes = 0;
4771 END_PROFILE(SMBwriteX);
4772 return;
4775 /****************************************************************************
4776 Reply to a lseek.
4777 ****************************************************************************/
4779 void reply_lseek(struct smb_request *req)
4781 connection_struct *conn = req->conn;
4782 off_t startpos;
4783 off_t res= -1;
4784 int mode,umode;
4785 files_struct *fsp;
4787 START_PROFILE(SMBlseek);
4789 if (req->wct < 4) {
4790 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4791 END_PROFILE(SMBlseek);
4792 return;
4795 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4797 if (!check_fsp(conn, req, fsp)) {
4798 return;
4801 flush_write_cache(fsp, SEEK_FLUSH);
4803 mode = SVAL(req->vwv+1, 0) & 3;
4804 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4805 startpos = (off_t)IVALS(req->vwv+2, 0);
4807 switch (mode) {
4808 case 0:
4809 umode = SEEK_SET;
4810 res = startpos;
4811 break;
4812 case 1:
4813 umode = SEEK_CUR;
4814 res = fsp->fh->pos + startpos;
4815 break;
4816 case 2:
4817 umode = SEEK_END;
4818 break;
4819 default:
4820 umode = SEEK_SET;
4821 res = startpos;
4822 break;
4825 if (umode == SEEK_END) {
4826 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
4827 if(errno == EINVAL) {
4828 off_t current_pos = startpos;
4830 if(fsp_stat(fsp) == -1) {
4831 reply_nterror(req,
4832 map_nt_error_from_unix(errno));
4833 END_PROFILE(SMBlseek);
4834 return;
4837 current_pos += fsp->fsp_name->st.st_ex_size;
4838 if(current_pos < 0)
4839 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
4843 if(res == -1) {
4844 reply_nterror(req, map_nt_error_from_unix(errno));
4845 END_PROFILE(SMBlseek);
4846 return;
4850 fsp->fh->pos = res;
4852 reply_outbuf(req, 2, 0);
4853 SIVAL(req->outbuf,smb_vwv0,res);
4855 DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n",
4856 fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode));
4858 END_PROFILE(SMBlseek);
4859 return;
4862 /****************************************************************************
4863 Reply to a flush.
4864 ****************************************************************************/
4866 void reply_flush(struct smb_request *req)
4868 connection_struct *conn = req->conn;
4869 uint16 fnum;
4870 files_struct *fsp;
4872 START_PROFILE(SMBflush);
4874 if (req->wct < 1) {
4875 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4876 return;
4879 fnum = SVAL(req->vwv+0, 0);
4880 fsp = file_fsp(req, fnum);
4882 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
4883 return;
4886 if (!fsp) {
4887 file_sync_all(conn);
4888 } else {
4889 NTSTATUS status = sync_file(conn, fsp, True);
4890 if (!NT_STATUS_IS_OK(status)) {
4891 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
4892 fsp_str_dbg(fsp), nt_errstr(status)));
4893 reply_nterror(req, status);
4894 END_PROFILE(SMBflush);
4895 return;
4899 reply_outbuf(req, 0, 0);
4901 DEBUG(3,("flush\n"));
4902 END_PROFILE(SMBflush);
4903 return;
4906 /****************************************************************************
4907 Reply to a exit.
4908 conn POINTER CAN BE NULL HERE !
4909 ****************************************************************************/
4911 void reply_exit(struct smb_request *req)
4913 START_PROFILE(SMBexit);
4915 file_close_pid(req->sconn, req->smbpid, req->vuid);
4917 reply_outbuf(req, 0, 0);
4919 DEBUG(3,("exit\n"));
4921 END_PROFILE(SMBexit);
4922 return;
4925 struct reply_close_state {
4926 files_struct *fsp;
4927 struct smb_request *smbreq;
4930 static void do_smb1_close(struct tevent_req *req);
4932 void reply_close(struct smb_request *req)
4934 connection_struct *conn = req->conn;
4935 NTSTATUS status = NT_STATUS_OK;
4936 files_struct *fsp = NULL;
4937 START_PROFILE(SMBclose);
4939 if (req->wct < 3) {
4940 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4941 END_PROFILE(SMBclose);
4942 return;
4945 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4948 * We can only use check_fsp if we know it's not a directory.
4951 if (!check_fsp_open(conn, req, fsp)) {
4952 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
4953 END_PROFILE(SMBclose);
4954 return;
4957 DEBUG(3, ("Close %s fd=%d %s (numopen=%d)\n",
4958 fsp->is_directory ? "directory" : "file",
4959 fsp->fh->fd, fsp_fnum_dbg(fsp),
4960 conn->num_files_open));
4962 if (!fsp->is_directory) {
4963 time_t t;
4966 * Take care of any time sent in the close.
4969 t = srv_make_unix_date3(req->vwv+1);
4970 set_close_write_time(fsp, convert_time_t_to_timespec(t));
4973 if (fsp->num_aio_requests != 0) {
4975 struct reply_close_state *state;
4977 DEBUG(10, ("closing with aio %u requests pending\n",
4978 fsp->num_aio_requests));
4981 * We depend on the aio_extra destructor to take care of this
4982 * close request once fsp->num_aio_request drops to 0.
4985 fsp->deferred_close = tevent_wait_send(
4986 fsp, fsp->conn->sconn->ev_ctx);
4987 if (fsp->deferred_close == NULL) {
4988 status = NT_STATUS_NO_MEMORY;
4989 goto done;
4992 state = talloc(fsp, struct reply_close_state);
4993 if (state == NULL) {
4994 TALLOC_FREE(fsp->deferred_close);
4995 status = NT_STATUS_NO_MEMORY;
4996 goto done;
4998 state->fsp = fsp;
4999 state->smbreq = talloc_move(fsp, &req);
5000 tevent_req_set_callback(fsp->deferred_close, do_smb1_close,
5001 state);
5002 END_PROFILE(SMBclose);
5003 return;
5007 * close_file() returns the unix errno if an error was detected on
5008 * close - normally this is due to a disk full error. If not then it
5009 * was probably an I/O error.
5012 status = close_file(req, fsp, NORMAL_CLOSE);
5013 done:
5014 if (!NT_STATUS_IS_OK(status)) {
5015 reply_nterror(req, status);
5016 END_PROFILE(SMBclose);
5017 return;
5020 reply_outbuf(req, 0, 0);
5021 END_PROFILE(SMBclose);
5022 return;
5025 static void do_smb1_close(struct tevent_req *req)
5027 struct reply_close_state *state = tevent_req_callback_data(
5028 req, struct reply_close_state);
5029 struct smb_request *smbreq;
5030 NTSTATUS status;
5031 int ret;
5033 ret = tevent_wait_recv(req);
5034 TALLOC_FREE(req);
5035 if (ret != 0) {
5036 DEBUG(10, ("tevent_wait_recv returned %s\n",
5037 strerror(ret)));
5039 * Continue anyway, this should never happen
5044 * fsp->smb2_close_request right now is a talloc grandchild of
5045 * fsp. When we close_file(fsp), it would go with it. No chance to
5046 * reply...
5048 smbreq = talloc_move(talloc_tos(), &state->smbreq);
5050 status = close_file(smbreq, state->fsp, NORMAL_CLOSE);
5051 if (NT_STATUS_IS_OK(status)) {
5052 reply_outbuf(smbreq, 0, 0);
5053 } else {
5054 reply_nterror(smbreq, status);
5056 if (!srv_send_smb(smbreq->sconn,
5057 (char *)smbreq->outbuf,
5058 true,
5059 smbreq->seqnum+1,
5060 IS_CONN_ENCRYPTED(smbreq->conn)||smbreq->encrypted,
5061 NULL)) {
5062 exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
5063 "failed.");
5065 TALLOC_FREE(smbreq);
5068 /****************************************************************************
5069 Reply to a writeclose (Core+ protocol).
5070 ****************************************************************************/
5072 void reply_writeclose(struct smb_request *req)
5074 connection_struct *conn = req->conn;
5075 size_t numtowrite;
5076 ssize_t nwritten = -1;
5077 NTSTATUS close_status = NT_STATUS_OK;
5078 off_t startpos;
5079 const char *data;
5080 struct timespec mtime;
5081 files_struct *fsp;
5082 struct lock_struct lock;
5084 START_PROFILE(SMBwriteclose);
5086 if (req->wct < 6) {
5087 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5088 END_PROFILE(SMBwriteclose);
5089 return;
5092 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5094 if (!check_fsp(conn, req, fsp)) {
5095 END_PROFILE(SMBwriteclose);
5096 return;
5098 if (!CHECK_WRITE(fsp)) {
5099 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5100 END_PROFILE(SMBwriteclose);
5101 return;
5104 numtowrite = SVAL(req->vwv+1, 0);
5105 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5106 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
5107 data = (const char *)req->buf + 1;
5109 if (!fsp->print_file) {
5110 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5111 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5112 &lock);
5114 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
5115 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5116 END_PROFILE(SMBwriteclose);
5117 return;
5121 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5123 set_close_write_time(fsp, mtime);
5126 * More insanity. W2K only closes the file if writelen > 0.
5127 * JRA.
5130 if (numtowrite) {
5131 DEBUG(3,("reply_writeclose: zero length write doesn't close "
5132 "file %s\n", fsp_str_dbg(fsp)));
5133 close_status = close_file(req, fsp, NORMAL_CLOSE);
5136 DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
5137 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
5138 conn->num_files_open));
5140 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
5141 reply_nterror(req, NT_STATUS_DISK_FULL);
5142 goto strict_unlock;
5145 if(!NT_STATUS_IS_OK(close_status)) {
5146 reply_nterror(req, close_status);
5147 goto strict_unlock;
5150 reply_outbuf(req, 1, 0);
5152 SSVAL(req->outbuf,smb_vwv0,nwritten);
5154 strict_unlock:
5155 if (numtowrite && !fsp->print_file) {
5156 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
5159 END_PROFILE(SMBwriteclose);
5160 return;
5163 #undef DBGC_CLASS
5164 #define DBGC_CLASS DBGC_LOCKING
5166 /****************************************************************************
5167 Reply to a lock.
5168 ****************************************************************************/
5170 void reply_lock(struct smb_request *req)
5172 connection_struct *conn = req->conn;
5173 uint64_t count,offset;
5174 NTSTATUS status;
5175 files_struct *fsp;
5176 struct byte_range_lock *br_lck = NULL;
5178 START_PROFILE(SMBlock);
5180 if (req->wct < 5) {
5181 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5182 END_PROFILE(SMBlock);
5183 return;
5186 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5188 if (!check_fsp(conn, req, fsp)) {
5189 END_PROFILE(SMBlock);
5190 return;
5193 count = (uint64_t)IVAL(req->vwv+1, 0);
5194 offset = (uint64_t)IVAL(req->vwv+3, 0);
5196 DEBUG(3,("lock fd=%d %s offset=%.0f count=%.0f\n",
5197 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count));
5199 br_lck = do_lock(req->sconn->msg_ctx,
5200 fsp,
5201 (uint64_t)req->smbpid,
5202 count,
5203 offset,
5204 WRITE_LOCK,
5205 WINDOWS_LOCK,
5206 False, /* Non-blocking lock. */
5207 &status,
5208 NULL,
5209 NULL);
5211 TALLOC_FREE(br_lck);
5213 if (NT_STATUS_V(status)) {
5214 reply_nterror(req, status);
5215 END_PROFILE(SMBlock);
5216 return;
5219 reply_outbuf(req, 0, 0);
5221 END_PROFILE(SMBlock);
5222 return;
5225 /****************************************************************************
5226 Reply to a unlock.
5227 ****************************************************************************/
5229 void reply_unlock(struct smb_request *req)
5231 connection_struct *conn = req->conn;
5232 uint64_t count,offset;
5233 NTSTATUS status;
5234 files_struct *fsp;
5236 START_PROFILE(SMBunlock);
5238 if (req->wct < 5) {
5239 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5240 END_PROFILE(SMBunlock);
5241 return;
5244 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5246 if (!check_fsp(conn, req, fsp)) {
5247 END_PROFILE(SMBunlock);
5248 return;
5251 count = (uint64_t)IVAL(req->vwv+1, 0);
5252 offset = (uint64_t)IVAL(req->vwv+3, 0);
5254 status = do_unlock(req->sconn->msg_ctx,
5255 fsp,
5256 (uint64_t)req->smbpid,
5257 count,
5258 offset,
5259 WINDOWS_LOCK);
5261 if (NT_STATUS_V(status)) {
5262 reply_nterror(req, status);
5263 END_PROFILE(SMBunlock);
5264 return;
5267 DEBUG( 3, ( "unlock fd=%d %s offset=%.0f count=%.0f\n",
5268 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count ) );
5270 reply_outbuf(req, 0, 0);
5272 END_PROFILE(SMBunlock);
5273 return;
5276 #undef DBGC_CLASS
5277 #define DBGC_CLASS DBGC_ALL
5279 /****************************************************************************
5280 Reply to a tdis.
5281 conn POINTER CAN BE NULL HERE !
5282 ****************************************************************************/
5284 void reply_tdis(struct smb_request *req)
5286 NTSTATUS status;
5287 connection_struct *conn = req->conn;
5288 struct smbXsrv_tcon *tcon;
5290 START_PROFILE(SMBtdis);
5292 if (!conn) {
5293 DEBUG(4,("Invalid connection in tdis\n"));
5294 reply_force_doserror(req, ERRSRV, ERRinvnid);
5295 END_PROFILE(SMBtdis);
5296 return;
5299 tcon = conn->tcon;
5300 req->conn = NULL;
5303 * TODO: cancel all outstanding requests on the tcon
5305 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
5306 if (!NT_STATUS_IS_OK(status)) {
5307 DEBUG(0, ("reply_tdis: "
5308 "smbXsrv_tcon_disconnect() failed: %s\n",
5309 nt_errstr(status)));
5311 * If we hit this case, there is something completely
5312 * wrong, so we better disconnect the transport connection.
5314 END_PROFILE(SMBtdis);
5315 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
5316 return;
5319 TALLOC_FREE(tcon);
5321 reply_outbuf(req, 0, 0);
5322 END_PROFILE(SMBtdis);
5323 return;
5326 /****************************************************************************
5327 Reply to a echo.
5328 conn POINTER CAN BE NULL HERE !
5329 ****************************************************************************/
5331 void reply_echo(struct smb_request *req)
5333 connection_struct *conn = req->conn;
5334 struct smb_perfcount_data local_pcd;
5335 struct smb_perfcount_data *cur_pcd;
5336 int smb_reverb;
5337 int seq_num;
5339 START_PROFILE(SMBecho);
5341 smb_init_perfcount_data(&local_pcd);
5343 if (req->wct < 1) {
5344 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5345 END_PROFILE(SMBecho);
5346 return;
5349 smb_reverb = SVAL(req->vwv+0, 0);
5351 reply_outbuf(req, 1, req->buflen);
5353 /* copy any incoming data back out */
5354 if (req->buflen > 0) {
5355 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5358 if (smb_reverb > 100) {
5359 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5360 smb_reverb = 100;
5363 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5365 /* this makes sure we catch the request pcd */
5366 if (seq_num == smb_reverb) {
5367 cur_pcd = &req->pcd;
5368 } else {
5369 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5370 cur_pcd = &local_pcd;
5373 SSVAL(req->outbuf,smb_vwv0,seq_num);
5375 show_msg((char *)req->outbuf);
5376 if (!srv_send_smb(req->sconn,
5377 (char *)req->outbuf,
5378 true, req->seqnum+1,
5379 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5380 cur_pcd))
5381 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5384 DEBUG(3,("echo %d times\n", smb_reverb));
5386 TALLOC_FREE(req->outbuf);
5388 END_PROFILE(SMBecho);
5389 return;
5392 /****************************************************************************
5393 Reply to a printopen.
5394 ****************************************************************************/
5396 void reply_printopen(struct smb_request *req)
5398 connection_struct *conn = req->conn;
5399 files_struct *fsp;
5400 NTSTATUS status;
5402 START_PROFILE(SMBsplopen);
5404 if (req->wct < 2) {
5405 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5406 END_PROFILE(SMBsplopen);
5407 return;
5410 if (!CAN_PRINT(conn)) {
5411 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5412 END_PROFILE(SMBsplopen);
5413 return;
5416 status = file_new(req, conn, &fsp);
5417 if(!NT_STATUS_IS_OK(status)) {
5418 reply_nterror(req, status);
5419 END_PROFILE(SMBsplopen);
5420 return;
5423 /* Open for exclusive use, write only. */
5424 status = print_spool_open(fsp, NULL, req->vuid);
5426 if (!NT_STATUS_IS_OK(status)) {
5427 file_free(req, fsp);
5428 reply_nterror(req, status);
5429 END_PROFILE(SMBsplopen);
5430 return;
5433 reply_outbuf(req, 1, 0);
5434 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5436 DEBUG(3,("openprint fd=%d %s\n",
5437 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5439 END_PROFILE(SMBsplopen);
5440 return;
5443 /****************************************************************************
5444 Reply to a printclose.
5445 ****************************************************************************/
5447 void reply_printclose(struct smb_request *req)
5449 connection_struct *conn = req->conn;
5450 files_struct *fsp;
5451 NTSTATUS status;
5453 START_PROFILE(SMBsplclose);
5455 if (req->wct < 1) {
5456 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5457 END_PROFILE(SMBsplclose);
5458 return;
5461 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5463 if (!check_fsp(conn, req, fsp)) {
5464 END_PROFILE(SMBsplclose);
5465 return;
5468 if (!CAN_PRINT(conn)) {
5469 reply_force_doserror(req, ERRSRV, ERRerror);
5470 END_PROFILE(SMBsplclose);
5471 return;
5474 DEBUG(3,("printclose fd=%d %s\n",
5475 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5477 status = close_file(req, fsp, NORMAL_CLOSE);
5479 if(!NT_STATUS_IS_OK(status)) {
5480 reply_nterror(req, status);
5481 END_PROFILE(SMBsplclose);
5482 return;
5485 reply_outbuf(req, 0, 0);
5487 END_PROFILE(SMBsplclose);
5488 return;
5491 /****************************************************************************
5492 Reply to a printqueue.
5493 ****************************************************************************/
5495 void reply_printqueue(struct smb_request *req)
5497 connection_struct *conn = req->conn;
5498 int max_count;
5499 int start_index;
5501 START_PROFILE(SMBsplretq);
5503 if (req->wct < 2) {
5504 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5505 END_PROFILE(SMBsplretq);
5506 return;
5509 max_count = SVAL(req->vwv+0, 0);
5510 start_index = SVAL(req->vwv+1, 0);
5512 /* we used to allow the client to get the cnum wrong, but that
5513 is really quite gross and only worked when there was only
5514 one printer - I think we should now only accept it if they
5515 get it right (tridge) */
5516 if (!CAN_PRINT(conn)) {
5517 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5518 END_PROFILE(SMBsplretq);
5519 return;
5522 reply_outbuf(req, 2, 3);
5523 SSVAL(req->outbuf,smb_vwv0,0);
5524 SSVAL(req->outbuf,smb_vwv1,0);
5525 SCVAL(smb_buf(req->outbuf),0,1);
5526 SSVAL(smb_buf(req->outbuf),1,0);
5528 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5529 start_index, max_count));
5532 TALLOC_CTX *mem_ctx = talloc_tos();
5533 NTSTATUS status;
5534 WERROR werr;
5535 const char *sharename = lp_servicename(mem_ctx, SNUM(conn));
5536 struct rpc_pipe_client *cli = NULL;
5537 struct dcerpc_binding_handle *b = NULL;
5538 struct policy_handle handle;
5539 struct spoolss_DevmodeContainer devmode_ctr;
5540 union spoolss_JobInfo *info;
5541 uint32_t count;
5542 uint32_t num_to_get;
5543 uint32_t first;
5544 uint32_t i;
5546 ZERO_STRUCT(handle);
5548 status = rpc_pipe_open_interface(conn,
5549 &ndr_table_spoolss.syntax_id,
5550 conn->session_info,
5551 conn->sconn->remote_address,
5552 conn->sconn->msg_ctx,
5553 &cli);
5554 if (!NT_STATUS_IS_OK(status)) {
5555 DEBUG(0, ("reply_printqueue: "
5556 "could not connect to spoolss: %s\n",
5557 nt_errstr(status)));
5558 reply_nterror(req, status);
5559 goto out;
5561 b = cli->binding_handle;
5563 ZERO_STRUCT(devmode_ctr);
5565 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5566 sharename,
5567 NULL, devmode_ctr,
5568 SEC_FLAG_MAXIMUM_ALLOWED,
5569 &handle,
5570 &werr);
5571 if (!NT_STATUS_IS_OK(status)) {
5572 reply_nterror(req, status);
5573 goto out;
5575 if (!W_ERROR_IS_OK(werr)) {
5576 reply_nterror(req, werror_to_ntstatus(werr));
5577 goto out;
5580 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5581 &handle,
5582 0, /* firstjob */
5583 0xff, /* numjobs */
5584 2, /* level */
5585 0, /* offered */
5586 &count,
5587 &info);
5588 if (!W_ERROR_IS_OK(werr)) {
5589 reply_nterror(req, werror_to_ntstatus(werr));
5590 goto out;
5593 if (max_count > 0) {
5594 first = start_index;
5595 } else {
5596 first = start_index + max_count + 1;
5599 if (first >= count) {
5600 num_to_get = first;
5601 } else {
5602 num_to_get = first + MIN(ABS(max_count), count - first);
5605 for (i = first; i < num_to_get; i++) {
5606 char blob[28];
5607 char *p = blob;
5608 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
5609 int qstatus;
5610 uint16_t qrapjobid = pjobid_to_rap(sharename,
5611 info[i].info2.job_id);
5613 if (info[i].info2.status == JOB_STATUS_PRINTING) {
5614 qstatus = 2;
5615 } else {
5616 qstatus = 3;
5619 srv_put_dos_date2(p, 0, qtime);
5620 SCVAL(p, 4, qstatus);
5621 SSVAL(p, 5, qrapjobid);
5622 SIVAL(p, 7, info[i].info2.size);
5623 SCVAL(p, 11, 0);
5624 srvstr_push(blob, req->flags2, p+12,
5625 info[i].info2.notify_name, 16, STR_ASCII);
5627 if (message_push_blob(
5628 &req->outbuf,
5629 data_blob_const(
5630 blob, sizeof(blob))) == -1) {
5631 reply_nterror(req, NT_STATUS_NO_MEMORY);
5632 goto out;
5636 if (count > 0) {
5637 SSVAL(req->outbuf,smb_vwv0,count);
5638 SSVAL(req->outbuf,smb_vwv1,
5639 (max_count>0?first+count:first-1));
5640 SCVAL(smb_buf(req->outbuf),0,1);
5641 SSVAL(smb_buf(req->outbuf),1,28*count);
5645 DEBUG(3, ("%u entries returned in queue\n",
5646 (unsigned)count));
5648 out:
5649 if (b && is_valid_policy_hnd(&handle)) {
5650 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5655 END_PROFILE(SMBsplretq);
5656 return;
5659 /****************************************************************************
5660 Reply to a printwrite.
5661 ****************************************************************************/
5663 void reply_printwrite(struct smb_request *req)
5665 connection_struct *conn = req->conn;
5666 int numtowrite;
5667 const char *data;
5668 files_struct *fsp;
5670 START_PROFILE(SMBsplwr);
5672 if (req->wct < 1) {
5673 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5674 END_PROFILE(SMBsplwr);
5675 return;
5678 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5680 if (!check_fsp(conn, req, fsp)) {
5681 END_PROFILE(SMBsplwr);
5682 return;
5685 if (!fsp->print_file) {
5686 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5687 END_PROFILE(SMBsplwr);
5688 return;
5691 if (!CHECK_WRITE(fsp)) {
5692 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5693 END_PROFILE(SMBsplwr);
5694 return;
5697 numtowrite = SVAL(req->buf, 1);
5699 if (req->buflen < numtowrite + 3) {
5700 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5701 END_PROFILE(SMBsplwr);
5702 return;
5705 data = (const char *)req->buf + 3;
5707 if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
5708 reply_nterror(req, map_nt_error_from_unix(errno));
5709 END_PROFILE(SMBsplwr);
5710 return;
5713 DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
5715 END_PROFILE(SMBsplwr);
5716 return;
5719 /****************************************************************************
5720 Reply to a mkdir.
5721 ****************************************************************************/
5723 void reply_mkdir(struct smb_request *req)
5725 connection_struct *conn = req->conn;
5726 struct smb_filename *smb_dname = NULL;
5727 char *directory = NULL;
5728 NTSTATUS status;
5729 TALLOC_CTX *ctx = talloc_tos();
5731 START_PROFILE(SMBmkdir);
5733 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5734 STR_TERMINATE, &status);
5735 if (!NT_STATUS_IS_OK(status)) {
5736 reply_nterror(req, status);
5737 goto out;
5740 status = filename_convert(ctx, conn,
5741 req->flags2 & FLAGS2_DFS_PATHNAMES,
5742 directory,
5744 NULL,
5745 &smb_dname);
5746 if (!NT_STATUS_IS_OK(status)) {
5747 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5748 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5749 ERRSRV, ERRbadpath);
5750 goto out;
5752 reply_nterror(req, status);
5753 goto out;
5756 status = create_directory(conn, req, smb_dname);
5758 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
5760 if (!NT_STATUS_IS_OK(status)) {
5762 if (!use_nt_status()
5763 && NT_STATUS_EQUAL(status,
5764 NT_STATUS_OBJECT_NAME_COLLISION)) {
5766 * Yes, in the DOS error code case we get a
5767 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
5768 * samba4 torture test.
5770 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
5773 reply_nterror(req, status);
5774 goto out;
5777 reply_outbuf(req, 0, 0);
5779 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
5780 out:
5781 TALLOC_FREE(smb_dname);
5782 END_PROFILE(SMBmkdir);
5783 return;
5786 /****************************************************************************
5787 Reply to a rmdir.
5788 ****************************************************************************/
5790 void reply_rmdir(struct smb_request *req)
5792 connection_struct *conn = req->conn;
5793 struct smb_filename *smb_dname = NULL;
5794 char *directory = NULL;
5795 NTSTATUS status;
5796 TALLOC_CTX *ctx = talloc_tos();
5797 files_struct *fsp = NULL;
5798 int info = 0;
5799 struct smbd_server_connection *sconn = req->sconn;
5801 START_PROFILE(SMBrmdir);
5803 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5804 STR_TERMINATE, &status);
5805 if (!NT_STATUS_IS_OK(status)) {
5806 reply_nterror(req, status);
5807 goto out;
5810 status = filename_convert(ctx, conn,
5811 req->flags2 & FLAGS2_DFS_PATHNAMES,
5812 directory,
5814 NULL,
5815 &smb_dname);
5816 if (!NT_STATUS_IS_OK(status)) {
5817 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5818 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5819 ERRSRV, ERRbadpath);
5820 goto out;
5822 reply_nterror(req, status);
5823 goto out;
5826 if (is_ntfs_stream_smb_fname(smb_dname)) {
5827 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
5828 goto out;
5831 status = SMB_VFS_CREATE_FILE(
5832 conn, /* conn */
5833 req, /* req */
5834 0, /* root_dir_fid */
5835 smb_dname, /* fname */
5836 DELETE_ACCESS, /* access_mask */
5837 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5838 FILE_SHARE_DELETE),
5839 FILE_OPEN, /* create_disposition*/
5840 FILE_DIRECTORY_FILE, /* create_options */
5841 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
5842 0, /* oplock_request */
5843 0, /* allocation_size */
5844 0, /* private_flags */
5845 NULL, /* sd */
5846 NULL, /* ea_list */
5847 &fsp, /* result */
5848 &info); /* pinfo */
5850 if (!NT_STATUS_IS_OK(status)) {
5851 if (open_was_deferred(req->sconn, req->mid)) {
5852 /* We have re-scheduled this call. */
5853 goto out;
5855 reply_nterror(req, status);
5856 goto out;
5859 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
5860 if (!NT_STATUS_IS_OK(status)) {
5861 close_file(req, fsp, ERROR_CLOSE);
5862 reply_nterror(req, status);
5863 goto out;
5866 if (!set_delete_on_close(fsp, true,
5867 conn->session_info->security_token,
5868 conn->session_info->unix_token)) {
5869 close_file(req, fsp, ERROR_CLOSE);
5870 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5871 goto out;
5874 status = close_file(req, fsp, NORMAL_CLOSE);
5875 if (!NT_STATUS_IS_OK(status)) {
5876 reply_nterror(req, status);
5877 } else {
5878 reply_outbuf(req, 0, 0);
5881 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
5883 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
5884 out:
5885 TALLOC_FREE(smb_dname);
5886 END_PROFILE(SMBrmdir);
5887 return;
5890 /*******************************************************************
5891 Resolve wildcards in a filename rename.
5892 ********************************************************************/
5894 static bool resolve_wildcards(TALLOC_CTX *ctx,
5895 const char *name1,
5896 const char *name2,
5897 char **pp_newname)
5899 char *name2_copy = NULL;
5900 char *root1 = NULL;
5901 char *root2 = NULL;
5902 char *ext1 = NULL;
5903 char *ext2 = NULL;
5904 char *p,*p2, *pname1, *pname2;
5906 name2_copy = talloc_strdup(ctx, name2);
5907 if (!name2_copy) {
5908 return False;
5911 pname1 = strrchr_m(name1,'/');
5912 pname2 = strrchr_m(name2_copy,'/');
5914 if (!pname1 || !pname2) {
5915 return False;
5918 /* Truncate the copy of name2 at the last '/' */
5919 *pname2 = '\0';
5921 /* Now go past the '/' */
5922 pname1++;
5923 pname2++;
5925 root1 = talloc_strdup(ctx, pname1);
5926 root2 = talloc_strdup(ctx, pname2);
5928 if (!root1 || !root2) {
5929 return False;
5932 p = strrchr_m(root1,'.');
5933 if (p) {
5934 *p = 0;
5935 ext1 = talloc_strdup(ctx, p+1);
5936 } else {
5937 ext1 = talloc_strdup(ctx, "");
5939 p = strrchr_m(root2,'.');
5940 if (p) {
5941 *p = 0;
5942 ext2 = talloc_strdup(ctx, p+1);
5943 } else {
5944 ext2 = talloc_strdup(ctx, "");
5947 if (!ext1 || !ext2) {
5948 return False;
5951 p = root1;
5952 p2 = root2;
5953 while (*p2) {
5954 if (*p2 == '?') {
5955 /* Hmmm. Should this be mb-aware ? */
5956 *p2 = *p;
5957 p2++;
5958 } else if (*p2 == '*') {
5959 *p2 = '\0';
5960 root2 = talloc_asprintf(ctx, "%s%s",
5961 root2,
5963 if (!root2) {
5964 return False;
5966 break;
5967 } else {
5968 p2++;
5970 if (*p) {
5971 p++;
5975 p = ext1;
5976 p2 = ext2;
5977 while (*p2) {
5978 if (*p2 == '?') {
5979 /* Hmmm. Should this be mb-aware ? */
5980 *p2 = *p;
5981 p2++;
5982 } else if (*p2 == '*') {
5983 *p2 = '\0';
5984 ext2 = talloc_asprintf(ctx, "%s%s",
5985 ext2,
5987 if (!ext2) {
5988 return False;
5990 break;
5991 } else {
5992 p2++;
5994 if (*p) {
5995 p++;
5999 if (*ext2) {
6000 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
6001 name2_copy,
6002 root2,
6003 ext2);
6004 } else {
6005 *pp_newname = talloc_asprintf(ctx, "%s/%s",
6006 name2_copy,
6007 root2);
6010 if (!*pp_newname) {
6011 return False;
6014 return True;
6017 /****************************************************************************
6018 Ensure open files have their names updated. Updated to notify other smbd's
6019 asynchronously.
6020 ****************************************************************************/
6022 static void rename_open_files(connection_struct *conn,
6023 struct share_mode_lock *lck,
6024 uint32_t orig_name_hash,
6025 const struct smb_filename *smb_fname_dst)
6027 files_struct *fsp;
6028 bool did_rename = False;
6029 NTSTATUS status;
6030 uint32_t new_name_hash = 0;
6032 for(fsp = file_find_di_first(conn->sconn, lck->data->id); fsp;
6033 fsp = file_find_di_next(fsp)) {
6034 /* fsp_name is a relative path under the fsp. To change this for other
6035 sharepaths we need to manipulate relative paths. */
6036 /* TODO - create the absolute path and manipulate the newname
6037 relative to the sharepath. */
6038 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
6039 continue;
6041 if (fsp->name_hash != orig_name_hash) {
6042 continue;
6044 DEBUG(10, ("rename_open_files: renaming file %s "
6045 "(file_id %s) from %s -> %s\n", fsp_fnum_dbg(fsp),
6046 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
6047 smb_fname_str_dbg(smb_fname_dst)));
6049 status = fsp_set_smb_fname(fsp, smb_fname_dst);
6050 if (NT_STATUS_IS_OK(status)) {
6051 did_rename = True;
6052 new_name_hash = fsp->name_hash;
6056 if (!did_rename) {
6057 DEBUG(10, ("rename_open_files: no open files on file_id %s "
6058 "for %s\n", file_id_string_tos(&lck->data->id),
6059 smb_fname_str_dbg(smb_fname_dst)));
6062 /* Send messages to all smbd's (not ourself) that the name has changed. */
6063 rename_share_filename(conn->sconn->msg_ctx, lck, conn->connectpath,
6064 orig_name_hash, new_name_hash,
6065 smb_fname_dst);
6069 /****************************************************************************
6070 We need to check if the source path is a parent directory of the destination
6071 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
6072 refuse the rename with a sharing violation. Under UNIX the above call can
6073 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
6074 probably need to check that the client is a Windows one before disallowing
6075 this as a UNIX client (one with UNIX extensions) can know the source is a
6076 symlink and make this decision intelligently. Found by an excellent bug
6077 report from <AndyLiebman@aol.com>.
6078 ****************************************************************************/
6080 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
6081 const struct smb_filename *smb_fname_dst)
6083 const char *psrc = smb_fname_src->base_name;
6084 const char *pdst = smb_fname_dst->base_name;
6085 size_t slen;
6087 if (psrc[0] == '.' && psrc[1] == '/') {
6088 psrc += 2;
6090 if (pdst[0] == '.' && pdst[1] == '/') {
6091 pdst += 2;
6093 if ((slen = strlen(psrc)) > strlen(pdst)) {
6094 return False;
6096 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
6100 * Do the notify calls from a rename
6103 static void notify_rename(connection_struct *conn, bool is_dir,
6104 const struct smb_filename *smb_fname_src,
6105 const struct smb_filename *smb_fname_dst)
6107 char *parent_dir_src = NULL;
6108 char *parent_dir_dst = NULL;
6109 uint32 mask;
6111 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
6112 : FILE_NOTIFY_CHANGE_FILE_NAME;
6114 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
6115 &parent_dir_src, NULL) ||
6116 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
6117 &parent_dir_dst, NULL)) {
6118 goto out;
6121 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
6122 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
6123 smb_fname_src->base_name);
6124 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
6125 smb_fname_dst->base_name);
6127 else {
6128 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
6129 smb_fname_src->base_name);
6130 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
6131 smb_fname_dst->base_name);
6134 /* this is a strange one. w2k3 gives an additional event for
6135 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
6136 files, but not directories */
6137 if (!is_dir) {
6138 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6139 FILE_NOTIFY_CHANGE_ATTRIBUTES
6140 |FILE_NOTIFY_CHANGE_CREATION,
6141 smb_fname_dst->base_name);
6143 out:
6144 TALLOC_FREE(parent_dir_src);
6145 TALLOC_FREE(parent_dir_dst);
6148 /****************************************************************************
6149 Returns an error if the parent directory for a filename is open in an
6150 incompatible way.
6151 ****************************************************************************/
6153 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
6154 const struct smb_filename *smb_fname_dst_in)
6156 char *parent_dir = NULL;
6157 struct smb_filename smb_fname_parent;
6158 struct file_id id;
6159 files_struct *fsp = NULL;
6160 int ret;
6162 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
6163 &parent_dir, NULL)) {
6164 return NT_STATUS_NO_MEMORY;
6166 ZERO_STRUCT(smb_fname_parent);
6167 smb_fname_parent.base_name = parent_dir;
6169 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
6170 if (ret == -1) {
6171 return map_nt_error_from_unix(errno);
6175 * We're only checking on this smbd here, mostly good
6176 * enough.. and will pass tests.
6179 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
6180 for (fsp = file_find_di_first(conn->sconn, id); fsp;
6181 fsp = file_find_di_next(fsp)) {
6182 if (fsp->access_mask & DELETE_ACCESS) {
6183 return NT_STATUS_SHARING_VIOLATION;
6186 return NT_STATUS_OK;
6189 /****************************************************************************
6190 Rename an open file - given an fsp.
6191 ****************************************************************************/
6193 NTSTATUS rename_internals_fsp(connection_struct *conn,
6194 files_struct *fsp,
6195 const struct smb_filename *smb_fname_dst_in,
6196 uint32 attrs,
6197 bool replace_if_exists)
6199 TALLOC_CTX *ctx = talloc_tos();
6200 struct smb_filename *smb_fname_dst = NULL;
6201 NTSTATUS status = NT_STATUS_OK;
6202 struct share_mode_lock *lck = NULL;
6203 bool dst_exists, old_is_stream, new_is_stream;
6205 status = check_name(conn, smb_fname_dst_in->base_name);
6206 if (!NT_STATUS_IS_OK(status)) {
6207 return status;
6210 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
6211 if (!NT_STATUS_IS_OK(status)) {
6212 return status;
6215 /* Make a copy of the dst smb_fname structs */
6217 status = copy_smb_filename(ctx, smb_fname_dst_in, &smb_fname_dst);
6218 if (!NT_STATUS_IS_OK(status)) {
6219 goto out;
6223 * Check for special case with case preserving and not
6224 * case sensitive. If the old last component differs from the original
6225 * last component only by case, then we should allow
6226 * the rename (user is trying to change the case of the
6227 * filename).
6229 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
6230 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6231 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
6232 char *last_slash;
6233 char *fname_dst_lcomp_base_mod = NULL;
6234 struct smb_filename *smb_fname_orig_lcomp = NULL;
6237 * Get the last component of the destination name.
6239 last_slash = strrchr_m(smb_fname_dst->base_name, '/');
6240 if (last_slash) {
6241 fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1);
6242 } else {
6243 fname_dst_lcomp_base_mod = talloc_strdup(ctx, smb_fname_dst->base_name);
6245 if (!fname_dst_lcomp_base_mod) {
6246 status = NT_STATUS_NO_MEMORY;
6247 goto out;
6251 * Create an smb_filename struct using the original last
6252 * component of the destination.
6254 status = create_synthetic_smb_fname_split(ctx,
6255 smb_fname_dst->original_lcomp, NULL,
6256 &smb_fname_orig_lcomp);
6257 if (!NT_STATUS_IS_OK(status)) {
6258 TALLOC_FREE(fname_dst_lcomp_base_mod);
6259 goto out;
6262 /* If the base names only differ by case, use original. */
6263 if(!strcsequal(fname_dst_lcomp_base_mod,
6264 smb_fname_orig_lcomp->base_name)) {
6265 char *tmp;
6267 * Replace the modified last component with the
6268 * original.
6270 if (last_slash) {
6271 *last_slash = '\0'; /* Truncate at the '/' */
6272 tmp = talloc_asprintf(smb_fname_dst,
6273 "%s/%s",
6274 smb_fname_dst->base_name,
6275 smb_fname_orig_lcomp->base_name);
6276 } else {
6277 tmp = talloc_asprintf(smb_fname_dst,
6278 "%s",
6279 smb_fname_orig_lcomp->base_name);
6281 if (tmp == NULL) {
6282 status = NT_STATUS_NO_MEMORY;
6283 TALLOC_FREE(fname_dst_lcomp_base_mod);
6284 TALLOC_FREE(smb_fname_orig_lcomp);
6285 goto out;
6287 TALLOC_FREE(smb_fname_dst->base_name);
6288 smb_fname_dst->base_name = tmp;
6291 /* If the stream_names only differ by case, use original. */
6292 if(!strcsequal(smb_fname_dst->stream_name,
6293 smb_fname_orig_lcomp->stream_name)) {
6294 char *tmp = NULL;
6295 /* Use the original stream. */
6296 tmp = talloc_strdup(smb_fname_dst,
6297 smb_fname_orig_lcomp->stream_name);
6298 if (tmp == NULL) {
6299 status = NT_STATUS_NO_MEMORY;
6300 TALLOC_FREE(fname_dst_lcomp_base_mod);
6301 TALLOC_FREE(smb_fname_orig_lcomp);
6302 goto out;
6304 TALLOC_FREE(smb_fname_dst->stream_name);
6305 smb_fname_dst->stream_name = tmp;
6307 TALLOC_FREE(fname_dst_lcomp_base_mod);
6308 TALLOC_FREE(smb_fname_orig_lcomp);
6312 * If the src and dest names are identical - including case,
6313 * don't do the rename, just return success.
6316 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6317 strcsequal(fsp->fsp_name->stream_name,
6318 smb_fname_dst->stream_name)) {
6319 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6320 "- returning success\n",
6321 smb_fname_str_dbg(smb_fname_dst)));
6322 status = NT_STATUS_OK;
6323 goto out;
6326 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6327 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6329 /* Return the correct error code if both names aren't streams. */
6330 if (!old_is_stream && new_is_stream) {
6331 status = NT_STATUS_OBJECT_NAME_INVALID;
6332 goto out;
6335 if (old_is_stream && !new_is_stream) {
6336 status = NT_STATUS_INVALID_PARAMETER;
6337 goto out;
6340 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6342 if(!replace_if_exists && dst_exists) {
6343 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6344 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6345 smb_fname_str_dbg(smb_fname_dst)));
6346 status = NT_STATUS_OBJECT_NAME_COLLISION;
6347 goto out;
6350 if (dst_exists) {
6351 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6352 &smb_fname_dst->st);
6353 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6354 fileid);
6355 /* The file can be open when renaming a stream */
6356 if (dst_fsp && !new_is_stream) {
6357 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6358 status = NT_STATUS_ACCESS_DENIED;
6359 goto out;
6363 /* Ensure we have a valid stat struct for the source. */
6364 status = vfs_stat_fsp(fsp);
6365 if (!NT_STATUS_IS_OK(status)) {
6366 goto out;
6369 status = can_rename(conn, fsp, attrs);
6371 if (!NT_STATUS_IS_OK(status)) {
6372 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6373 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6374 smb_fname_str_dbg(smb_fname_dst)));
6375 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6376 status = NT_STATUS_ACCESS_DENIED;
6377 goto out;
6380 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6381 status = NT_STATUS_ACCESS_DENIED;
6384 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
6387 * We have the file open ourselves, so not being able to get the
6388 * corresponding share mode lock is a fatal error.
6391 SMB_ASSERT(lck != NULL);
6393 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6394 uint32 create_options = fsp->fh->private_options;
6396 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6397 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6398 smb_fname_str_dbg(smb_fname_dst)));
6400 if (!lp_posix_pathnames() &&
6401 (lp_map_archive(SNUM(conn)) ||
6402 lp_store_dos_attributes(SNUM(conn)))) {
6403 /* We must set the archive bit on the newly
6404 renamed file. */
6405 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6406 uint32_t old_dosmode = dos_mode(conn,
6407 smb_fname_dst);
6408 file_set_dosmode(conn,
6409 smb_fname_dst,
6410 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6411 NULL,
6412 true);
6416 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6417 smb_fname_dst);
6419 rename_open_files(conn, lck, fsp->name_hash, smb_fname_dst);
6422 * A rename acts as a new file create w.r.t. allowing an initial delete
6423 * on close, probably because in Windows there is a new handle to the
6424 * new file. If initial delete on close was requested but not
6425 * originally set, we need to set it here. This is probably not 100% correct,
6426 * but will work for the CIFSFS client which in non-posix mode
6427 * depends on these semantics. JRA.
6430 if (create_options & FILE_DELETE_ON_CLOSE) {
6431 status = can_set_delete_on_close(fsp, 0);
6433 if (NT_STATUS_IS_OK(status)) {
6434 /* Note that here we set the *inital* delete on close flag,
6435 * not the regular one. The magic gets handled in close. */
6436 fsp->initial_delete_on_close = True;
6439 TALLOC_FREE(lck);
6440 status = NT_STATUS_OK;
6441 goto out;
6444 TALLOC_FREE(lck);
6446 if (errno == ENOTDIR || errno == EISDIR) {
6447 status = NT_STATUS_OBJECT_NAME_COLLISION;
6448 } else {
6449 status = map_nt_error_from_unix(errno);
6452 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6453 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6454 smb_fname_str_dbg(smb_fname_dst)));
6456 out:
6457 TALLOC_FREE(smb_fname_dst);
6459 return status;
6462 /****************************************************************************
6463 The guts of the rename command, split out so it may be called by the NT SMB
6464 code.
6465 ****************************************************************************/
6467 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6468 connection_struct *conn,
6469 struct smb_request *req,
6470 struct smb_filename *smb_fname_src,
6471 struct smb_filename *smb_fname_dst,
6472 uint32 attrs,
6473 bool replace_if_exists,
6474 bool src_has_wild,
6475 bool dest_has_wild,
6476 uint32_t access_mask)
6478 char *fname_src_dir = NULL;
6479 char *fname_src_mask = NULL;
6480 int count=0;
6481 NTSTATUS status = NT_STATUS_OK;
6482 struct smb_Dir *dir_hnd = NULL;
6483 const char *dname = NULL;
6484 char *talloced = NULL;
6485 long offset = 0;
6486 int create_options = 0;
6487 bool posix_pathnames = lp_posix_pathnames();
6488 int rc;
6491 * Split the old name into directory and last component
6492 * strings. Note that unix_convert may have stripped off a
6493 * leading ./ from both name and newname if the rename is
6494 * at the root of the share. We need to make sure either both
6495 * name and newname contain a / character or neither of them do
6496 * as this is checked in resolve_wildcards().
6499 /* Split up the directory from the filename/mask. */
6500 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6501 &fname_src_dir, &fname_src_mask);
6502 if (!NT_STATUS_IS_OK(status)) {
6503 status = NT_STATUS_NO_MEMORY;
6504 goto out;
6508 * We should only check the mangled cache
6509 * here if unix_convert failed. This means
6510 * that the path in 'mask' doesn't exist
6511 * on the file system and so we need to look
6512 * for a possible mangle. This patch from
6513 * Tine Smukavec <valentin.smukavec@hermes.si>.
6516 if (!VALID_STAT(smb_fname_src->st) &&
6517 mangle_is_mangled(fname_src_mask, conn->params)) {
6518 char *new_mask = NULL;
6519 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6520 conn->params);
6521 if (new_mask) {
6522 TALLOC_FREE(fname_src_mask);
6523 fname_src_mask = new_mask;
6527 if (!src_has_wild) {
6528 files_struct *fsp;
6531 * Only one file needs to be renamed. Append the mask back
6532 * onto the directory.
6534 TALLOC_FREE(smb_fname_src->base_name);
6535 if (ISDOT(fname_src_dir)) {
6536 /* Ensure we use canonical names on open. */
6537 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6538 "%s",
6539 fname_src_mask);
6540 } else {
6541 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6542 "%s/%s",
6543 fname_src_dir,
6544 fname_src_mask);
6546 if (!smb_fname_src->base_name) {
6547 status = NT_STATUS_NO_MEMORY;
6548 goto out;
6551 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6552 "case_preserve = %d, short case preserve = %d, "
6553 "directory = %s, newname = %s, "
6554 "last_component_dest = %s\n",
6555 conn->case_sensitive, conn->case_preserve,
6556 conn->short_case_preserve,
6557 smb_fname_str_dbg(smb_fname_src),
6558 smb_fname_str_dbg(smb_fname_dst),
6559 smb_fname_dst->original_lcomp));
6561 /* The dest name still may have wildcards. */
6562 if (dest_has_wild) {
6563 char *fname_dst_mod = NULL;
6564 if (!resolve_wildcards(smb_fname_dst,
6565 smb_fname_src->base_name,
6566 smb_fname_dst->base_name,
6567 &fname_dst_mod)) {
6568 DEBUG(6, ("rename_internals: resolve_wildcards "
6569 "%s %s failed\n",
6570 smb_fname_src->base_name,
6571 smb_fname_dst->base_name));
6572 status = NT_STATUS_NO_MEMORY;
6573 goto out;
6575 TALLOC_FREE(smb_fname_dst->base_name);
6576 smb_fname_dst->base_name = fname_dst_mod;
6579 ZERO_STRUCT(smb_fname_src->st);
6580 if (posix_pathnames) {
6581 rc = SMB_VFS_LSTAT(conn, smb_fname_src);
6582 } else {
6583 rc = SMB_VFS_STAT(conn, smb_fname_src);
6585 if (rc == -1) {
6586 status = map_nt_error_from_unix_common(errno);
6587 goto out;
6590 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6591 create_options |= FILE_DIRECTORY_FILE;
6594 status = SMB_VFS_CREATE_FILE(
6595 conn, /* conn */
6596 req, /* req */
6597 0, /* root_dir_fid */
6598 smb_fname_src, /* fname */
6599 access_mask, /* access_mask */
6600 (FILE_SHARE_READ | /* share_access */
6601 FILE_SHARE_WRITE),
6602 FILE_OPEN, /* create_disposition*/
6603 create_options, /* create_options */
6604 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6605 0, /* oplock_request */
6606 0, /* allocation_size */
6607 0, /* private_flags */
6608 NULL, /* sd */
6609 NULL, /* ea_list */
6610 &fsp, /* result */
6611 NULL); /* pinfo */
6613 if (!NT_STATUS_IS_OK(status)) {
6614 DEBUG(3, ("Could not open rename source %s: %s\n",
6615 smb_fname_str_dbg(smb_fname_src),
6616 nt_errstr(status)));
6617 goto out;
6620 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6621 attrs, replace_if_exists);
6623 close_file(req, fsp, NORMAL_CLOSE);
6625 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
6626 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
6627 smb_fname_str_dbg(smb_fname_dst)));
6629 goto out;
6633 * Wildcards - process each file that matches.
6635 if (strequal(fname_src_mask, "????????.???")) {
6636 TALLOC_FREE(fname_src_mask);
6637 fname_src_mask = talloc_strdup(ctx, "*");
6638 if (!fname_src_mask) {
6639 status = NT_STATUS_NO_MEMORY;
6640 goto out;
6644 status = check_name(conn, fname_src_dir);
6645 if (!NT_STATUS_IS_OK(status)) {
6646 goto out;
6649 dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask,
6650 attrs);
6651 if (dir_hnd == NULL) {
6652 status = map_nt_error_from_unix(errno);
6653 goto out;
6656 status = NT_STATUS_NO_SUCH_FILE;
6658 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
6659 * - gentest fix. JRA
6662 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
6663 &talloced))) {
6664 files_struct *fsp = NULL;
6665 char *destname = NULL;
6666 bool sysdir_entry = False;
6668 /* Quick check for "." and ".." */
6669 if (ISDOT(dname) || ISDOTDOT(dname)) {
6670 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
6671 sysdir_entry = True;
6672 } else {
6673 TALLOC_FREE(talloced);
6674 continue;
6678 if (!is_visible_file(conn, fname_src_dir, dname,
6679 &smb_fname_src->st, false)) {
6680 TALLOC_FREE(talloced);
6681 continue;
6684 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
6685 TALLOC_FREE(talloced);
6686 continue;
6689 if (sysdir_entry) {
6690 status = NT_STATUS_OBJECT_NAME_INVALID;
6691 break;
6694 TALLOC_FREE(smb_fname_src->base_name);
6695 if (ISDOT(fname_src_dir)) {
6696 /* Ensure we use canonical names on open. */
6697 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6698 "%s",
6699 dname);
6700 } else {
6701 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6702 "%s/%s",
6703 fname_src_dir,
6704 dname);
6706 if (!smb_fname_src->base_name) {
6707 status = NT_STATUS_NO_MEMORY;
6708 goto out;
6711 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6712 smb_fname_dst->base_name,
6713 &destname)) {
6714 DEBUG(6, ("resolve_wildcards %s %s failed\n",
6715 smb_fname_src->base_name, destname));
6716 TALLOC_FREE(talloced);
6717 continue;
6719 if (!destname) {
6720 status = NT_STATUS_NO_MEMORY;
6721 goto out;
6724 TALLOC_FREE(smb_fname_dst->base_name);
6725 smb_fname_dst->base_name = destname;
6727 ZERO_STRUCT(smb_fname_src->st);
6728 if (posix_pathnames) {
6729 SMB_VFS_LSTAT(conn, smb_fname_src);
6730 } else {
6731 SMB_VFS_STAT(conn, smb_fname_src);
6734 create_options = 0;
6736 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6737 create_options |= FILE_DIRECTORY_FILE;
6740 status = SMB_VFS_CREATE_FILE(
6741 conn, /* conn */
6742 req, /* req */
6743 0, /* root_dir_fid */
6744 smb_fname_src, /* fname */
6745 access_mask, /* access_mask */
6746 (FILE_SHARE_READ | /* share_access */
6747 FILE_SHARE_WRITE),
6748 FILE_OPEN, /* create_disposition*/
6749 create_options, /* create_options */
6750 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6751 0, /* oplock_request */
6752 0, /* allocation_size */
6753 0, /* private_flags */
6754 NULL, /* sd */
6755 NULL, /* ea_list */
6756 &fsp, /* result */
6757 NULL); /* pinfo */
6759 if (!NT_STATUS_IS_OK(status)) {
6760 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
6761 "returned %s rename %s -> %s\n",
6762 nt_errstr(status),
6763 smb_fname_str_dbg(smb_fname_src),
6764 smb_fname_str_dbg(smb_fname_dst)));
6765 break;
6768 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6769 dname);
6770 if (!smb_fname_dst->original_lcomp) {
6771 status = NT_STATUS_NO_MEMORY;
6772 goto out;
6775 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6776 attrs, replace_if_exists);
6778 close_file(req, fsp, NORMAL_CLOSE);
6780 if (!NT_STATUS_IS_OK(status)) {
6781 DEBUG(3, ("rename_internals_fsp returned %s for "
6782 "rename %s -> %s\n", nt_errstr(status),
6783 smb_fname_str_dbg(smb_fname_src),
6784 smb_fname_str_dbg(smb_fname_dst)));
6785 break;
6788 count++;
6790 DEBUG(3,("rename_internals: doing rename on %s -> "
6791 "%s\n", smb_fname_str_dbg(smb_fname_src),
6792 smb_fname_str_dbg(smb_fname_src)));
6793 TALLOC_FREE(talloced);
6795 TALLOC_FREE(dir_hnd);
6797 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
6798 status = map_nt_error_from_unix(errno);
6801 out:
6802 TALLOC_FREE(talloced);
6803 TALLOC_FREE(fname_src_dir);
6804 TALLOC_FREE(fname_src_mask);
6805 return status;
6808 /****************************************************************************
6809 Reply to a mv.
6810 ****************************************************************************/
6812 void reply_mv(struct smb_request *req)
6814 connection_struct *conn = req->conn;
6815 char *name = NULL;
6816 char *newname = NULL;
6817 const char *p;
6818 uint32 attrs;
6819 NTSTATUS status;
6820 bool src_has_wcard = False;
6821 bool dest_has_wcard = False;
6822 TALLOC_CTX *ctx = talloc_tos();
6823 struct smb_filename *smb_fname_src = NULL;
6824 struct smb_filename *smb_fname_dst = NULL;
6825 uint32_t src_ucf_flags = lp_posix_pathnames() ? UCF_UNIX_NAME_LOOKUP : UCF_COND_ALLOW_WCARD_LCOMP;
6826 uint32_t dst_ucf_flags = UCF_SAVE_LCOMP | (lp_posix_pathnames() ? 0 : UCF_COND_ALLOW_WCARD_LCOMP);
6827 bool stream_rename = false;
6829 START_PROFILE(SMBmv);
6831 if (req->wct < 1) {
6832 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6833 goto out;
6836 attrs = SVAL(req->vwv+0, 0);
6838 p = (const char *)req->buf + 1;
6839 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
6840 &status, &src_has_wcard);
6841 if (!NT_STATUS_IS_OK(status)) {
6842 reply_nterror(req, status);
6843 goto out;
6845 p++;
6846 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
6847 &status, &dest_has_wcard);
6848 if (!NT_STATUS_IS_OK(status)) {
6849 reply_nterror(req, status);
6850 goto out;
6853 if (!lp_posix_pathnames()) {
6854 /* The newname must begin with a ':' if the
6855 name contains a ':'. */
6856 if (strchr_m(name, ':')) {
6857 if (newname[0] != ':') {
6858 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6859 goto out;
6861 stream_rename = true;
6865 status = filename_convert(ctx,
6866 conn,
6867 req->flags2 & FLAGS2_DFS_PATHNAMES,
6868 name,
6869 src_ucf_flags,
6870 &src_has_wcard,
6871 &smb_fname_src);
6873 if (!NT_STATUS_IS_OK(status)) {
6874 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6875 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6876 ERRSRV, ERRbadpath);
6877 goto out;
6879 reply_nterror(req, status);
6880 goto out;
6883 status = filename_convert(ctx,
6884 conn,
6885 req->flags2 & FLAGS2_DFS_PATHNAMES,
6886 newname,
6887 dst_ucf_flags,
6888 &dest_has_wcard,
6889 &smb_fname_dst);
6891 if (!NT_STATUS_IS_OK(status)) {
6892 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6893 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6894 ERRSRV, ERRbadpath);
6895 goto out;
6897 reply_nterror(req, status);
6898 goto out;
6901 if (stream_rename) {
6902 /* smb_fname_dst->base_name must be the same as
6903 smb_fname_src->base_name. */
6904 TALLOC_FREE(smb_fname_dst->base_name);
6905 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
6906 smb_fname_src->base_name);
6907 if (!smb_fname_dst->base_name) {
6908 reply_nterror(req, NT_STATUS_NO_MEMORY);
6909 goto out;
6913 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
6914 smb_fname_str_dbg(smb_fname_dst)));
6916 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
6917 attrs, False, src_has_wcard, dest_has_wcard,
6918 DELETE_ACCESS);
6919 if (!NT_STATUS_IS_OK(status)) {
6920 if (open_was_deferred(req->sconn, req->mid)) {
6921 /* We have re-scheduled this call. */
6922 goto out;
6924 reply_nterror(req, status);
6925 goto out;
6928 reply_outbuf(req, 0, 0);
6929 out:
6930 TALLOC_FREE(smb_fname_src);
6931 TALLOC_FREE(smb_fname_dst);
6932 END_PROFILE(SMBmv);
6933 return;
6936 /*******************************************************************
6937 Copy a file as part of a reply_copy.
6938 ******************************************************************/
6941 * TODO: check error codes on all callers
6944 NTSTATUS copy_file(TALLOC_CTX *ctx,
6945 connection_struct *conn,
6946 struct smb_filename *smb_fname_src,
6947 struct smb_filename *smb_fname_dst,
6948 int ofun,
6949 int count,
6950 bool target_is_directory)
6952 struct smb_filename *smb_fname_dst_tmp = NULL;
6953 off_t ret=-1;
6954 files_struct *fsp1,*fsp2;
6955 uint32 dosattrs;
6956 uint32 new_create_disposition;
6957 NTSTATUS status;
6960 status = copy_smb_filename(ctx, smb_fname_dst, &smb_fname_dst_tmp);
6961 if (!NT_STATUS_IS_OK(status)) {
6962 return status;
6966 * If the target is a directory, extract the last component from the
6967 * src filename and append it to the dst filename
6969 if (target_is_directory) {
6970 const char *p;
6972 /* dest/target can't be a stream if it's a directory. */
6973 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
6975 p = strrchr_m(smb_fname_src->base_name,'/');
6976 if (p) {
6977 p++;
6978 } else {
6979 p = smb_fname_src->base_name;
6981 smb_fname_dst_tmp->base_name =
6982 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
6984 if (!smb_fname_dst_tmp->base_name) {
6985 status = NT_STATUS_NO_MEMORY;
6986 goto out;
6990 status = vfs_file_exist(conn, smb_fname_src);
6991 if (!NT_STATUS_IS_OK(status)) {
6992 goto out;
6995 if (!target_is_directory && count) {
6996 new_create_disposition = FILE_OPEN;
6997 } else {
6998 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
6999 0, ofun,
7000 NULL, NULL,
7001 &new_create_disposition,
7002 NULL,
7003 NULL)) {
7004 status = NT_STATUS_INVALID_PARAMETER;
7005 goto out;
7009 /* Open the src file for reading. */
7010 status = SMB_VFS_CREATE_FILE(
7011 conn, /* conn */
7012 NULL, /* req */
7013 0, /* root_dir_fid */
7014 smb_fname_src, /* fname */
7015 FILE_GENERIC_READ, /* access_mask */
7016 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7017 FILE_OPEN, /* create_disposition*/
7018 0, /* create_options */
7019 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
7020 INTERNAL_OPEN_ONLY, /* oplock_request */
7021 0, /* allocation_size */
7022 0, /* private_flags */
7023 NULL, /* sd */
7024 NULL, /* ea_list */
7025 &fsp1, /* result */
7026 NULL); /* psbuf */
7028 if (!NT_STATUS_IS_OK(status)) {
7029 goto out;
7032 dosattrs = dos_mode(conn, smb_fname_src);
7034 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
7035 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
7038 /* Open the dst file for writing. */
7039 status = SMB_VFS_CREATE_FILE(
7040 conn, /* conn */
7041 NULL, /* req */
7042 0, /* root_dir_fid */
7043 smb_fname_dst, /* fname */
7044 FILE_GENERIC_WRITE, /* access_mask */
7045 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7046 new_create_disposition, /* create_disposition*/
7047 0, /* create_options */
7048 dosattrs, /* file_attributes */
7049 INTERNAL_OPEN_ONLY, /* oplock_request */
7050 0, /* allocation_size */
7051 0, /* private_flags */
7052 NULL, /* sd */
7053 NULL, /* ea_list */
7054 &fsp2, /* result */
7055 NULL); /* psbuf */
7057 if (!NT_STATUS_IS_OK(status)) {
7058 close_file(NULL, fsp1, ERROR_CLOSE);
7059 goto out;
7062 if (ofun & OPENX_FILE_EXISTS_OPEN) {
7063 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
7064 if (ret == -1) {
7065 DEBUG(0, ("error - vfs lseek returned error %s\n",
7066 strerror(errno)));
7067 status = map_nt_error_from_unix(errno);
7068 close_file(NULL, fsp1, ERROR_CLOSE);
7069 close_file(NULL, fsp2, ERROR_CLOSE);
7070 goto out;
7074 /* Do the actual copy. */
7075 if (smb_fname_src->st.st_ex_size) {
7076 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
7077 } else {
7078 ret = 0;
7081 close_file(NULL, fsp1, NORMAL_CLOSE);
7083 /* Ensure the modtime is set correctly on the destination file. */
7084 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
7087 * As we are opening fsp1 read-only we only expect
7088 * an error on close on fsp2 if we are out of space.
7089 * Thus we don't look at the error return from the
7090 * close of fsp1.
7092 status = close_file(NULL, fsp2, NORMAL_CLOSE);
7094 if (!NT_STATUS_IS_OK(status)) {
7095 goto out;
7098 if (ret != (off_t)smb_fname_src->st.st_ex_size) {
7099 status = NT_STATUS_DISK_FULL;
7100 goto out;
7103 status = NT_STATUS_OK;
7105 out:
7106 TALLOC_FREE(smb_fname_dst_tmp);
7107 return status;
7110 /****************************************************************************
7111 Reply to a file copy.
7112 ****************************************************************************/
7114 void reply_copy(struct smb_request *req)
7116 connection_struct *conn = req->conn;
7117 struct smb_filename *smb_fname_src = NULL;
7118 struct smb_filename *smb_fname_dst = NULL;
7119 char *fname_src = NULL;
7120 char *fname_dst = NULL;
7121 char *fname_src_mask = NULL;
7122 char *fname_src_dir = NULL;
7123 const char *p;
7124 int count=0;
7125 int error = ERRnoaccess;
7126 int tid2;
7127 int ofun;
7128 int flags;
7129 bool target_is_directory=False;
7130 bool source_has_wild = False;
7131 bool dest_has_wild = False;
7132 NTSTATUS status;
7133 TALLOC_CTX *ctx = talloc_tos();
7135 START_PROFILE(SMBcopy);
7137 if (req->wct < 3) {
7138 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7139 goto out;
7142 tid2 = SVAL(req->vwv+0, 0);
7143 ofun = SVAL(req->vwv+1, 0);
7144 flags = SVAL(req->vwv+2, 0);
7146 p = (const char *)req->buf;
7147 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
7148 &status, &source_has_wild);
7149 if (!NT_STATUS_IS_OK(status)) {
7150 reply_nterror(req, status);
7151 goto out;
7153 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
7154 &status, &dest_has_wild);
7155 if (!NT_STATUS_IS_OK(status)) {
7156 reply_nterror(req, status);
7157 goto out;
7160 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
7162 if (tid2 != conn->cnum) {
7163 /* can't currently handle inter share copies XXXX */
7164 DEBUG(3,("Rejecting inter-share copy\n"));
7165 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
7166 goto out;
7169 status = filename_convert(ctx, conn,
7170 req->flags2 & FLAGS2_DFS_PATHNAMES,
7171 fname_src,
7172 UCF_COND_ALLOW_WCARD_LCOMP,
7173 &source_has_wild,
7174 &smb_fname_src);
7175 if (!NT_STATUS_IS_OK(status)) {
7176 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7177 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7178 ERRSRV, ERRbadpath);
7179 goto out;
7181 reply_nterror(req, status);
7182 goto out;
7185 status = filename_convert(ctx, conn,
7186 req->flags2 & FLAGS2_DFS_PATHNAMES,
7187 fname_dst,
7188 UCF_COND_ALLOW_WCARD_LCOMP,
7189 &dest_has_wild,
7190 &smb_fname_dst);
7191 if (!NT_STATUS_IS_OK(status)) {
7192 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7193 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7194 ERRSRV, ERRbadpath);
7195 goto out;
7197 reply_nterror(req, status);
7198 goto out;
7201 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
7203 if ((flags&1) && target_is_directory) {
7204 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
7205 goto out;
7208 if ((flags&2) && !target_is_directory) {
7209 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
7210 goto out;
7213 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
7214 /* wants a tree copy! XXXX */
7215 DEBUG(3,("Rejecting tree copy\n"));
7216 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7217 goto out;
7220 /* Split up the directory from the filename/mask. */
7221 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7222 &fname_src_dir, &fname_src_mask);
7223 if (!NT_STATUS_IS_OK(status)) {
7224 reply_nterror(req, NT_STATUS_NO_MEMORY);
7225 goto out;
7229 * We should only check the mangled cache
7230 * here if unix_convert failed. This means
7231 * that the path in 'mask' doesn't exist
7232 * on the file system and so we need to look
7233 * for a possible mangle. This patch from
7234 * Tine Smukavec <valentin.smukavec@hermes.si>.
7236 if (!VALID_STAT(smb_fname_src->st) &&
7237 mangle_is_mangled(fname_src_mask, conn->params)) {
7238 char *new_mask = NULL;
7239 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
7240 &new_mask, conn->params);
7242 /* Use demangled name if one was successfully found. */
7243 if (new_mask) {
7244 TALLOC_FREE(fname_src_mask);
7245 fname_src_mask = new_mask;
7249 if (!source_has_wild) {
7252 * Only one file needs to be copied. Append the mask back onto
7253 * the directory.
7255 TALLOC_FREE(smb_fname_src->base_name);
7256 if (ISDOT(fname_src_dir)) {
7257 /* Ensure we use canonical names on open. */
7258 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7259 "%s",
7260 fname_src_mask);
7261 } else {
7262 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7263 "%s/%s",
7264 fname_src_dir,
7265 fname_src_mask);
7267 if (!smb_fname_src->base_name) {
7268 reply_nterror(req, NT_STATUS_NO_MEMORY);
7269 goto out;
7272 if (dest_has_wild) {
7273 char *fname_dst_mod = NULL;
7274 if (!resolve_wildcards(smb_fname_dst,
7275 smb_fname_src->base_name,
7276 smb_fname_dst->base_name,
7277 &fname_dst_mod)) {
7278 reply_nterror(req, NT_STATUS_NO_MEMORY);
7279 goto out;
7281 TALLOC_FREE(smb_fname_dst->base_name);
7282 smb_fname_dst->base_name = fname_dst_mod;
7285 status = check_name(conn, smb_fname_src->base_name);
7286 if (!NT_STATUS_IS_OK(status)) {
7287 reply_nterror(req, status);
7288 goto out;
7291 status = check_name(conn, smb_fname_dst->base_name);
7292 if (!NT_STATUS_IS_OK(status)) {
7293 reply_nterror(req, status);
7294 goto out;
7297 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7298 ofun, count, target_is_directory);
7300 if(!NT_STATUS_IS_OK(status)) {
7301 reply_nterror(req, status);
7302 goto out;
7303 } else {
7304 count++;
7306 } else {
7307 struct smb_Dir *dir_hnd = NULL;
7308 const char *dname = NULL;
7309 char *talloced = NULL;
7310 long offset = 0;
7313 * There is a wildcard that requires us to actually read the
7314 * src dir and copy each file matching the mask to the dst.
7315 * Right now streams won't be copied, but this could
7316 * presumably be added with a nested loop for reach dir entry.
7318 SMB_ASSERT(!smb_fname_src->stream_name);
7319 SMB_ASSERT(!smb_fname_dst->stream_name);
7321 smb_fname_src->stream_name = NULL;
7322 smb_fname_dst->stream_name = NULL;
7324 if (strequal(fname_src_mask,"????????.???")) {
7325 TALLOC_FREE(fname_src_mask);
7326 fname_src_mask = talloc_strdup(ctx, "*");
7327 if (!fname_src_mask) {
7328 reply_nterror(req, NT_STATUS_NO_MEMORY);
7329 goto out;
7333 status = check_name(conn, fname_src_dir);
7334 if (!NT_STATUS_IS_OK(status)) {
7335 reply_nterror(req, status);
7336 goto out;
7339 dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0);
7340 if (dir_hnd == NULL) {
7341 status = map_nt_error_from_unix(errno);
7342 reply_nterror(req, status);
7343 goto out;
7346 error = ERRbadfile;
7348 /* Iterate over the src dir copying each entry to the dst. */
7349 while ((dname = ReadDirName(dir_hnd, &offset,
7350 &smb_fname_src->st, &talloced))) {
7351 char *destname = NULL;
7353 if (ISDOT(dname) || ISDOTDOT(dname)) {
7354 TALLOC_FREE(talloced);
7355 continue;
7358 if (!is_visible_file(conn, fname_src_dir, dname,
7359 &smb_fname_src->st, false)) {
7360 TALLOC_FREE(talloced);
7361 continue;
7364 if(!mask_match(dname, fname_src_mask,
7365 conn->case_sensitive)) {
7366 TALLOC_FREE(talloced);
7367 continue;
7370 error = ERRnoaccess;
7372 /* Get the src smb_fname struct setup. */
7373 TALLOC_FREE(smb_fname_src->base_name);
7374 if (ISDOT(fname_src_dir)) {
7375 /* Ensure we use canonical names on open. */
7376 smb_fname_src->base_name =
7377 talloc_asprintf(smb_fname_src, "%s",
7378 dname);
7379 } else {
7380 smb_fname_src->base_name =
7381 talloc_asprintf(smb_fname_src, "%s/%s",
7382 fname_src_dir, dname);
7385 if (!smb_fname_src->base_name) {
7386 TALLOC_FREE(dir_hnd);
7387 TALLOC_FREE(talloced);
7388 reply_nterror(req, NT_STATUS_NO_MEMORY);
7389 goto out;
7392 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7393 smb_fname_dst->base_name,
7394 &destname)) {
7395 TALLOC_FREE(talloced);
7396 continue;
7398 if (!destname) {
7399 TALLOC_FREE(dir_hnd);
7400 TALLOC_FREE(talloced);
7401 reply_nterror(req, NT_STATUS_NO_MEMORY);
7402 goto out;
7405 TALLOC_FREE(smb_fname_dst->base_name);
7406 smb_fname_dst->base_name = destname;
7408 status = check_name(conn, smb_fname_src->base_name);
7409 if (!NT_STATUS_IS_OK(status)) {
7410 TALLOC_FREE(dir_hnd);
7411 TALLOC_FREE(talloced);
7412 reply_nterror(req, status);
7413 goto out;
7416 status = check_name(conn, smb_fname_dst->base_name);
7417 if (!NT_STATUS_IS_OK(status)) {
7418 TALLOC_FREE(dir_hnd);
7419 TALLOC_FREE(talloced);
7420 reply_nterror(req, status);
7421 goto out;
7424 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7425 smb_fname_src->base_name,
7426 smb_fname_dst->base_name));
7428 status = copy_file(ctx, conn, smb_fname_src,
7429 smb_fname_dst, ofun, count,
7430 target_is_directory);
7431 if (NT_STATUS_IS_OK(status)) {
7432 count++;
7435 TALLOC_FREE(talloced);
7437 TALLOC_FREE(dir_hnd);
7440 if (count == 0) {
7441 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7442 goto out;
7445 reply_outbuf(req, 1, 0);
7446 SSVAL(req->outbuf,smb_vwv0,count);
7447 out:
7448 TALLOC_FREE(smb_fname_src);
7449 TALLOC_FREE(smb_fname_dst);
7450 TALLOC_FREE(fname_src);
7451 TALLOC_FREE(fname_dst);
7452 TALLOC_FREE(fname_src_mask);
7453 TALLOC_FREE(fname_src_dir);
7455 END_PROFILE(SMBcopy);
7456 return;
7459 #undef DBGC_CLASS
7460 #define DBGC_CLASS DBGC_LOCKING
7462 /****************************************************************************
7463 Get a lock pid, dealing with large count requests.
7464 ****************************************************************************/
7466 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7467 bool large_file_format)
7469 if(!large_file_format)
7470 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7471 else
7472 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7475 /****************************************************************************
7476 Get a lock count, dealing with large count requests.
7477 ****************************************************************************/
7479 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7480 bool large_file_format)
7482 uint64_t count = 0;
7484 if(!large_file_format) {
7485 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7486 } else {
7488 #if defined(HAVE_LONGLONG)
7489 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7490 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7491 #else /* HAVE_LONGLONG */
7494 * NT4.x seems to be broken in that it sends large file (64 bit)
7495 * lockingX calls even if the CAP_LARGE_FILES was *not*
7496 * negotiated. For boxes without large unsigned ints truncate the
7497 * lock count by dropping the top 32 bits.
7500 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
7501 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
7502 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
7503 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
7504 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
7507 count = (uint64_t)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
7508 #endif /* HAVE_LONGLONG */
7511 return count;
7514 #if !defined(HAVE_LONGLONG)
7515 /****************************************************************************
7516 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
7517 ****************************************************************************/
7519 static uint32 map_lock_offset(uint32 high, uint32 low)
7521 unsigned int i;
7522 uint32 mask = 0;
7523 uint32 highcopy = high;
7526 * Try and find out how many significant bits there are in high.
7529 for(i = 0; highcopy; i++)
7530 highcopy >>= 1;
7533 * We use 31 bits not 32 here as POSIX
7534 * lock offsets may not be negative.
7537 mask = (~0) << (31 - i);
7539 if(low & mask)
7540 return 0; /* Fail. */
7542 high <<= (31 - i);
7544 return (high|low);
7546 #endif /* !defined(HAVE_LONGLONG) */
7548 /****************************************************************************
7549 Get a lock offset, dealing with large offset requests.
7550 ****************************************************************************/
7552 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7553 bool large_file_format, bool *err)
7555 uint64_t offset = 0;
7557 *err = False;
7559 if(!large_file_format) {
7560 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7561 } else {
7563 #if defined(HAVE_LONGLONG)
7564 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7565 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7566 #else /* HAVE_LONGLONG */
7569 * NT4.x seems to be broken in that it sends large file (64 bit)
7570 * lockingX calls even if the CAP_LARGE_FILES was *not*
7571 * negotiated. For boxes without large unsigned ints mangle the
7572 * lock offset by mapping the top 32 bits onto the lower 32.
7575 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
7576 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7577 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
7578 uint32 new_low = 0;
7580 if((new_low = map_lock_offset(high, low)) == 0) {
7581 *err = True;
7582 return (uint64_t)-1;
7585 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
7586 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
7587 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
7588 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
7591 offset = (uint64_t)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7592 #endif /* HAVE_LONGLONG */
7595 return offset;
7598 NTSTATUS smbd_do_locking(struct smb_request *req,
7599 files_struct *fsp,
7600 uint8_t type,
7601 int32_t timeout,
7602 uint16_t num_ulocks,
7603 struct smbd_lock_element *ulocks,
7604 uint16_t num_locks,
7605 struct smbd_lock_element *locks,
7606 bool *async)
7608 connection_struct *conn = req->conn;
7609 int i;
7610 NTSTATUS status = NT_STATUS_OK;
7612 *async = false;
7614 /* Data now points at the beginning of the list
7615 of smb_unlkrng structs */
7616 for(i = 0; i < (int)num_ulocks; i++) {
7617 struct smbd_lock_element *e = &ulocks[i];
7619 DEBUG(10,("smbd_do_locking: unlock start=%.0f, len=%.0f for "
7620 "pid %u, file %s\n",
7621 (double)e->offset,
7622 (double)e->count,
7623 (unsigned int)e->smblctx,
7624 fsp_str_dbg(fsp)));
7626 if (e->brltype != UNLOCK_LOCK) {
7627 /* this can only happen with SMB2 */
7628 return NT_STATUS_INVALID_PARAMETER;
7631 status = do_unlock(req->sconn->msg_ctx,
7632 fsp,
7633 e->smblctx,
7634 e->count,
7635 e->offset,
7636 WINDOWS_LOCK);
7638 DEBUG(10, ("smbd_do_locking: unlock returned %s\n",
7639 nt_errstr(status)));
7641 if (!NT_STATUS_IS_OK(status)) {
7642 return status;
7646 /* Setup the timeout in seconds. */
7648 if (!lp_blocking_locks(SNUM(conn))) {
7649 timeout = 0;
7652 /* Data now points at the beginning of the list
7653 of smb_lkrng structs */
7655 for(i = 0; i < (int)num_locks; i++) {
7656 struct smbd_lock_element *e = &locks[i];
7658 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
7659 "%llu, file %s timeout = %d\n",
7660 (double)e->offset,
7661 (double)e->count,
7662 (unsigned long long)e->smblctx,
7663 fsp_str_dbg(fsp),
7664 (int)timeout));
7666 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7667 struct blocking_lock_record *blr = NULL;
7669 if (num_locks > 1) {
7671 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
7672 * if the lock vector contains one entry. When given mutliple cancel
7673 * requests in a single PDU we expect the server to return an
7674 * error. Windows servers seem to accept the request but only
7675 * cancel the first lock.
7676 * JRA - Do what Windows does (tm) :-).
7679 #if 0
7680 /* MS-CIFS (2.2.4.32.1) behavior. */
7681 return NT_STATUS_DOS(ERRDOS,
7682 ERRcancelviolation);
7683 #else
7684 /* Windows behavior. */
7685 if (i != 0) {
7686 DEBUG(10,("smbd_do_locking: ignoring subsequent "
7687 "cancel request\n"));
7688 continue;
7690 #endif
7693 if (lp_blocking_locks(SNUM(conn))) {
7695 /* Schedule a message to ourselves to
7696 remove the blocking lock record and
7697 return the right error. */
7699 blr = blocking_lock_cancel_smb1(fsp,
7700 e->smblctx,
7701 e->offset,
7702 e->count,
7703 WINDOWS_LOCK,
7704 type,
7705 NT_STATUS_FILE_LOCK_CONFLICT);
7706 if (blr == NULL) {
7707 return NT_STATUS_DOS(
7708 ERRDOS,
7709 ERRcancelviolation);
7712 /* Remove a matching pending lock. */
7713 status = do_lock_cancel(fsp,
7714 e->smblctx,
7715 e->count,
7716 e->offset,
7717 WINDOWS_LOCK,
7718 blr);
7719 } else {
7720 bool blocking_lock = timeout ? true : false;
7721 bool defer_lock = false;
7722 struct byte_range_lock *br_lck;
7723 uint64_t block_smblctx;
7725 br_lck = do_lock(req->sconn->msg_ctx,
7726 fsp,
7727 e->smblctx,
7728 e->count,
7729 e->offset,
7730 e->brltype,
7731 WINDOWS_LOCK,
7732 blocking_lock,
7733 &status,
7734 &block_smblctx,
7735 NULL);
7737 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
7738 /* Windows internal resolution for blocking locks seems
7739 to be about 200ms... Don't wait for less than that. JRA. */
7740 if (timeout != -1 && timeout < lp_lock_spin_time()) {
7741 timeout = lp_lock_spin_time();
7743 defer_lock = true;
7746 /* If a lock sent with timeout of zero would fail, and
7747 * this lock has been requested multiple times,
7748 * according to brl_lock_failed() we convert this
7749 * request to a blocking lock with a timeout of between
7750 * 150 - 300 milliseconds.
7752 * If lp_lock_spin_time() has been set to 0, we skip
7753 * this blocking retry and fail immediately.
7755 * Replacement for do_lock_spin(). JRA. */
7757 if (!req->sconn->using_smb2 &&
7758 br_lck && lp_blocking_locks(SNUM(conn)) &&
7759 lp_lock_spin_time() && !blocking_lock &&
7760 NT_STATUS_EQUAL((status),
7761 NT_STATUS_FILE_LOCK_CONFLICT))
7763 defer_lock = true;
7764 timeout = lp_lock_spin_time();
7767 if (br_lck && defer_lock) {
7769 * A blocking lock was requested. Package up
7770 * this smb into a queued request and push it
7771 * onto the blocking lock queue.
7773 if(push_blocking_lock_request(br_lck,
7774 req,
7775 fsp,
7776 timeout,
7778 e->smblctx,
7779 e->brltype,
7780 WINDOWS_LOCK,
7781 e->offset,
7782 e->count,
7783 block_smblctx)) {
7784 TALLOC_FREE(br_lck);
7785 *async = true;
7786 return NT_STATUS_OK;
7790 TALLOC_FREE(br_lck);
7793 if (!NT_STATUS_IS_OK(status)) {
7794 break;
7798 /* If any of the above locks failed, then we must unlock
7799 all of the previous locks (X/Open spec). */
7801 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
7803 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7804 i = -1; /* we want to skip the for loop */
7808 * Ensure we don't do a remove on the lock that just failed,
7809 * as under POSIX rules, if we have a lock already there, we
7810 * will delete it (and we shouldn't) .....
7812 for(i--; i >= 0; i--) {
7813 struct smbd_lock_element *e = &locks[i];
7815 do_unlock(req->sconn->msg_ctx,
7816 fsp,
7817 e->smblctx,
7818 e->count,
7819 e->offset,
7820 WINDOWS_LOCK);
7822 return status;
7825 DEBUG(3, ("smbd_do_locking: %s type=%d num_locks=%d num_ulocks=%d\n",
7826 fsp_fnum_dbg(fsp), (unsigned int)type, num_locks, num_ulocks));
7828 return NT_STATUS_OK;
7831 /****************************************************************************
7832 Reply to a lockingX request.
7833 ****************************************************************************/
7835 void reply_lockingX(struct smb_request *req)
7837 connection_struct *conn = req->conn;
7838 files_struct *fsp;
7839 unsigned char locktype;
7840 unsigned char oplocklevel;
7841 uint16 num_ulocks;
7842 uint16 num_locks;
7843 int32 lock_timeout;
7844 int i;
7845 const uint8_t *data;
7846 bool large_file_format;
7847 bool err;
7848 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
7849 struct smbd_lock_element *ulocks;
7850 struct smbd_lock_element *locks;
7851 bool async = false;
7853 START_PROFILE(SMBlockingX);
7855 if (req->wct < 8) {
7856 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7857 END_PROFILE(SMBlockingX);
7858 return;
7861 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
7862 locktype = CVAL(req->vwv+3, 0);
7863 oplocklevel = CVAL(req->vwv+3, 1);
7864 num_ulocks = SVAL(req->vwv+6, 0);
7865 num_locks = SVAL(req->vwv+7, 0);
7866 lock_timeout = IVAL(req->vwv+4, 0);
7867 large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
7869 if (!check_fsp(conn, req, fsp)) {
7870 END_PROFILE(SMBlockingX);
7871 return;
7874 data = req->buf;
7876 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
7877 /* we don't support these - and CANCEL_LOCK makes w2k
7878 and XP reboot so I don't really want to be
7879 compatible! (tridge) */
7880 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
7881 END_PROFILE(SMBlockingX);
7882 return;
7885 /* Check if this is an oplock break on a file
7886 we have granted an oplock on.
7888 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
7889 /* Client can insist on breaking to none. */
7890 bool break_to_none = (oplocklevel == 0);
7891 bool result;
7893 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
7894 "for %s\n", (unsigned int)oplocklevel,
7895 fsp_fnum_dbg(fsp)));
7898 * Make sure we have granted an exclusive or batch oplock on
7899 * this file.
7902 if (fsp->oplock_type == 0) {
7904 /* The Samba4 nbench simulator doesn't understand
7905 the difference between break to level2 and break
7906 to none from level2 - it sends oplock break
7907 replies in both cases. Don't keep logging an error
7908 message here - just ignore it. JRA. */
7910 DEBUG(5,("reply_lockingX: Error : oplock break from "
7911 "client for %s (oplock=%d) and no "
7912 "oplock granted on this file (%s).\n",
7913 fsp_fnum_dbg(fsp), fsp->oplock_type,
7914 fsp_str_dbg(fsp)));
7916 /* if this is a pure oplock break request then don't
7917 * send a reply */
7918 if (num_locks == 0 && num_ulocks == 0) {
7919 END_PROFILE(SMBlockingX);
7920 return;
7921 } else {
7922 END_PROFILE(SMBlockingX);
7923 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
7924 return;
7928 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
7929 (break_to_none)) {
7930 result = remove_oplock(fsp);
7931 } else {
7932 result = downgrade_oplock(fsp);
7935 if (!result) {
7936 DEBUG(0, ("reply_lockingX: error in removing "
7937 "oplock on file %s\n", fsp_str_dbg(fsp)));
7938 /* Hmmm. Is this panic justified? */
7939 smb_panic("internal tdb error");
7942 reply_to_oplock_break_requests(fsp);
7944 /* if this is a pure oplock break request then don't send a
7945 * reply */
7946 if (num_locks == 0 && num_ulocks == 0) {
7947 /* Sanity check - ensure a pure oplock break is not a
7948 chained request. */
7949 if(CVAL(req->vwv+0, 0) != 0xff)
7950 DEBUG(0,("reply_lockingX: Error : pure oplock "
7951 "break is a chained %d request !\n",
7952 (unsigned int)CVAL(req->vwv+0, 0)));
7953 END_PROFILE(SMBlockingX);
7954 return;
7958 if (req->buflen <
7959 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
7960 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7961 END_PROFILE(SMBlockingX);
7962 return;
7965 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
7966 if (ulocks == NULL) {
7967 reply_nterror(req, NT_STATUS_NO_MEMORY);
7968 END_PROFILE(SMBlockingX);
7969 return;
7972 locks = talloc_array(req, struct smbd_lock_element, num_locks);
7973 if (locks == NULL) {
7974 reply_nterror(req, NT_STATUS_NO_MEMORY);
7975 END_PROFILE(SMBlockingX);
7976 return;
7979 /* Data now points at the beginning of the list
7980 of smb_unlkrng structs */
7981 for(i = 0; i < (int)num_ulocks; i++) {
7982 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
7983 ulocks[i].count = get_lock_count(data, i, large_file_format);
7984 ulocks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7985 ulocks[i].brltype = UNLOCK_LOCK;
7988 * There is no error code marked "stupid client bug".... :-).
7990 if(err) {
7991 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7992 END_PROFILE(SMBlockingX);
7993 return;
7997 /* Now do any requested locks */
7998 data += ((large_file_format ? 20 : 10)*num_ulocks);
8000 /* Data now points at the beginning of the list
8001 of smb_lkrng structs */
8003 for(i = 0; i < (int)num_locks; i++) {
8004 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
8005 locks[i].count = get_lock_count(data, i, large_file_format);
8006 locks[i].offset = get_lock_offset(data, i, large_file_format, &err);
8008 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
8009 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8010 locks[i].brltype = PENDING_READ_LOCK;
8011 } else {
8012 locks[i].brltype = READ_LOCK;
8014 } else {
8015 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8016 locks[i].brltype = PENDING_WRITE_LOCK;
8017 } else {
8018 locks[i].brltype = WRITE_LOCK;
8023 * There is no error code marked "stupid client bug".... :-).
8025 if(err) {
8026 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8027 END_PROFILE(SMBlockingX);
8028 return;
8032 status = smbd_do_locking(req, fsp,
8033 locktype, lock_timeout,
8034 num_ulocks, ulocks,
8035 num_locks, locks,
8036 &async);
8037 if (!NT_STATUS_IS_OK(status)) {
8038 END_PROFILE(SMBlockingX);
8039 reply_nterror(req, status);
8040 return;
8042 if (async) {
8043 END_PROFILE(SMBlockingX);
8044 return;
8047 reply_outbuf(req, 2, 0);
8048 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
8049 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
8051 DEBUG(3, ("lockingX %s type=%d num_locks=%d num_ulocks=%d\n",
8052 fsp_fnum_dbg(fsp), (unsigned int)locktype, num_locks, num_ulocks));
8054 END_PROFILE(SMBlockingX);
8057 #undef DBGC_CLASS
8058 #define DBGC_CLASS DBGC_ALL
8060 /****************************************************************************
8061 Reply to a SMBreadbmpx (read block multiplex) request.
8062 Always reply with an error, if someone has a platform really needs this,
8063 please contact vl@samba.org
8064 ****************************************************************************/
8066 void reply_readbmpx(struct smb_request *req)
8068 START_PROFILE(SMBreadBmpx);
8069 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8070 END_PROFILE(SMBreadBmpx);
8071 return;
8074 /****************************************************************************
8075 Reply to a SMBreadbs (read block multiplex secondary) request.
8076 Always reply with an error, if someone has a platform really needs this,
8077 please contact vl@samba.org
8078 ****************************************************************************/
8080 void reply_readbs(struct smb_request *req)
8082 START_PROFILE(SMBreadBs);
8083 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8084 END_PROFILE(SMBreadBs);
8085 return;
8088 /****************************************************************************
8089 Reply to a SMBsetattrE.
8090 ****************************************************************************/
8092 void reply_setattrE(struct smb_request *req)
8094 connection_struct *conn = req->conn;
8095 struct smb_file_time ft;
8096 files_struct *fsp;
8097 NTSTATUS status;
8099 START_PROFILE(SMBsetattrE);
8100 ZERO_STRUCT(ft);
8102 if (req->wct < 7) {
8103 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8104 goto out;
8107 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8109 if(!fsp || (fsp->conn != conn)) {
8110 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8111 goto out;
8115 * Convert the DOS times into unix times.
8118 ft.atime = convert_time_t_to_timespec(
8119 srv_make_unix_date2(req->vwv+3));
8120 ft.mtime = convert_time_t_to_timespec(
8121 srv_make_unix_date2(req->vwv+5));
8122 ft.create_time = convert_time_t_to_timespec(
8123 srv_make_unix_date2(req->vwv+1));
8125 reply_outbuf(req, 0, 0);
8128 * Patch from Ray Frush <frush@engr.colostate.edu>
8129 * Sometimes times are sent as zero - ignore them.
8132 /* Ensure we have a valid stat struct for the source. */
8133 status = vfs_stat_fsp(fsp);
8134 if (!NT_STATUS_IS_OK(status)) {
8135 reply_nterror(req, status);
8136 goto out;
8139 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
8140 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8141 goto out;
8144 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
8145 if (!NT_STATUS_IS_OK(status)) {
8146 reply_nterror(req, status);
8147 goto out;
8150 DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
8151 " createtime=%u\n",
8152 fsp_fnum_dbg(fsp),
8153 (unsigned int)ft.atime.tv_sec,
8154 (unsigned int)ft.mtime.tv_sec,
8155 (unsigned int)ft.create_time.tv_sec
8157 out:
8158 END_PROFILE(SMBsetattrE);
8159 return;
8163 /* Back from the dead for OS/2..... JRA. */
8165 /****************************************************************************
8166 Reply to a SMBwritebmpx (write block multiplex primary) request.
8167 Always reply with an error, if someone has a platform really needs this,
8168 please contact vl@samba.org
8169 ****************************************************************************/
8171 void reply_writebmpx(struct smb_request *req)
8173 START_PROFILE(SMBwriteBmpx);
8174 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8175 END_PROFILE(SMBwriteBmpx);
8176 return;
8179 /****************************************************************************
8180 Reply to a SMBwritebs (write block multiplex secondary) request.
8181 Always reply with an error, if someone has a platform really needs this,
8182 please contact vl@samba.org
8183 ****************************************************************************/
8185 void reply_writebs(struct smb_request *req)
8187 START_PROFILE(SMBwriteBs);
8188 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8189 END_PROFILE(SMBwriteBs);
8190 return;
8193 /****************************************************************************
8194 Reply to a SMBgetattrE.
8195 ****************************************************************************/
8197 void reply_getattrE(struct smb_request *req)
8199 connection_struct *conn = req->conn;
8200 int mode;
8201 files_struct *fsp;
8202 struct timespec create_ts;
8204 START_PROFILE(SMBgetattrE);
8206 if (req->wct < 1) {
8207 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8208 END_PROFILE(SMBgetattrE);
8209 return;
8212 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8214 if(!fsp || (fsp->conn != conn)) {
8215 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8216 END_PROFILE(SMBgetattrE);
8217 return;
8220 /* Do an fstat on this file */
8221 if(fsp_stat(fsp)) {
8222 reply_nterror(req, map_nt_error_from_unix(errno));
8223 END_PROFILE(SMBgetattrE);
8224 return;
8227 mode = dos_mode(conn, fsp->fsp_name);
8230 * Convert the times into dos times. Set create
8231 * date to be last modify date as UNIX doesn't save
8232 * this.
8235 reply_outbuf(req, 11, 0);
8237 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
8238 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
8239 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
8240 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
8241 /* Should we check pending modtime here ? JRA */
8242 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
8243 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
8245 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
8246 SIVAL(req->outbuf, smb_vwv6, 0);
8247 SIVAL(req->outbuf, smb_vwv8, 0);
8248 } else {
8249 uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8250 SIVAL(req->outbuf, smb_vwv6, (uint32)fsp->fsp_name->st.st_ex_size);
8251 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8253 SSVAL(req->outbuf,smb_vwv10, mode);
8255 DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp)));
8257 END_PROFILE(SMBgetattrE);
8258 return;