Fix bug #9724 - is_encrypted_packet() function incorrectly used inside server.
[Samba/gbeck.git] / source3 / smbd / reply.c
blob2c31f159171bef255c5a3fd074222429d3f3cfc2
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) || req->encrypted) {
3298 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3299 "raw reads/writes are disallowed.");
3302 if (req->wct < 8) {
3303 reply_readbraw_error(sconn);
3304 END_PROFILE(SMBreadbraw);
3305 return;
3308 if (sconn->smb1.echo_handler.trusted_fde) {
3309 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3310 "'async smb echo handler = yes'\n"));
3311 reply_readbraw_error(sconn);
3312 END_PROFILE(SMBreadbraw);
3313 return;
3317 * Special check if an oplock break has been issued
3318 * and the readraw request croses on the wire, we must
3319 * return a zero length response here.
3322 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3325 * We have to do a check_fsp by hand here, as
3326 * we must always return 4 zero bytes on error,
3327 * not a NTSTATUS.
3330 if (!fsp || !conn || conn != fsp->conn ||
3331 req->vuid != fsp->vuid ||
3332 fsp->is_directory || fsp->fh->fd == -1) {
3334 * fsp could be NULL here so use the value from the packet. JRA.
3336 DEBUG(3,("reply_readbraw: fnum %d not valid "
3337 "- cache prime?\n",
3338 (int)SVAL(req->vwv+0, 0)));
3339 reply_readbraw_error(sconn);
3340 END_PROFILE(SMBreadbraw);
3341 return;
3344 /* Do a "by hand" version of CHECK_READ. */
3345 if (!(fsp->can_read ||
3346 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3347 (fsp->access_mask & FILE_EXECUTE)))) {
3348 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3349 (int)SVAL(req->vwv+0, 0)));
3350 reply_readbraw_error(sconn);
3351 END_PROFILE(SMBreadbraw);
3352 return;
3355 flush_write_cache(fsp, READRAW_FLUSH);
3357 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3358 if(req->wct == 10) {
3360 * This is a large offset (64 bit) read.
3363 startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32);
3365 if(startpos < 0) {
3366 DEBUG(0,("reply_readbraw: negative 64 bit "
3367 "readraw offset (%.0f) !\n",
3368 (double)startpos ));
3369 reply_readbraw_error(sconn);
3370 END_PROFILE(SMBreadbraw);
3371 return;
3375 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3376 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3378 /* ensure we don't overrun the packet size */
3379 maxcount = MIN(65535,maxcount);
3381 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3382 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3383 &lock);
3385 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3386 reply_readbraw_error(sconn);
3387 END_PROFILE(SMBreadbraw);
3388 return;
3391 if (fsp_stat(fsp) == 0) {
3392 size = fsp->fsp_name->st.st_ex_size;
3395 if (startpos >= size) {
3396 nread = 0;
3397 } else {
3398 nread = MIN(maxcount,(size - startpos));
3401 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3402 if (nread < mincount)
3403 nread = 0;
3404 #endif
3406 DEBUG( 3, ( "reply_readbraw: %s start=%.0f max=%lu "
3407 "min=%lu nread=%lu\n",
3408 fsp_fnum_dbg(fsp), (double)startpos,
3409 (unsigned long)maxcount,
3410 (unsigned long)mincount,
3411 (unsigned long)nread ) );
3413 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3415 DEBUG(5,("reply_readbraw finished\n"));
3417 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3419 END_PROFILE(SMBreadbraw);
3420 return;
3423 #undef DBGC_CLASS
3424 #define DBGC_CLASS DBGC_LOCKING
3426 /****************************************************************************
3427 Reply to a lockread (core+ protocol).
3428 ****************************************************************************/
3430 void reply_lockread(struct smb_request *req)
3432 connection_struct *conn = req->conn;
3433 ssize_t nread = -1;
3434 char *data;
3435 off_t startpos;
3436 size_t numtoread;
3437 NTSTATUS status;
3438 files_struct *fsp;
3439 struct byte_range_lock *br_lck = NULL;
3440 char *p = NULL;
3441 struct smbd_server_connection *sconn = req->sconn;
3443 START_PROFILE(SMBlockread);
3445 if (req->wct < 5) {
3446 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3447 END_PROFILE(SMBlockread);
3448 return;
3451 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3453 if (!check_fsp(conn, req, fsp)) {
3454 END_PROFILE(SMBlockread);
3455 return;
3458 if (!CHECK_READ(fsp,req)) {
3459 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3460 END_PROFILE(SMBlockread);
3461 return;
3464 numtoread = SVAL(req->vwv+1, 0);
3465 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3467 numtoread = MIN(BUFFER_SIZE - (smb_size + 3*2 + 3), numtoread);
3469 reply_outbuf(req, 5, numtoread + 3);
3471 data = smb_buf(req->outbuf) + 3;
3474 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3475 * protocol request that predates the read/write lock concept.
3476 * Thus instead of asking for a read lock here we need to ask
3477 * for a write lock. JRA.
3478 * Note that the requested lock size is unaffected by max_recv.
3481 br_lck = do_lock(req->sconn->msg_ctx,
3482 fsp,
3483 (uint64_t)req->smbpid,
3484 (uint64_t)numtoread,
3485 (uint64_t)startpos,
3486 WRITE_LOCK,
3487 WINDOWS_LOCK,
3488 False, /* Non-blocking lock. */
3489 &status,
3490 NULL,
3491 NULL);
3492 TALLOC_FREE(br_lck);
3494 if (NT_STATUS_V(status)) {
3495 reply_nterror(req, status);
3496 END_PROFILE(SMBlockread);
3497 return;
3501 * However the requested READ size IS affected by max_recv. Insanity.... JRA.
3504 if (numtoread > sconn->smb1.negprot.max_recv) {
3505 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \
3506 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3507 (unsigned int)numtoread,
3508 (unsigned int)sconn->smb1.negprot.max_recv));
3509 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3511 nread = read_file(fsp,data,startpos,numtoread);
3513 if (nread < 0) {
3514 reply_nterror(req, map_nt_error_from_unix(errno));
3515 END_PROFILE(SMBlockread);
3516 return;
3519 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3521 SSVAL(req->outbuf,smb_vwv0,nread);
3522 SSVAL(req->outbuf,smb_vwv5,nread+3);
3523 p = smb_buf(req->outbuf);
3524 SCVAL(p,0,0); /* pad byte. */
3525 SSVAL(p,1,nread);
3527 DEBUG(3,("lockread %s num=%d nread=%d\n",
3528 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3530 END_PROFILE(SMBlockread);
3531 return;
3534 #undef DBGC_CLASS
3535 #define DBGC_CLASS DBGC_ALL
3537 /****************************************************************************
3538 Reply to a read.
3539 ****************************************************************************/
3541 void reply_read(struct smb_request *req)
3543 connection_struct *conn = req->conn;
3544 size_t numtoread;
3545 ssize_t nread = 0;
3546 char *data;
3547 off_t startpos;
3548 int outsize = 0;
3549 files_struct *fsp;
3550 struct lock_struct lock;
3551 struct smbd_server_connection *sconn = req->sconn;
3553 START_PROFILE(SMBread);
3555 if (req->wct < 3) {
3556 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3557 END_PROFILE(SMBread);
3558 return;
3561 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3563 if (!check_fsp(conn, req, fsp)) {
3564 END_PROFILE(SMBread);
3565 return;
3568 if (!CHECK_READ(fsp,req)) {
3569 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3570 END_PROFILE(SMBread);
3571 return;
3574 numtoread = SVAL(req->vwv+1, 0);
3575 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3577 numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
3580 * The requested read size cannot be greater than max_recv. JRA.
3582 if (numtoread > sconn->smb1.negprot.max_recv) {
3583 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \
3584 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3585 (unsigned int)numtoread,
3586 (unsigned int)sconn->smb1.negprot.max_recv));
3587 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3590 reply_outbuf(req, 5, numtoread+3);
3592 data = smb_buf(req->outbuf) + 3;
3594 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3595 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3596 &lock);
3598 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3599 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3600 END_PROFILE(SMBread);
3601 return;
3604 if (numtoread > 0)
3605 nread = read_file(fsp,data,startpos,numtoread);
3607 if (nread < 0) {
3608 reply_nterror(req, map_nt_error_from_unix(errno));
3609 goto strict_unlock;
3612 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3614 SSVAL(req->outbuf,smb_vwv0,nread);
3615 SSVAL(req->outbuf,smb_vwv5,nread+3);
3616 SCVAL(smb_buf(req->outbuf),0,1);
3617 SSVAL(smb_buf(req->outbuf),1,nread);
3619 DEBUG(3, ("read %s num=%d nread=%d\n",
3620 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3622 strict_unlock:
3623 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3625 END_PROFILE(SMBread);
3626 return;
3629 /****************************************************************************
3630 Setup readX header.
3631 ****************************************************************************/
3633 static int setup_readX_header(struct smb_request *req, char *outbuf,
3634 size_t smb_maxcnt)
3636 int outsize;
3638 outsize = srv_set_message(outbuf,12,smb_maxcnt,False);
3640 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3642 SCVAL(outbuf,smb_vwv0,0xFF);
3643 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3644 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3645 SSVAL(outbuf,smb_vwv6,
3646 (smb_wct - 4) /* offset from smb header to wct */
3647 + 1 /* the wct field */
3648 + 12 * sizeof(uint16_t) /* vwv */
3649 + 2); /* the buflen field */
3650 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3651 SSVAL(outbuf,smb_vwv11,smb_maxcnt);
3652 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3653 _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
3654 return outsize;
3657 /****************************************************************************
3658 Reply to a read and X - possibly using sendfile.
3659 ****************************************************************************/
3661 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3662 files_struct *fsp, off_t startpos,
3663 size_t smb_maxcnt)
3665 ssize_t nread = -1;
3666 struct lock_struct lock;
3667 int saved_errno = 0;
3669 if(fsp_stat(fsp) == -1) {
3670 reply_nterror(req, map_nt_error_from_unix(errno));
3671 return;
3674 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3675 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3676 &lock);
3678 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3679 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3680 return;
3683 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3684 (startpos > fsp->fsp_name->st.st_ex_size)
3685 || (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3687 * We already know that we would do a short read, so don't
3688 * try the sendfile() path.
3690 goto nosendfile_read;
3694 * We can only use sendfile on a non-chained packet
3695 * but we can use on a non-oplocked file. tridge proved this
3696 * on a train in Germany :-). JRA.
3699 if (!req_is_in_chain(req) &&
3700 !req->encrypted &&
3701 (fsp->base_fsp == NULL) &&
3702 (fsp->wcp == NULL) &&
3703 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3704 uint8 headerbuf[smb_size + 12 * 2];
3705 DATA_BLOB header;
3708 * Set up the packet header before send. We
3709 * assume here the sendfile will work (get the
3710 * correct amount of data).
3713 header = data_blob_const(headerbuf, sizeof(headerbuf));
3715 construct_reply_common_req(req, (char *)headerbuf);
3716 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3718 nread = SMB_VFS_SENDFILE(req->sconn->sock, fsp, &header,
3719 startpos, smb_maxcnt);
3720 if (nread == -1) {
3721 /* Returning ENOSYS means no data at all was sent.
3722 Do this as a normal read. */
3723 if (errno == ENOSYS) {
3724 goto normal_read;
3728 * Special hack for broken Linux with no working sendfile. If we
3729 * return EINTR we sent the header but not the rest of the data.
3730 * Fake this up by doing read/write calls.
3733 if (errno == EINTR) {
3734 /* Ensure we don't do this again. */
3735 set_use_sendfile(SNUM(conn), False);
3736 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3737 nread = fake_sendfile(fsp, startpos,
3738 smb_maxcnt);
3739 if (nread == -1) {
3740 DEBUG(0,("send_file_readX: "
3741 "fake_sendfile failed for "
3742 "file %s (%s).\n",
3743 fsp_str_dbg(fsp),
3744 strerror(errno)));
3745 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3747 DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
3748 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3749 /* No outbuf here means successful sendfile. */
3750 goto strict_unlock;
3753 DEBUG(0,("send_file_readX: sendfile failed for file "
3754 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3755 strerror(errno)));
3756 exit_server_cleanly("send_file_readX sendfile failed");
3757 } else if (nread == 0) {
3759 * Some sendfile implementations return 0 to indicate
3760 * that there was a short read, but nothing was
3761 * actually written to the socket. In this case,
3762 * fallback to the normal read path so the header gets
3763 * the correct byte count.
3765 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
3766 "falling back to the normal read: %s\n",
3767 fsp_str_dbg(fsp)));
3768 goto normal_read;
3771 DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n",
3772 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3774 /* Deal with possible short send. */
3775 if (nread != smb_maxcnt + sizeof(headerbuf)) {
3776 sendfile_short_send(fsp, nread, sizeof(headerbuf), smb_maxcnt);
3778 /* No outbuf here means successful sendfile. */
3779 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
3780 SMB_PERFCOUNT_END(&req->pcd);
3781 goto strict_unlock;
3784 normal_read:
3786 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3787 uint8 headerbuf[smb_size + 2*12];
3789 construct_reply_common_req(req, (char *)headerbuf);
3790 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3792 /* Send out the header. */
3793 if (write_data(req->sconn->sock, (char *)headerbuf,
3794 sizeof(headerbuf)) != sizeof(headerbuf)) {
3796 char addr[INET6_ADDRSTRLEN];
3798 * Try and give an error message saying what
3799 * client failed.
3801 DEBUG(0, ("write_data failed for client %s. "
3802 "Error %s\n",
3803 get_peer_addr(req->sconn->sock, addr,
3804 sizeof(addr)),
3805 strerror(errno)));
3807 DEBUG(0,("send_file_readX: write_data failed for file "
3808 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3809 strerror(errno)));
3810 exit_server_cleanly("send_file_readX sendfile failed");
3812 nread = fake_sendfile(fsp, startpos, smb_maxcnt);
3813 if (nread == -1) {
3814 DEBUG(0,("send_file_readX: fake_sendfile failed for "
3815 "file %s (%s).\n", fsp_str_dbg(fsp),
3816 strerror(errno)));
3817 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3819 goto strict_unlock;
3822 nosendfile_read:
3824 reply_outbuf(req, 12, smb_maxcnt);
3825 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
3826 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
3828 nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt);
3829 saved_errno = errno;
3831 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3833 if (nread < 0) {
3834 reply_nterror(req, map_nt_error_from_unix(saved_errno));
3835 return;
3838 setup_readX_header(req, (char *)req->outbuf, nread);
3840 DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
3841 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3842 return;
3844 strict_unlock:
3845 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3846 TALLOC_FREE(req->outbuf);
3847 return;
3850 /****************************************************************************
3851 MacOSX clients send large reads without telling us they are going to do that.
3852 Bug #9572 - File corruption during SMB1 read by Mac OSX 10.8.2 clients
3853 Allow this if we are talking to a Samba client, or if we told the client
3854 we supported this.
3855 ****************************************************************************/
3857 static bool server_will_accept_large_read(void)
3859 /* Samba client ? No problem. */
3860 if (get_remote_arch() == RA_SAMBA) {
3861 return true;
3863 /* Need UNIX extensions. */
3864 if (!lp_unix_extensions()) {
3865 return false;
3867 return true;
3870 /****************************************************************************
3871 Reply to a read and X.
3872 ****************************************************************************/
3874 void reply_read_and_X(struct smb_request *req)
3876 connection_struct *conn = req->conn;
3877 files_struct *fsp;
3878 off_t startpos;
3879 size_t smb_maxcnt;
3880 size_t upper_size;
3881 bool big_readX = False;
3882 #if 0
3883 size_t smb_mincnt = SVAL(req->vwv+6, 0);
3884 #endif
3886 START_PROFILE(SMBreadX);
3888 if ((req->wct != 10) && (req->wct != 12)) {
3889 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3890 return;
3893 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
3894 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3895 smb_maxcnt = SVAL(req->vwv+5, 0);
3897 /* If it's an IPC, pass off the pipe handler. */
3898 if (IS_IPC(conn)) {
3899 reply_pipe_read_and_X(req);
3900 END_PROFILE(SMBreadX);
3901 return;
3904 if (!check_fsp(conn, req, fsp)) {
3905 END_PROFILE(SMBreadX);
3906 return;
3909 if (!CHECK_READ(fsp,req)) {
3910 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3911 END_PROFILE(SMBreadX);
3912 return;
3915 upper_size = SVAL(req->vwv+7, 0);
3916 if ((upper_size != 0) && server_will_accept_large_read()) {
3918 * This is Samba only behavior (up to Samba 3.6)!
3920 * Windows 2008 R2 ignores the upper_size,
3921 * so we do unless unix extentions are active
3922 * or "smbclient" is talking to us.
3924 smb_maxcnt |= (upper_size<<16);
3925 if (upper_size > 1) {
3926 /* Can't do this on a chained packet. */
3927 if ((CVAL(req->vwv+0, 0) != 0xFF)) {
3928 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3929 END_PROFILE(SMBreadX);
3930 return;
3932 /* We currently don't do this on signed or sealed data. */
3933 if (srv_is_signing_active(req->sconn) ||
3934 is_encrypted_packet(req->sconn, req->inbuf)) {
3935 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3936 END_PROFILE(SMBreadX);
3937 return;
3939 /* Is there room in the reply for this data ? */
3940 if (smb_maxcnt > (0xFFFFFF - (smb_size -4 + 12*2))) {
3941 reply_nterror(req,
3942 NT_STATUS_INVALID_PARAMETER);
3943 END_PROFILE(SMBreadX);
3944 return;
3946 big_readX = True;
3950 if (req->wct == 12) {
3952 * This is a large offset (64 bit) read.
3954 startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
3958 if (!big_readX) {
3959 NTSTATUS status = schedule_aio_read_and_X(conn,
3960 req,
3961 fsp,
3962 startpos,
3963 smb_maxcnt);
3964 if (NT_STATUS_IS_OK(status)) {
3965 /* Read scheduled - we're done. */
3966 goto out;
3968 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
3969 /* Real error - report to client. */
3970 END_PROFILE(SMBreadX);
3971 reply_nterror(req, status);
3972 return;
3974 /* NT_STATUS_RETRY - fall back to sync read. */
3977 smbd_lock_socket(req->sconn);
3978 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
3979 smbd_unlock_socket(req->sconn);
3981 out:
3982 END_PROFILE(SMBreadX);
3983 return;
3986 /****************************************************************************
3987 Error replies to writebraw must have smb_wct == 1. Fix this up.
3988 ****************************************************************************/
3990 void error_to_writebrawerr(struct smb_request *req)
3992 uint8 *old_outbuf = req->outbuf;
3994 reply_outbuf(req, 1, 0);
3996 memcpy(req->outbuf, old_outbuf, smb_size);
3997 TALLOC_FREE(old_outbuf);
4000 /****************************************************************************
4001 Read 4 bytes of a smb packet and return the smb length of the packet.
4002 Store the result in the buffer. This version of the function will
4003 never return a session keepalive (length of zero).
4004 Timeout is in milliseconds.
4005 ****************************************************************************/
4007 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
4008 size_t *len)
4010 uint8_t msgtype = NBSSkeepalive;
4012 while (msgtype == NBSSkeepalive) {
4013 NTSTATUS status;
4015 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
4016 len);
4017 if (!NT_STATUS_IS_OK(status)) {
4018 char addr[INET6_ADDRSTRLEN];
4019 /* Try and give an error message
4020 * saying what client failed. */
4021 DEBUG(0, ("read_fd_with_timeout failed for "
4022 "client %s read error = %s.\n",
4023 get_peer_addr(fd,addr,sizeof(addr)),
4024 nt_errstr(status)));
4025 return status;
4028 msgtype = CVAL(inbuf, 0);
4031 DEBUG(10,("read_smb_length: got smb length of %lu\n",
4032 (unsigned long)len));
4034 return NT_STATUS_OK;
4037 /****************************************************************************
4038 Reply to a writebraw (core+ or LANMAN1.0 protocol).
4039 ****************************************************************************/
4041 void reply_writebraw(struct smb_request *req)
4043 connection_struct *conn = req->conn;
4044 char *buf = NULL;
4045 ssize_t nwritten=0;
4046 ssize_t total_written=0;
4047 size_t numtowrite=0;
4048 size_t tcount;
4049 off_t startpos;
4050 const char *data=NULL;
4051 bool write_through;
4052 files_struct *fsp;
4053 struct lock_struct lock;
4054 NTSTATUS status;
4056 START_PROFILE(SMBwritebraw);
4059 * If we ever reply with an error, it must have the SMB command
4060 * type of SMBwritec, not SMBwriteBraw, as this tells the client
4061 * we're finished.
4063 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
4065 if (srv_is_signing_active(req->sconn)) {
4066 END_PROFILE(SMBwritebraw);
4067 exit_server_cleanly("reply_writebraw: SMB signing is active - "
4068 "raw reads/writes are disallowed.");
4071 if (req->wct < 12) {
4072 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4073 error_to_writebrawerr(req);
4074 END_PROFILE(SMBwritebraw);
4075 return;
4078 if (req->sconn->smb1.echo_handler.trusted_fde) {
4079 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
4080 "'async smb echo handler = yes'\n"));
4081 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
4082 error_to_writebrawerr(req);
4083 END_PROFILE(SMBwritebraw);
4084 return;
4087 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4088 if (!check_fsp(conn, req, fsp)) {
4089 error_to_writebrawerr(req);
4090 END_PROFILE(SMBwritebraw);
4091 return;
4094 if (!CHECK_WRITE(fsp)) {
4095 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4096 error_to_writebrawerr(req);
4097 END_PROFILE(SMBwritebraw);
4098 return;
4101 tcount = IVAL(req->vwv+1, 0);
4102 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4103 write_through = BITSETW(req->vwv+7,0);
4105 /* We have to deal with slightly different formats depending
4106 on whether we are using the core+ or lanman1.0 protocol */
4108 if(get_Protocol() <= PROTOCOL_COREPLUS) {
4109 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
4110 data = smb_buf_const(req->inbuf);
4111 } else {
4112 numtowrite = SVAL(req->vwv+10, 0);
4113 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
4116 /* Ensure we don't write bytes past the end of this packet. */
4117 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
4118 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4119 error_to_writebrawerr(req);
4120 END_PROFILE(SMBwritebraw);
4121 return;
4124 if (!fsp->print_file) {
4125 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4126 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4127 &lock);
4129 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4130 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4131 error_to_writebrawerr(req);
4132 END_PROFILE(SMBwritebraw);
4133 return;
4137 if (numtowrite>0) {
4138 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4141 DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d "
4142 "wrote=%d sync=%d\n",
4143 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4144 (int)nwritten, (int)write_through));
4146 if (nwritten < (ssize_t)numtowrite) {
4147 reply_nterror(req, NT_STATUS_DISK_FULL);
4148 error_to_writebrawerr(req);
4149 goto strict_unlock;
4152 total_written = nwritten;
4154 /* Allocate a buffer of 64k + length. */
4155 buf = talloc_array(NULL, char, 65540);
4156 if (!buf) {
4157 reply_nterror(req, NT_STATUS_NO_MEMORY);
4158 error_to_writebrawerr(req);
4159 goto strict_unlock;
4162 /* Return a SMBwritebraw message to the redirector to tell
4163 * it to send more bytes */
4165 memcpy(buf, req->inbuf, smb_size);
4166 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4167 SCVAL(buf,smb_com,SMBwritebraw);
4168 SSVALS(buf,smb_vwv0,0xFFFF);
4169 show_msg(buf);
4170 if (!srv_send_smb(req->sconn,
4171 buf,
4172 false, 0, /* no signing */
4173 IS_CONN_ENCRYPTED(conn),
4174 &req->pcd)) {
4175 exit_server_cleanly("reply_writebraw: srv_send_smb "
4176 "failed.");
4179 /* Now read the raw data into the buffer and write it */
4180 status = read_smb_length(req->sconn->sock, buf, SMB_SECONDARY_WAIT,
4181 &numtowrite);
4182 if (!NT_STATUS_IS_OK(status)) {
4183 exit_server_cleanly("secondary writebraw failed");
4186 /* Set up outbuf to return the correct size */
4187 reply_outbuf(req, 1, 0);
4189 if (numtowrite != 0) {
4191 if (numtowrite > 0xFFFF) {
4192 DEBUG(0,("reply_writebraw: Oversize secondary write "
4193 "raw requested (%u). Terminating\n",
4194 (unsigned int)numtowrite ));
4195 exit_server_cleanly("secondary writebraw failed");
4198 if (tcount > nwritten+numtowrite) {
4199 DEBUG(3,("reply_writebraw: Client overestimated the "
4200 "write %d %d %d\n",
4201 (int)tcount,(int)nwritten,(int)numtowrite));
4204 status = read_data(req->sconn->sock, buf+4, numtowrite);
4206 if (!NT_STATUS_IS_OK(status)) {
4207 char addr[INET6_ADDRSTRLEN];
4208 /* Try and give an error message
4209 * saying what client failed. */
4210 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4211 "raw read failed (%s) for client %s. "
4212 "Terminating\n", nt_errstr(status),
4213 get_peer_addr(req->sconn->sock, addr,
4214 sizeof(addr))));
4215 exit_server_cleanly("secondary writebraw failed");
4218 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4219 if (nwritten == -1) {
4220 TALLOC_FREE(buf);
4221 reply_nterror(req, map_nt_error_from_unix(errno));
4222 error_to_writebrawerr(req);
4223 goto strict_unlock;
4226 if (nwritten < (ssize_t)numtowrite) {
4227 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4228 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4231 if (nwritten > 0) {
4232 total_written += nwritten;
4236 TALLOC_FREE(buf);
4237 SSVAL(req->outbuf,smb_vwv0,total_written);
4239 status = sync_file(conn, fsp, write_through);
4240 if (!NT_STATUS_IS_OK(status)) {
4241 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4242 fsp_str_dbg(fsp), nt_errstr(status)));
4243 reply_nterror(req, status);
4244 error_to_writebrawerr(req);
4245 goto strict_unlock;
4248 DEBUG(3,("reply_writebraw: secondart write %s start=%.0f num=%d "
4249 "wrote=%d\n",
4250 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4251 (int)total_written));
4253 if (!fsp->print_file) {
4254 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4257 /* We won't return a status if write through is not selected - this
4258 * follows what WfWg does */
4259 END_PROFILE(SMBwritebraw);
4261 if (!write_through && total_written==tcount) {
4263 #if RABBIT_PELLET_FIX
4265 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4266 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4267 * JRA.
4269 if (!send_keepalive(req->sconn->sock)) {
4270 exit_server_cleanly("reply_writebraw: send of "
4271 "keepalive failed");
4273 #endif
4274 TALLOC_FREE(req->outbuf);
4276 return;
4278 strict_unlock:
4279 if (!fsp->print_file) {
4280 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4283 END_PROFILE(SMBwritebraw);
4284 return;
4287 #undef DBGC_CLASS
4288 #define DBGC_CLASS DBGC_LOCKING
4290 /****************************************************************************
4291 Reply to a writeunlock (core+).
4292 ****************************************************************************/
4294 void reply_writeunlock(struct smb_request *req)
4296 connection_struct *conn = req->conn;
4297 ssize_t nwritten = -1;
4298 size_t numtowrite;
4299 off_t startpos;
4300 const char *data;
4301 NTSTATUS status = NT_STATUS_OK;
4302 files_struct *fsp;
4303 struct lock_struct lock;
4304 int saved_errno = 0;
4306 START_PROFILE(SMBwriteunlock);
4308 if (req->wct < 5) {
4309 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4310 END_PROFILE(SMBwriteunlock);
4311 return;
4314 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4316 if (!check_fsp(conn, req, fsp)) {
4317 END_PROFILE(SMBwriteunlock);
4318 return;
4321 if (!CHECK_WRITE(fsp)) {
4322 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4323 END_PROFILE(SMBwriteunlock);
4324 return;
4327 numtowrite = SVAL(req->vwv+1, 0);
4328 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4329 data = (const char *)req->buf + 3;
4331 if (!fsp->print_file && numtowrite > 0) {
4332 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4333 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4334 &lock);
4336 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4337 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4338 END_PROFILE(SMBwriteunlock);
4339 return;
4343 /* The special X/Open SMB protocol handling of
4344 zero length writes is *NOT* done for
4345 this call */
4346 if(numtowrite == 0) {
4347 nwritten = 0;
4348 } else {
4349 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4350 saved_errno = errno;
4353 status = sync_file(conn, fsp, False /* write through */);
4354 if (!NT_STATUS_IS_OK(status)) {
4355 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4356 fsp_str_dbg(fsp), nt_errstr(status)));
4357 reply_nterror(req, status);
4358 goto strict_unlock;
4361 if(nwritten < 0) {
4362 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4363 goto strict_unlock;
4366 if((nwritten < numtowrite) && (numtowrite != 0)) {
4367 reply_nterror(req, NT_STATUS_DISK_FULL);
4368 goto strict_unlock;
4371 if (numtowrite && !fsp->print_file) {
4372 status = do_unlock(req->sconn->msg_ctx,
4373 fsp,
4374 (uint64_t)req->smbpid,
4375 (uint64_t)numtowrite,
4376 (uint64_t)startpos,
4377 WINDOWS_LOCK);
4379 if (NT_STATUS_V(status)) {
4380 reply_nterror(req, status);
4381 goto strict_unlock;
4385 reply_outbuf(req, 1, 0);
4387 SSVAL(req->outbuf,smb_vwv0,nwritten);
4389 DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
4390 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4392 strict_unlock:
4393 if (numtowrite && !fsp->print_file) {
4394 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4397 END_PROFILE(SMBwriteunlock);
4398 return;
4401 #undef DBGC_CLASS
4402 #define DBGC_CLASS DBGC_ALL
4404 /****************************************************************************
4405 Reply to a write.
4406 ****************************************************************************/
4408 void reply_write(struct smb_request *req)
4410 connection_struct *conn = req->conn;
4411 size_t numtowrite;
4412 ssize_t nwritten = -1;
4413 off_t startpos;
4414 const char *data;
4415 files_struct *fsp;
4416 struct lock_struct lock;
4417 NTSTATUS status;
4418 int saved_errno = 0;
4420 START_PROFILE(SMBwrite);
4422 if (req->wct < 5) {
4423 END_PROFILE(SMBwrite);
4424 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4425 return;
4428 /* If it's an IPC, pass off the pipe handler. */
4429 if (IS_IPC(conn)) {
4430 reply_pipe_write(req);
4431 END_PROFILE(SMBwrite);
4432 return;
4435 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4437 if (!check_fsp(conn, req, fsp)) {
4438 END_PROFILE(SMBwrite);
4439 return;
4442 if (!CHECK_WRITE(fsp)) {
4443 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4444 END_PROFILE(SMBwrite);
4445 return;
4448 numtowrite = SVAL(req->vwv+1, 0);
4449 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4450 data = (const char *)req->buf + 3;
4452 if (!fsp->print_file) {
4453 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4454 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4455 &lock);
4457 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4458 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4459 END_PROFILE(SMBwrite);
4460 return;
4465 * X/Open SMB protocol says that if smb_vwv1 is
4466 * zero then the file size should be extended or
4467 * truncated to the size given in smb_vwv[2-3].
4470 if(numtowrite == 0) {
4472 * This is actually an allocate call, and set EOF. JRA.
4474 nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
4475 if (nwritten < 0) {
4476 reply_nterror(req, NT_STATUS_DISK_FULL);
4477 goto strict_unlock;
4479 nwritten = vfs_set_filelen(fsp, (off_t)startpos);
4480 if (nwritten < 0) {
4481 reply_nterror(req, NT_STATUS_DISK_FULL);
4482 goto strict_unlock;
4484 trigger_write_time_update_immediate(fsp);
4485 } else {
4486 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4489 status = sync_file(conn, fsp, False);
4490 if (!NT_STATUS_IS_OK(status)) {
4491 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4492 fsp_str_dbg(fsp), nt_errstr(status)));
4493 reply_nterror(req, status);
4494 goto strict_unlock;
4497 if(nwritten < 0) {
4498 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4499 goto strict_unlock;
4502 if((nwritten == 0) && (numtowrite != 0)) {
4503 reply_nterror(req, NT_STATUS_DISK_FULL);
4504 goto strict_unlock;
4507 reply_outbuf(req, 1, 0);
4509 SSVAL(req->outbuf,smb_vwv0,nwritten);
4511 if (nwritten < (ssize_t)numtowrite) {
4512 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4513 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4516 DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4518 strict_unlock:
4519 if (!fsp->print_file) {
4520 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4523 END_PROFILE(SMBwrite);
4524 return;
4527 /****************************************************************************
4528 Ensure a buffer is a valid writeX for recvfile purposes.
4529 ****************************************************************************/
4531 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4532 (2*14) + /* word count (including bcc) */ \
4533 1 /* pad byte */)
4535 bool is_valid_writeX_buffer(struct smbd_server_connection *sconn,
4536 const uint8_t *inbuf)
4538 size_t numtowrite;
4539 connection_struct *conn = NULL;
4540 unsigned int doff = 0;
4541 size_t len = smb_len_large(inbuf);
4542 struct smbXsrv_tcon *tcon;
4543 NTSTATUS status;
4544 NTTIME now = 0;
4546 if (is_encrypted_packet(sconn, inbuf)) {
4547 /* Can't do this on encrypted
4548 * connections. */
4549 return false;
4552 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4553 return false;
4556 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4557 CVAL(inbuf,smb_wct) != 14) {
4558 DEBUG(10,("is_valid_writeX_buffer: chained or "
4559 "invalid word length.\n"));
4560 return false;
4563 status = smb1srv_tcon_lookup(sconn->conn, SVAL(inbuf, smb_tid),
4564 now, &tcon);
4565 if (!NT_STATUS_IS_OK(status)) {
4566 DEBUG(10,("is_valid_writeX_buffer: bad tid\n"));
4567 return false;
4569 conn = tcon->compat;
4571 if (IS_IPC(conn)) {
4572 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4573 return false;
4575 if (IS_PRINT(conn)) {
4576 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4577 return false;
4579 doff = SVAL(inbuf,smb_vwv11);
4581 numtowrite = SVAL(inbuf,smb_vwv10);
4583 if (len > doff && len - doff > 0xFFFF) {
4584 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4587 if (numtowrite == 0) {
4588 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4589 return false;
4592 /* Ensure the sizes match up. */
4593 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4594 /* no pad byte...old smbclient :-( */
4595 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4596 (unsigned int)doff,
4597 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4598 return false;
4601 if (len - doff != numtowrite) {
4602 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4603 "len = %u, doff = %u, numtowrite = %u\n",
4604 (unsigned int)len,
4605 (unsigned int)doff,
4606 (unsigned int)numtowrite ));
4607 return false;
4610 DEBUG(10,("is_valid_writeX_buffer: true "
4611 "len = %u, doff = %u, numtowrite = %u\n",
4612 (unsigned int)len,
4613 (unsigned int)doff,
4614 (unsigned int)numtowrite ));
4616 return true;
4619 /****************************************************************************
4620 Reply to a write and X.
4621 ****************************************************************************/
4623 void reply_write_and_X(struct smb_request *req)
4625 connection_struct *conn = req->conn;
4626 files_struct *fsp;
4627 struct lock_struct lock;
4628 off_t startpos;
4629 size_t numtowrite;
4630 bool write_through;
4631 ssize_t nwritten;
4632 unsigned int smb_doff;
4633 unsigned int smblen;
4634 const char *data;
4635 NTSTATUS status;
4636 int saved_errno = 0;
4638 START_PROFILE(SMBwriteX);
4640 if ((req->wct != 12) && (req->wct != 14)) {
4641 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4642 goto out;
4645 numtowrite = SVAL(req->vwv+10, 0);
4646 smb_doff = SVAL(req->vwv+11, 0);
4647 smblen = smb_len(req->inbuf);
4649 if (req->unread_bytes > 0xFFFF ||
4650 (smblen > smb_doff &&
4651 smblen - smb_doff > 0xFFFF)) {
4652 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
4655 if (req->unread_bytes) {
4656 /* Can't do a recvfile write on IPC$ */
4657 if (IS_IPC(conn)) {
4658 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4659 goto out;
4661 if (numtowrite != req->unread_bytes) {
4662 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4663 goto out;
4665 } else {
4666 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4667 smb_doff + numtowrite > smblen) {
4668 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4669 goto out;
4673 /* If it's an IPC, pass off the pipe handler. */
4674 if (IS_IPC(conn)) {
4675 if (req->unread_bytes) {
4676 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4677 goto out;
4679 reply_pipe_write_and_X(req);
4680 goto out;
4683 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4684 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4685 write_through = BITSETW(req->vwv+7,0);
4687 if (!check_fsp(conn, req, fsp)) {
4688 goto out;
4691 if (!CHECK_WRITE(fsp)) {
4692 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4693 goto out;
4696 data = smb_base(req->inbuf) + smb_doff;
4698 if(req->wct == 14) {
4700 * This is a large offset (64 bit) write.
4702 startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
4706 /* X/Open SMB protocol says that, unlike SMBwrite
4707 if the length is zero then NO truncation is
4708 done, just a write of zero. To truncate a file,
4709 use SMBwrite. */
4711 if(numtowrite == 0) {
4712 nwritten = 0;
4713 } else {
4714 if (req->unread_bytes == 0) {
4715 status = schedule_aio_write_and_X(conn,
4716 req,
4717 fsp,
4718 data,
4719 startpos,
4720 numtowrite);
4722 if (NT_STATUS_IS_OK(status)) {
4723 /* write scheduled - we're done. */
4724 goto out;
4726 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4727 /* Real error - report to client. */
4728 reply_nterror(req, status);
4729 goto out;
4731 /* NT_STATUS_RETRY - fall through to sync write. */
4734 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4735 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4736 &lock);
4738 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4739 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4740 goto out;
4743 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4744 saved_errno = errno;
4746 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4749 if(nwritten < 0) {
4750 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4751 goto out;
4754 if((nwritten == 0) && (numtowrite != 0)) {
4755 reply_nterror(req, NT_STATUS_DISK_FULL);
4756 goto out;
4759 reply_outbuf(req, 6, 0);
4760 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
4761 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
4762 SSVAL(req->outbuf,smb_vwv2,nwritten);
4763 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4765 DEBUG(3,("writeX %s num=%d wrote=%d\n",
4766 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4768 status = sync_file(conn, fsp, write_through);
4769 if (!NT_STATUS_IS_OK(status)) {
4770 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4771 fsp_str_dbg(fsp), nt_errstr(status)));
4772 reply_nterror(req, status);
4773 goto out;
4776 END_PROFILE(SMBwriteX);
4777 return;
4779 out:
4780 if (req->unread_bytes) {
4781 /* writeX failed. drain socket. */
4782 if (drain_socket(req->sconn->sock, req->unread_bytes) !=
4783 req->unread_bytes) {
4784 smb_panic("failed to drain pending bytes");
4786 req->unread_bytes = 0;
4789 END_PROFILE(SMBwriteX);
4790 return;
4793 /****************************************************************************
4794 Reply to a lseek.
4795 ****************************************************************************/
4797 void reply_lseek(struct smb_request *req)
4799 connection_struct *conn = req->conn;
4800 off_t startpos;
4801 off_t res= -1;
4802 int mode,umode;
4803 files_struct *fsp;
4805 START_PROFILE(SMBlseek);
4807 if (req->wct < 4) {
4808 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4809 END_PROFILE(SMBlseek);
4810 return;
4813 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4815 if (!check_fsp(conn, req, fsp)) {
4816 return;
4819 flush_write_cache(fsp, SEEK_FLUSH);
4821 mode = SVAL(req->vwv+1, 0) & 3;
4822 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4823 startpos = (off_t)IVALS(req->vwv+2, 0);
4825 switch (mode) {
4826 case 0:
4827 umode = SEEK_SET;
4828 res = startpos;
4829 break;
4830 case 1:
4831 umode = SEEK_CUR;
4832 res = fsp->fh->pos + startpos;
4833 break;
4834 case 2:
4835 umode = SEEK_END;
4836 break;
4837 default:
4838 umode = SEEK_SET;
4839 res = startpos;
4840 break;
4843 if (umode == SEEK_END) {
4844 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
4845 if(errno == EINVAL) {
4846 off_t current_pos = startpos;
4848 if(fsp_stat(fsp) == -1) {
4849 reply_nterror(req,
4850 map_nt_error_from_unix(errno));
4851 END_PROFILE(SMBlseek);
4852 return;
4855 current_pos += fsp->fsp_name->st.st_ex_size;
4856 if(current_pos < 0)
4857 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
4861 if(res == -1) {
4862 reply_nterror(req, map_nt_error_from_unix(errno));
4863 END_PROFILE(SMBlseek);
4864 return;
4868 fsp->fh->pos = res;
4870 reply_outbuf(req, 2, 0);
4871 SIVAL(req->outbuf,smb_vwv0,res);
4873 DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n",
4874 fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode));
4876 END_PROFILE(SMBlseek);
4877 return;
4880 /****************************************************************************
4881 Reply to a flush.
4882 ****************************************************************************/
4884 void reply_flush(struct smb_request *req)
4886 connection_struct *conn = req->conn;
4887 uint16 fnum;
4888 files_struct *fsp;
4890 START_PROFILE(SMBflush);
4892 if (req->wct < 1) {
4893 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4894 return;
4897 fnum = SVAL(req->vwv+0, 0);
4898 fsp = file_fsp(req, fnum);
4900 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
4901 return;
4904 if (!fsp) {
4905 file_sync_all(conn);
4906 } else {
4907 NTSTATUS status = sync_file(conn, fsp, True);
4908 if (!NT_STATUS_IS_OK(status)) {
4909 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
4910 fsp_str_dbg(fsp), nt_errstr(status)));
4911 reply_nterror(req, status);
4912 END_PROFILE(SMBflush);
4913 return;
4917 reply_outbuf(req, 0, 0);
4919 DEBUG(3,("flush\n"));
4920 END_PROFILE(SMBflush);
4921 return;
4924 /****************************************************************************
4925 Reply to a exit.
4926 conn POINTER CAN BE NULL HERE !
4927 ****************************************************************************/
4929 void reply_exit(struct smb_request *req)
4931 START_PROFILE(SMBexit);
4933 file_close_pid(req->sconn, req->smbpid, req->vuid);
4935 reply_outbuf(req, 0, 0);
4937 DEBUG(3,("exit\n"));
4939 END_PROFILE(SMBexit);
4940 return;
4943 struct reply_close_state {
4944 files_struct *fsp;
4945 struct smb_request *smbreq;
4948 static void do_smb1_close(struct tevent_req *req);
4950 void reply_close(struct smb_request *req)
4952 connection_struct *conn = req->conn;
4953 NTSTATUS status = NT_STATUS_OK;
4954 files_struct *fsp = NULL;
4955 START_PROFILE(SMBclose);
4957 if (req->wct < 3) {
4958 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4959 END_PROFILE(SMBclose);
4960 return;
4963 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4966 * We can only use check_fsp if we know it's not a directory.
4969 if (!check_fsp_open(conn, req, fsp)) {
4970 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
4971 END_PROFILE(SMBclose);
4972 return;
4975 DEBUG(3, ("Close %s fd=%d %s (numopen=%d)\n",
4976 fsp->is_directory ? "directory" : "file",
4977 fsp->fh->fd, fsp_fnum_dbg(fsp),
4978 conn->num_files_open));
4980 if (!fsp->is_directory) {
4981 time_t t;
4984 * Take care of any time sent in the close.
4987 t = srv_make_unix_date3(req->vwv+1);
4988 set_close_write_time(fsp, convert_time_t_to_timespec(t));
4991 if (fsp->num_aio_requests != 0) {
4993 struct reply_close_state *state;
4995 DEBUG(10, ("closing with aio %u requests pending\n",
4996 fsp->num_aio_requests));
4999 * We depend on the aio_extra destructor to take care of this
5000 * close request once fsp->num_aio_request drops to 0.
5003 fsp->deferred_close = tevent_wait_send(
5004 fsp, fsp->conn->sconn->ev_ctx);
5005 if (fsp->deferred_close == NULL) {
5006 status = NT_STATUS_NO_MEMORY;
5007 goto done;
5010 state = talloc(fsp, struct reply_close_state);
5011 if (state == NULL) {
5012 TALLOC_FREE(fsp->deferred_close);
5013 status = NT_STATUS_NO_MEMORY;
5014 goto done;
5016 state->fsp = fsp;
5017 state->smbreq = talloc_move(fsp, &req);
5018 tevent_req_set_callback(fsp->deferred_close, do_smb1_close,
5019 state);
5020 END_PROFILE(SMBclose);
5021 return;
5025 * close_file() returns the unix errno if an error was detected on
5026 * close - normally this is due to a disk full error. If not then it
5027 * was probably an I/O error.
5030 status = close_file(req, fsp, NORMAL_CLOSE);
5031 done:
5032 if (!NT_STATUS_IS_OK(status)) {
5033 reply_nterror(req, status);
5034 END_PROFILE(SMBclose);
5035 return;
5038 reply_outbuf(req, 0, 0);
5039 END_PROFILE(SMBclose);
5040 return;
5043 static void do_smb1_close(struct tevent_req *req)
5045 struct reply_close_state *state = tevent_req_callback_data(
5046 req, struct reply_close_state);
5047 struct smb_request *smbreq;
5048 NTSTATUS status;
5049 int ret;
5051 ret = tevent_wait_recv(req);
5052 TALLOC_FREE(req);
5053 if (ret != 0) {
5054 DEBUG(10, ("tevent_wait_recv returned %s\n",
5055 strerror(ret)));
5057 * Continue anyway, this should never happen
5062 * fsp->smb2_close_request right now is a talloc grandchild of
5063 * fsp. When we close_file(fsp), it would go with it. No chance to
5064 * reply...
5066 smbreq = talloc_move(talloc_tos(), &state->smbreq);
5068 status = close_file(smbreq, state->fsp, NORMAL_CLOSE);
5069 if (NT_STATUS_IS_OK(status)) {
5070 reply_outbuf(smbreq, 0, 0);
5071 } else {
5072 reply_nterror(smbreq, status);
5074 if (!srv_send_smb(smbreq->sconn,
5075 (char *)smbreq->outbuf,
5076 true,
5077 smbreq->seqnum+1,
5078 IS_CONN_ENCRYPTED(smbreq->conn)||smbreq->encrypted,
5079 NULL)) {
5080 exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
5081 "failed.");
5083 TALLOC_FREE(smbreq);
5086 /****************************************************************************
5087 Reply to a writeclose (Core+ protocol).
5088 ****************************************************************************/
5090 void reply_writeclose(struct smb_request *req)
5092 connection_struct *conn = req->conn;
5093 size_t numtowrite;
5094 ssize_t nwritten = -1;
5095 NTSTATUS close_status = NT_STATUS_OK;
5096 off_t startpos;
5097 const char *data;
5098 struct timespec mtime;
5099 files_struct *fsp;
5100 struct lock_struct lock;
5102 START_PROFILE(SMBwriteclose);
5104 if (req->wct < 6) {
5105 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5106 END_PROFILE(SMBwriteclose);
5107 return;
5110 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5112 if (!check_fsp(conn, req, fsp)) {
5113 END_PROFILE(SMBwriteclose);
5114 return;
5116 if (!CHECK_WRITE(fsp)) {
5117 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5118 END_PROFILE(SMBwriteclose);
5119 return;
5122 numtowrite = SVAL(req->vwv+1, 0);
5123 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5124 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
5125 data = (const char *)req->buf + 1;
5127 if (!fsp->print_file) {
5128 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5129 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5130 &lock);
5132 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
5133 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5134 END_PROFILE(SMBwriteclose);
5135 return;
5139 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5141 set_close_write_time(fsp, mtime);
5144 * More insanity. W2K only closes the file if writelen > 0.
5145 * JRA.
5148 if (numtowrite) {
5149 DEBUG(3,("reply_writeclose: zero length write doesn't close "
5150 "file %s\n", fsp_str_dbg(fsp)));
5151 close_status = close_file(req, fsp, NORMAL_CLOSE);
5154 DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
5155 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
5156 conn->num_files_open));
5158 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
5159 reply_nterror(req, NT_STATUS_DISK_FULL);
5160 goto strict_unlock;
5163 if(!NT_STATUS_IS_OK(close_status)) {
5164 reply_nterror(req, close_status);
5165 goto strict_unlock;
5168 reply_outbuf(req, 1, 0);
5170 SSVAL(req->outbuf,smb_vwv0,nwritten);
5172 strict_unlock:
5173 if (numtowrite && !fsp->print_file) {
5174 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
5177 END_PROFILE(SMBwriteclose);
5178 return;
5181 #undef DBGC_CLASS
5182 #define DBGC_CLASS DBGC_LOCKING
5184 /****************************************************************************
5185 Reply to a lock.
5186 ****************************************************************************/
5188 void reply_lock(struct smb_request *req)
5190 connection_struct *conn = req->conn;
5191 uint64_t count,offset;
5192 NTSTATUS status;
5193 files_struct *fsp;
5194 struct byte_range_lock *br_lck = NULL;
5196 START_PROFILE(SMBlock);
5198 if (req->wct < 5) {
5199 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5200 END_PROFILE(SMBlock);
5201 return;
5204 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5206 if (!check_fsp(conn, req, fsp)) {
5207 END_PROFILE(SMBlock);
5208 return;
5211 count = (uint64_t)IVAL(req->vwv+1, 0);
5212 offset = (uint64_t)IVAL(req->vwv+3, 0);
5214 DEBUG(3,("lock fd=%d %s offset=%.0f count=%.0f\n",
5215 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count));
5217 br_lck = do_lock(req->sconn->msg_ctx,
5218 fsp,
5219 (uint64_t)req->smbpid,
5220 count,
5221 offset,
5222 WRITE_LOCK,
5223 WINDOWS_LOCK,
5224 False, /* Non-blocking lock. */
5225 &status,
5226 NULL,
5227 NULL);
5229 TALLOC_FREE(br_lck);
5231 if (NT_STATUS_V(status)) {
5232 reply_nterror(req, status);
5233 END_PROFILE(SMBlock);
5234 return;
5237 reply_outbuf(req, 0, 0);
5239 END_PROFILE(SMBlock);
5240 return;
5243 /****************************************************************************
5244 Reply to a unlock.
5245 ****************************************************************************/
5247 void reply_unlock(struct smb_request *req)
5249 connection_struct *conn = req->conn;
5250 uint64_t count,offset;
5251 NTSTATUS status;
5252 files_struct *fsp;
5254 START_PROFILE(SMBunlock);
5256 if (req->wct < 5) {
5257 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5258 END_PROFILE(SMBunlock);
5259 return;
5262 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5264 if (!check_fsp(conn, req, fsp)) {
5265 END_PROFILE(SMBunlock);
5266 return;
5269 count = (uint64_t)IVAL(req->vwv+1, 0);
5270 offset = (uint64_t)IVAL(req->vwv+3, 0);
5272 status = do_unlock(req->sconn->msg_ctx,
5273 fsp,
5274 (uint64_t)req->smbpid,
5275 count,
5276 offset,
5277 WINDOWS_LOCK);
5279 if (NT_STATUS_V(status)) {
5280 reply_nterror(req, status);
5281 END_PROFILE(SMBunlock);
5282 return;
5285 DEBUG( 3, ( "unlock fd=%d %s offset=%.0f count=%.0f\n",
5286 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count ) );
5288 reply_outbuf(req, 0, 0);
5290 END_PROFILE(SMBunlock);
5291 return;
5294 #undef DBGC_CLASS
5295 #define DBGC_CLASS DBGC_ALL
5297 /****************************************************************************
5298 Reply to a tdis.
5299 conn POINTER CAN BE NULL HERE !
5300 ****************************************************************************/
5302 void reply_tdis(struct smb_request *req)
5304 NTSTATUS status;
5305 connection_struct *conn = req->conn;
5306 struct smbXsrv_tcon *tcon;
5308 START_PROFILE(SMBtdis);
5310 if (!conn) {
5311 DEBUG(4,("Invalid connection in tdis\n"));
5312 reply_force_doserror(req, ERRSRV, ERRinvnid);
5313 END_PROFILE(SMBtdis);
5314 return;
5317 tcon = conn->tcon;
5318 req->conn = NULL;
5321 * TODO: cancel all outstanding requests on the tcon
5323 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
5324 if (!NT_STATUS_IS_OK(status)) {
5325 DEBUG(0, ("reply_tdis: "
5326 "smbXsrv_tcon_disconnect() failed: %s\n",
5327 nt_errstr(status)));
5329 * If we hit this case, there is something completely
5330 * wrong, so we better disconnect the transport connection.
5332 END_PROFILE(SMBtdis);
5333 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
5334 return;
5337 TALLOC_FREE(tcon);
5339 reply_outbuf(req, 0, 0);
5340 END_PROFILE(SMBtdis);
5341 return;
5344 /****************************************************************************
5345 Reply to a echo.
5346 conn POINTER CAN BE NULL HERE !
5347 ****************************************************************************/
5349 void reply_echo(struct smb_request *req)
5351 connection_struct *conn = req->conn;
5352 struct smb_perfcount_data local_pcd;
5353 struct smb_perfcount_data *cur_pcd;
5354 int smb_reverb;
5355 int seq_num;
5357 START_PROFILE(SMBecho);
5359 smb_init_perfcount_data(&local_pcd);
5361 if (req->wct < 1) {
5362 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5363 END_PROFILE(SMBecho);
5364 return;
5367 smb_reverb = SVAL(req->vwv+0, 0);
5369 reply_outbuf(req, 1, req->buflen);
5371 /* copy any incoming data back out */
5372 if (req->buflen > 0) {
5373 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5376 if (smb_reverb > 100) {
5377 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5378 smb_reverb = 100;
5381 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5383 /* this makes sure we catch the request pcd */
5384 if (seq_num == smb_reverb) {
5385 cur_pcd = &req->pcd;
5386 } else {
5387 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5388 cur_pcd = &local_pcd;
5391 SSVAL(req->outbuf,smb_vwv0,seq_num);
5393 show_msg((char *)req->outbuf);
5394 if (!srv_send_smb(req->sconn,
5395 (char *)req->outbuf,
5396 true, req->seqnum+1,
5397 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5398 cur_pcd))
5399 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5402 DEBUG(3,("echo %d times\n", smb_reverb));
5404 TALLOC_FREE(req->outbuf);
5406 END_PROFILE(SMBecho);
5407 return;
5410 /****************************************************************************
5411 Reply to a printopen.
5412 ****************************************************************************/
5414 void reply_printopen(struct smb_request *req)
5416 connection_struct *conn = req->conn;
5417 files_struct *fsp;
5418 NTSTATUS status;
5420 START_PROFILE(SMBsplopen);
5422 if (req->wct < 2) {
5423 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5424 END_PROFILE(SMBsplopen);
5425 return;
5428 if (!CAN_PRINT(conn)) {
5429 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5430 END_PROFILE(SMBsplopen);
5431 return;
5434 status = file_new(req, conn, &fsp);
5435 if(!NT_STATUS_IS_OK(status)) {
5436 reply_nterror(req, status);
5437 END_PROFILE(SMBsplopen);
5438 return;
5441 /* Open for exclusive use, write only. */
5442 status = print_spool_open(fsp, NULL, req->vuid);
5444 if (!NT_STATUS_IS_OK(status)) {
5445 file_free(req, fsp);
5446 reply_nterror(req, status);
5447 END_PROFILE(SMBsplopen);
5448 return;
5451 reply_outbuf(req, 1, 0);
5452 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5454 DEBUG(3,("openprint fd=%d %s\n",
5455 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5457 END_PROFILE(SMBsplopen);
5458 return;
5461 /****************************************************************************
5462 Reply to a printclose.
5463 ****************************************************************************/
5465 void reply_printclose(struct smb_request *req)
5467 connection_struct *conn = req->conn;
5468 files_struct *fsp;
5469 NTSTATUS status;
5471 START_PROFILE(SMBsplclose);
5473 if (req->wct < 1) {
5474 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5475 END_PROFILE(SMBsplclose);
5476 return;
5479 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5481 if (!check_fsp(conn, req, fsp)) {
5482 END_PROFILE(SMBsplclose);
5483 return;
5486 if (!CAN_PRINT(conn)) {
5487 reply_force_doserror(req, ERRSRV, ERRerror);
5488 END_PROFILE(SMBsplclose);
5489 return;
5492 DEBUG(3,("printclose fd=%d %s\n",
5493 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5495 status = close_file(req, fsp, NORMAL_CLOSE);
5497 if(!NT_STATUS_IS_OK(status)) {
5498 reply_nterror(req, status);
5499 END_PROFILE(SMBsplclose);
5500 return;
5503 reply_outbuf(req, 0, 0);
5505 END_PROFILE(SMBsplclose);
5506 return;
5509 /****************************************************************************
5510 Reply to a printqueue.
5511 ****************************************************************************/
5513 void reply_printqueue(struct smb_request *req)
5515 connection_struct *conn = req->conn;
5516 int max_count;
5517 int start_index;
5519 START_PROFILE(SMBsplretq);
5521 if (req->wct < 2) {
5522 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5523 END_PROFILE(SMBsplretq);
5524 return;
5527 max_count = SVAL(req->vwv+0, 0);
5528 start_index = SVAL(req->vwv+1, 0);
5530 /* we used to allow the client to get the cnum wrong, but that
5531 is really quite gross and only worked when there was only
5532 one printer - I think we should now only accept it if they
5533 get it right (tridge) */
5534 if (!CAN_PRINT(conn)) {
5535 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5536 END_PROFILE(SMBsplretq);
5537 return;
5540 reply_outbuf(req, 2, 3);
5541 SSVAL(req->outbuf,smb_vwv0,0);
5542 SSVAL(req->outbuf,smb_vwv1,0);
5543 SCVAL(smb_buf(req->outbuf),0,1);
5544 SSVAL(smb_buf(req->outbuf),1,0);
5546 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5547 start_index, max_count));
5550 TALLOC_CTX *mem_ctx = talloc_tos();
5551 NTSTATUS status;
5552 WERROR werr;
5553 const char *sharename = lp_servicename(mem_ctx, SNUM(conn));
5554 struct rpc_pipe_client *cli = NULL;
5555 struct dcerpc_binding_handle *b = NULL;
5556 struct policy_handle handle;
5557 struct spoolss_DevmodeContainer devmode_ctr;
5558 union spoolss_JobInfo *info;
5559 uint32_t count;
5560 uint32_t num_to_get;
5561 uint32_t first;
5562 uint32_t i;
5564 ZERO_STRUCT(handle);
5566 status = rpc_pipe_open_interface(conn,
5567 &ndr_table_spoolss.syntax_id,
5568 conn->session_info,
5569 conn->sconn->remote_address,
5570 conn->sconn->msg_ctx,
5571 &cli);
5572 if (!NT_STATUS_IS_OK(status)) {
5573 DEBUG(0, ("reply_printqueue: "
5574 "could not connect to spoolss: %s\n",
5575 nt_errstr(status)));
5576 reply_nterror(req, status);
5577 goto out;
5579 b = cli->binding_handle;
5581 ZERO_STRUCT(devmode_ctr);
5583 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5584 sharename,
5585 NULL, devmode_ctr,
5586 SEC_FLAG_MAXIMUM_ALLOWED,
5587 &handle,
5588 &werr);
5589 if (!NT_STATUS_IS_OK(status)) {
5590 reply_nterror(req, status);
5591 goto out;
5593 if (!W_ERROR_IS_OK(werr)) {
5594 reply_nterror(req, werror_to_ntstatus(werr));
5595 goto out;
5598 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5599 &handle,
5600 0, /* firstjob */
5601 0xff, /* numjobs */
5602 2, /* level */
5603 0, /* offered */
5604 &count,
5605 &info);
5606 if (!W_ERROR_IS_OK(werr)) {
5607 reply_nterror(req, werror_to_ntstatus(werr));
5608 goto out;
5611 if (max_count > 0) {
5612 first = start_index;
5613 } else {
5614 first = start_index + max_count + 1;
5617 if (first >= count) {
5618 num_to_get = first;
5619 } else {
5620 num_to_get = first + MIN(ABS(max_count), count - first);
5623 for (i = first; i < num_to_get; i++) {
5624 char blob[28];
5625 char *p = blob;
5626 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
5627 int qstatus;
5628 uint16_t qrapjobid = pjobid_to_rap(sharename,
5629 info[i].info2.job_id);
5631 if (info[i].info2.status == JOB_STATUS_PRINTING) {
5632 qstatus = 2;
5633 } else {
5634 qstatus = 3;
5637 srv_put_dos_date2(p, 0, qtime);
5638 SCVAL(p, 4, qstatus);
5639 SSVAL(p, 5, qrapjobid);
5640 SIVAL(p, 7, info[i].info2.size);
5641 SCVAL(p, 11, 0);
5642 srvstr_push(blob, req->flags2, p+12,
5643 info[i].info2.notify_name, 16, STR_ASCII);
5645 if (message_push_blob(
5646 &req->outbuf,
5647 data_blob_const(
5648 blob, sizeof(blob))) == -1) {
5649 reply_nterror(req, NT_STATUS_NO_MEMORY);
5650 goto out;
5654 if (count > 0) {
5655 SSVAL(req->outbuf,smb_vwv0,count);
5656 SSVAL(req->outbuf,smb_vwv1,
5657 (max_count>0?first+count:first-1));
5658 SCVAL(smb_buf(req->outbuf),0,1);
5659 SSVAL(smb_buf(req->outbuf),1,28*count);
5663 DEBUG(3, ("%u entries returned in queue\n",
5664 (unsigned)count));
5666 out:
5667 if (b && is_valid_policy_hnd(&handle)) {
5668 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5673 END_PROFILE(SMBsplretq);
5674 return;
5677 /****************************************************************************
5678 Reply to a printwrite.
5679 ****************************************************************************/
5681 void reply_printwrite(struct smb_request *req)
5683 connection_struct *conn = req->conn;
5684 int numtowrite;
5685 const char *data;
5686 files_struct *fsp;
5688 START_PROFILE(SMBsplwr);
5690 if (req->wct < 1) {
5691 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5692 END_PROFILE(SMBsplwr);
5693 return;
5696 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5698 if (!check_fsp(conn, req, fsp)) {
5699 END_PROFILE(SMBsplwr);
5700 return;
5703 if (!fsp->print_file) {
5704 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5705 END_PROFILE(SMBsplwr);
5706 return;
5709 if (!CHECK_WRITE(fsp)) {
5710 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5711 END_PROFILE(SMBsplwr);
5712 return;
5715 numtowrite = SVAL(req->buf, 1);
5717 if (req->buflen < numtowrite + 3) {
5718 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5719 END_PROFILE(SMBsplwr);
5720 return;
5723 data = (const char *)req->buf + 3;
5725 if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
5726 reply_nterror(req, map_nt_error_from_unix(errno));
5727 END_PROFILE(SMBsplwr);
5728 return;
5731 DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
5733 END_PROFILE(SMBsplwr);
5734 return;
5737 /****************************************************************************
5738 Reply to a mkdir.
5739 ****************************************************************************/
5741 void reply_mkdir(struct smb_request *req)
5743 connection_struct *conn = req->conn;
5744 struct smb_filename *smb_dname = NULL;
5745 char *directory = NULL;
5746 NTSTATUS status;
5747 TALLOC_CTX *ctx = talloc_tos();
5749 START_PROFILE(SMBmkdir);
5751 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5752 STR_TERMINATE, &status);
5753 if (!NT_STATUS_IS_OK(status)) {
5754 reply_nterror(req, status);
5755 goto out;
5758 status = filename_convert(ctx, conn,
5759 req->flags2 & FLAGS2_DFS_PATHNAMES,
5760 directory,
5762 NULL,
5763 &smb_dname);
5764 if (!NT_STATUS_IS_OK(status)) {
5765 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5766 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5767 ERRSRV, ERRbadpath);
5768 goto out;
5770 reply_nterror(req, status);
5771 goto out;
5774 status = create_directory(conn, req, smb_dname);
5776 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
5778 if (!NT_STATUS_IS_OK(status)) {
5780 if (!use_nt_status()
5781 && NT_STATUS_EQUAL(status,
5782 NT_STATUS_OBJECT_NAME_COLLISION)) {
5784 * Yes, in the DOS error code case we get a
5785 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
5786 * samba4 torture test.
5788 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
5791 reply_nterror(req, status);
5792 goto out;
5795 reply_outbuf(req, 0, 0);
5797 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
5798 out:
5799 TALLOC_FREE(smb_dname);
5800 END_PROFILE(SMBmkdir);
5801 return;
5804 /****************************************************************************
5805 Reply to a rmdir.
5806 ****************************************************************************/
5808 void reply_rmdir(struct smb_request *req)
5810 connection_struct *conn = req->conn;
5811 struct smb_filename *smb_dname = NULL;
5812 char *directory = NULL;
5813 NTSTATUS status;
5814 TALLOC_CTX *ctx = talloc_tos();
5815 files_struct *fsp = NULL;
5816 int info = 0;
5817 struct smbd_server_connection *sconn = req->sconn;
5819 START_PROFILE(SMBrmdir);
5821 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5822 STR_TERMINATE, &status);
5823 if (!NT_STATUS_IS_OK(status)) {
5824 reply_nterror(req, status);
5825 goto out;
5828 status = filename_convert(ctx, conn,
5829 req->flags2 & FLAGS2_DFS_PATHNAMES,
5830 directory,
5832 NULL,
5833 &smb_dname);
5834 if (!NT_STATUS_IS_OK(status)) {
5835 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5836 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5837 ERRSRV, ERRbadpath);
5838 goto out;
5840 reply_nterror(req, status);
5841 goto out;
5844 if (is_ntfs_stream_smb_fname(smb_dname)) {
5845 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
5846 goto out;
5849 status = SMB_VFS_CREATE_FILE(
5850 conn, /* conn */
5851 req, /* req */
5852 0, /* root_dir_fid */
5853 smb_dname, /* fname */
5854 DELETE_ACCESS, /* access_mask */
5855 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5856 FILE_SHARE_DELETE),
5857 FILE_OPEN, /* create_disposition*/
5858 FILE_DIRECTORY_FILE, /* create_options */
5859 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
5860 0, /* oplock_request */
5861 0, /* allocation_size */
5862 0, /* private_flags */
5863 NULL, /* sd */
5864 NULL, /* ea_list */
5865 &fsp, /* result */
5866 &info); /* pinfo */
5868 if (!NT_STATUS_IS_OK(status)) {
5869 if (open_was_deferred(req->sconn, req->mid)) {
5870 /* We have re-scheduled this call. */
5871 goto out;
5873 reply_nterror(req, status);
5874 goto out;
5877 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
5878 if (!NT_STATUS_IS_OK(status)) {
5879 close_file(req, fsp, ERROR_CLOSE);
5880 reply_nterror(req, status);
5881 goto out;
5884 if (!set_delete_on_close(fsp, true,
5885 conn->session_info->security_token,
5886 conn->session_info->unix_token)) {
5887 close_file(req, fsp, ERROR_CLOSE);
5888 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5889 goto out;
5892 status = close_file(req, fsp, NORMAL_CLOSE);
5893 if (!NT_STATUS_IS_OK(status)) {
5894 reply_nterror(req, status);
5895 } else {
5896 reply_outbuf(req, 0, 0);
5899 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
5901 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
5902 out:
5903 TALLOC_FREE(smb_dname);
5904 END_PROFILE(SMBrmdir);
5905 return;
5908 /*******************************************************************
5909 Resolve wildcards in a filename rename.
5910 ********************************************************************/
5912 static bool resolve_wildcards(TALLOC_CTX *ctx,
5913 const char *name1,
5914 const char *name2,
5915 char **pp_newname)
5917 char *name2_copy = NULL;
5918 char *root1 = NULL;
5919 char *root2 = NULL;
5920 char *ext1 = NULL;
5921 char *ext2 = NULL;
5922 char *p,*p2, *pname1, *pname2;
5924 name2_copy = talloc_strdup(ctx, name2);
5925 if (!name2_copy) {
5926 return False;
5929 pname1 = strrchr_m(name1,'/');
5930 pname2 = strrchr_m(name2_copy,'/');
5932 if (!pname1 || !pname2) {
5933 return False;
5936 /* Truncate the copy of name2 at the last '/' */
5937 *pname2 = '\0';
5939 /* Now go past the '/' */
5940 pname1++;
5941 pname2++;
5943 root1 = talloc_strdup(ctx, pname1);
5944 root2 = talloc_strdup(ctx, pname2);
5946 if (!root1 || !root2) {
5947 return False;
5950 p = strrchr_m(root1,'.');
5951 if (p) {
5952 *p = 0;
5953 ext1 = talloc_strdup(ctx, p+1);
5954 } else {
5955 ext1 = talloc_strdup(ctx, "");
5957 p = strrchr_m(root2,'.');
5958 if (p) {
5959 *p = 0;
5960 ext2 = talloc_strdup(ctx, p+1);
5961 } else {
5962 ext2 = talloc_strdup(ctx, "");
5965 if (!ext1 || !ext2) {
5966 return False;
5969 p = root1;
5970 p2 = root2;
5971 while (*p2) {
5972 if (*p2 == '?') {
5973 /* Hmmm. Should this be mb-aware ? */
5974 *p2 = *p;
5975 p2++;
5976 } else if (*p2 == '*') {
5977 *p2 = '\0';
5978 root2 = talloc_asprintf(ctx, "%s%s",
5979 root2,
5981 if (!root2) {
5982 return False;
5984 break;
5985 } else {
5986 p2++;
5988 if (*p) {
5989 p++;
5993 p = ext1;
5994 p2 = ext2;
5995 while (*p2) {
5996 if (*p2 == '?') {
5997 /* Hmmm. Should this be mb-aware ? */
5998 *p2 = *p;
5999 p2++;
6000 } else if (*p2 == '*') {
6001 *p2 = '\0';
6002 ext2 = talloc_asprintf(ctx, "%s%s",
6003 ext2,
6005 if (!ext2) {
6006 return False;
6008 break;
6009 } else {
6010 p2++;
6012 if (*p) {
6013 p++;
6017 if (*ext2) {
6018 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
6019 name2_copy,
6020 root2,
6021 ext2);
6022 } else {
6023 *pp_newname = talloc_asprintf(ctx, "%s/%s",
6024 name2_copy,
6025 root2);
6028 if (!*pp_newname) {
6029 return False;
6032 return True;
6035 /****************************************************************************
6036 Ensure open files have their names updated. Updated to notify other smbd's
6037 asynchronously.
6038 ****************************************************************************/
6040 static void rename_open_files(connection_struct *conn,
6041 struct share_mode_lock *lck,
6042 uint32_t orig_name_hash,
6043 const struct smb_filename *smb_fname_dst)
6045 files_struct *fsp;
6046 bool did_rename = False;
6047 NTSTATUS status;
6048 uint32_t new_name_hash = 0;
6050 for(fsp = file_find_di_first(conn->sconn, lck->data->id); fsp;
6051 fsp = file_find_di_next(fsp)) {
6052 /* fsp_name is a relative path under the fsp. To change this for other
6053 sharepaths we need to manipulate relative paths. */
6054 /* TODO - create the absolute path and manipulate the newname
6055 relative to the sharepath. */
6056 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
6057 continue;
6059 if (fsp->name_hash != orig_name_hash) {
6060 continue;
6062 DEBUG(10, ("rename_open_files: renaming file %s "
6063 "(file_id %s) from %s -> %s\n", fsp_fnum_dbg(fsp),
6064 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
6065 smb_fname_str_dbg(smb_fname_dst)));
6067 status = fsp_set_smb_fname(fsp, smb_fname_dst);
6068 if (NT_STATUS_IS_OK(status)) {
6069 did_rename = True;
6070 new_name_hash = fsp->name_hash;
6074 if (!did_rename) {
6075 DEBUG(10, ("rename_open_files: no open files on file_id %s "
6076 "for %s\n", file_id_string_tos(&lck->data->id),
6077 smb_fname_str_dbg(smb_fname_dst)));
6080 /* Send messages to all smbd's (not ourself) that the name has changed. */
6081 rename_share_filename(conn->sconn->msg_ctx, lck, conn->connectpath,
6082 orig_name_hash, new_name_hash,
6083 smb_fname_dst);
6087 /****************************************************************************
6088 We need to check if the source path is a parent directory of the destination
6089 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
6090 refuse the rename with a sharing violation. Under UNIX the above call can
6091 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
6092 probably need to check that the client is a Windows one before disallowing
6093 this as a UNIX client (one with UNIX extensions) can know the source is a
6094 symlink and make this decision intelligently. Found by an excellent bug
6095 report from <AndyLiebman@aol.com>.
6096 ****************************************************************************/
6098 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
6099 const struct smb_filename *smb_fname_dst)
6101 const char *psrc = smb_fname_src->base_name;
6102 const char *pdst = smb_fname_dst->base_name;
6103 size_t slen;
6105 if (psrc[0] == '.' && psrc[1] == '/') {
6106 psrc += 2;
6108 if (pdst[0] == '.' && pdst[1] == '/') {
6109 pdst += 2;
6111 if ((slen = strlen(psrc)) > strlen(pdst)) {
6112 return False;
6114 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
6118 * Do the notify calls from a rename
6121 static void notify_rename(connection_struct *conn, bool is_dir,
6122 const struct smb_filename *smb_fname_src,
6123 const struct smb_filename *smb_fname_dst)
6125 char *parent_dir_src = NULL;
6126 char *parent_dir_dst = NULL;
6127 uint32 mask;
6129 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
6130 : FILE_NOTIFY_CHANGE_FILE_NAME;
6132 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
6133 &parent_dir_src, NULL) ||
6134 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
6135 &parent_dir_dst, NULL)) {
6136 goto out;
6139 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
6140 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
6141 smb_fname_src->base_name);
6142 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
6143 smb_fname_dst->base_name);
6145 else {
6146 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
6147 smb_fname_src->base_name);
6148 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
6149 smb_fname_dst->base_name);
6152 /* this is a strange one. w2k3 gives an additional event for
6153 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
6154 files, but not directories */
6155 if (!is_dir) {
6156 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6157 FILE_NOTIFY_CHANGE_ATTRIBUTES
6158 |FILE_NOTIFY_CHANGE_CREATION,
6159 smb_fname_dst->base_name);
6161 out:
6162 TALLOC_FREE(parent_dir_src);
6163 TALLOC_FREE(parent_dir_dst);
6166 /****************************************************************************
6167 Returns an error if the parent directory for a filename is open in an
6168 incompatible way.
6169 ****************************************************************************/
6171 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
6172 const struct smb_filename *smb_fname_dst_in)
6174 char *parent_dir = NULL;
6175 struct smb_filename smb_fname_parent;
6176 struct file_id id;
6177 files_struct *fsp = NULL;
6178 int ret;
6180 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
6181 &parent_dir, NULL)) {
6182 return NT_STATUS_NO_MEMORY;
6184 ZERO_STRUCT(smb_fname_parent);
6185 smb_fname_parent.base_name = parent_dir;
6187 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
6188 if (ret == -1) {
6189 return map_nt_error_from_unix(errno);
6193 * We're only checking on this smbd here, mostly good
6194 * enough.. and will pass tests.
6197 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
6198 for (fsp = file_find_di_first(conn->sconn, id); fsp;
6199 fsp = file_find_di_next(fsp)) {
6200 if (fsp->access_mask & DELETE_ACCESS) {
6201 return NT_STATUS_SHARING_VIOLATION;
6204 return NT_STATUS_OK;
6207 /****************************************************************************
6208 Rename an open file - given an fsp.
6209 ****************************************************************************/
6211 NTSTATUS rename_internals_fsp(connection_struct *conn,
6212 files_struct *fsp,
6213 const struct smb_filename *smb_fname_dst_in,
6214 uint32 attrs,
6215 bool replace_if_exists)
6217 TALLOC_CTX *ctx = talloc_tos();
6218 struct smb_filename *smb_fname_dst = NULL;
6219 NTSTATUS status = NT_STATUS_OK;
6220 struct share_mode_lock *lck = NULL;
6221 bool dst_exists, old_is_stream, new_is_stream;
6223 status = check_name(conn, smb_fname_dst_in->base_name);
6224 if (!NT_STATUS_IS_OK(status)) {
6225 return status;
6228 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
6229 if (!NT_STATUS_IS_OK(status)) {
6230 return status;
6233 /* Make a copy of the dst smb_fname structs */
6235 status = copy_smb_filename(ctx, smb_fname_dst_in, &smb_fname_dst);
6236 if (!NT_STATUS_IS_OK(status)) {
6237 goto out;
6241 * Check for special case with case preserving and not
6242 * case sensitive. If the old last component differs from the original
6243 * last component only by case, then we should allow
6244 * the rename (user is trying to change the case of the
6245 * filename).
6247 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
6248 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6249 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
6250 char *last_slash;
6251 char *fname_dst_lcomp_base_mod = NULL;
6252 struct smb_filename *smb_fname_orig_lcomp = NULL;
6255 * Get the last component of the destination name.
6257 last_slash = strrchr_m(smb_fname_dst->base_name, '/');
6258 if (last_slash) {
6259 fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1);
6260 } else {
6261 fname_dst_lcomp_base_mod = talloc_strdup(ctx, smb_fname_dst->base_name);
6263 if (!fname_dst_lcomp_base_mod) {
6264 status = NT_STATUS_NO_MEMORY;
6265 goto out;
6269 * Create an smb_filename struct using the original last
6270 * component of the destination.
6272 status = create_synthetic_smb_fname_split(ctx,
6273 smb_fname_dst->original_lcomp, NULL,
6274 &smb_fname_orig_lcomp);
6275 if (!NT_STATUS_IS_OK(status)) {
6276 TALLOC_FREE(fname_dst_lcomp_base_mod);
6277 goto out;
6280 /* If the base names only differ by case, use original. */
6281 if(!strcsequal(fname_dst_lcomp_base_mod,
6282 smb_fname_orig_lcomp->base_name)) {
6283 char *tmp;
6285 * Replace the modified last component with the
6286 * original.
6288 if (last_slash) {
6289 *last_slash = '\0'; /* Truncate at the '/' */
6290 tmp = talloc_asprintf(smb_fname_dst,
6291 "%s/%s",
6292 smb_fname_dst->base_name,
6293 smb_fname_orig_lcomp->base_name);
6294 } else {
6295 tmp = talloc_asprintf(smb_fname_dst,
6296 "%s",
6297 smb_fname_orig_lcomp->base_name);
6299 if (tmp == NULL) {
6300 status = NT_STATUS_NO_MEMORY;
6301 TALLOC_FREE(fname_dst_lcomp_base_mod);
6302 TALLOC_FREE(smb_fname_orig_lcomp);
6303 goto out;
6305 TALLOC_FREE(smb_fname_dst->base_name);
6306 smb_fname_dst->base_name = tmp;
6309 /* If the stream_names only differ by case, use original. */
6310 if(!strcsequal(smb_fname_dst->stream_name,
6311 smb_fname_orig_lcomp->stream_name)) {
6312 char *tmp = NULL;
6313 /* Use the original stream. */
6314 tmp = talloc_strdup(smb_fname_dst,
6315 smb_fname_orig_lcomp->stream_name);
6316 if (tmp == NULL) {
6317 status = NT_STATUS_NO_MEMORY;
6318 TALLOC_FREE(fname_dst_lcomp_base_mod);
6319 TALLOC_FREE(smb_fname_orig_lcomp);
6320 goto out;
6322 TALLOC_FREE(smb_fname_dst->stream_name);
6323 smb_fname_dst->stream_name = tmp;
6325 TALLOC_FREE(fname_dst_lcomp_base_mod);
6326 TALLOC_FREE(smb_fname_orig_lcomp);
6330 * If the src and dest names are identical - including case,
6331 * don't do the rename, just return success.
6334 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6335 strcsequal(fsp->fsp_name->stream_name,
6336 smb_fname_dst->stream_name)) {
6337 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6338 "- returning success\n",
6339 smb_fname_str_dbg(smb_fname_dst)));
6340 status = NT_STATUS_OK;
6341 goto out;
6344 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6345 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6347 /* Return the correct error code if both names aren't streams. */
6348 if (!old_is_stream && new_is_stream) {
6349 status = NT_STATUS_OBJECT_NAME_INVALID;
6350 goto out;
6353 if (old_is_stream && !new_is_stream) {
6354 status = NT_STATUS_INVALID_PARAMETER;
6355 goto out;
6358 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6360 if(!replace_if_exists && dst_exists) {
6361 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6362 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6363 smb_fname_str_dbg(smb_fname_dst)));
6364 status = NT_STATUS_OBJECT_NAME_COLLISION;
6365 goto out;
6368 if (dst_exists) {
6369 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6370 &smb_fname_dst->st);
6371 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6372 fileid);
6373 /* The file can be open when renaming a stream */
6374 if (dst_fsp && !new_is_stream) {
6375 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6376 status = NT_STATUS_ACCESS_DENIED;
6377 goto out;
6381 /* Ensure we have a valid stat struct for the source. */
6382 status = vfs_stat_fsp(fsp);
6383 if (!NT_STATUS_IS_OK(status)) {
6384 goto out;
6387 status = can_rename(conn, fsp, attrs);
6389 if (!NT_STATUS_IS_OK(status)) {
6390 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6391 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6392 smb_fname_str_dbg(smb_fname_dst)));
6393 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6394 status = NT_STATUS_ACCESS_DENIED;
6395 goto out;
6398 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6399 status = NT_STATUS_ACCESS_DENIED;
6402 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
6405 * We have the file open ourselves, so not being able to get the
6406 * corresponding share mode lock is a fatal error.
6409 SMB_ASSERT(lck != NULL);
6411 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6412 uint32 create_options = fsp->fh->private_options;
6414 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6415 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6416 smb_fname_str_dbg(smb_fname_dst)));
6418 if (!fsp->is_directory &&
6419 !lp_posix_pathnames() &&
6420 (lp_map_archive(SNUM(conn)) ||
6421 lp_store_dos_attributes(SNUM(conn)))) {
6422 /* We must set the archive bit on the newly
6423 renamed file. */
6424 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6425 uint32_t old_dosmode = dos_mode(conn,
6426 smb_fname_dst);
6427 file_set_dosmode(conn,
6428 smb_fname_dst,
6429 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6430 NULL,
6431 true);
6435 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6436 smb_fname_dst);
6438 rename_open_files(conn, lck, fsp->name_hash, smb_fname_dst);
6441 * A rename acts as a new file create w.r.t. allowing an initial delete
6442 * on close, probably because in Windows there is a new handle to the
6443 * new file. If initial delete on close was requested but not
6444 * originally set, we need to set it here. This is probably not 100% correct,
6445 * but will work for the CIFSFS client which in non-posix mode
6446 * depends on these semantics. JRA.
6449 if (create_options & FILE_DELETE_ON_CLOSE) {
6450 status = can_set_delete_on_close(fsp, 0);
6452 if (NT_STATUS_IS_OK(status)) {
6453 /* Note that here we set the *inital* delete on close flag,
6454 * not the regular one. The magic gets handled in close. */
6455 fsp->initial_delete_on_close = True;
6458 TALLOC_FREE(lck);
6459 status = NT_STATUS_OK;
6460 goto out;
6463 TALLOC_FREE(lck);
6465 if (errno == ENOTDIR || errno == EISDIR) {
6466 status = NT_STATUS_OBJECT_NAME_COLLISION;
6467 } else {
6468 status = map_nt_error_from_unix(errno);
6471 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6472 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6473 smb_fname_str_dbg(smb_fname_dst)));
6475 out:
6476 TALLOC_FREE(smb_fname_dst);
6478 return status;
6481 /****************************************************************************
6482 The guts of the rename command, split out so it may be called by the NT SMB
6483 code.
6484 ****************************************************************************/
6486 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6487 connection_struct *conn,
6488 struct smb_request *req,
6489 struct smb_filename *smb_fname_src,
6490 struct smb_filename *smb_fname_dst,
6491 uint32 attrs,
6492 bool replace_if_exists,
6493 bool src_has_wild,
6494 bool dest_has_wild,
6495 uint32_t access_mask)
6497 char *fname_src_dir = NULL;
6498 char *fname_src_mask = NULL;
6499 int count=0;
6500 NTSTATUS status = NT_STATUS_OK;
6501 struct smb_Dir *dir_hnd = NULL;
6502 const char *dname = NULL;
6503 char *talloced = NULL;
6504 long offset = 0;
6505 int create_options = 0;
6506 bool posix_pathnames = lp_posix_pathnames();
6507 int rc;
6510 * Split the old name into directory and last component
6511 * strings. Note that unix_convert may have stripped off a
6512 * leading ./ from both name and newname if the rename is
6513 * at the root of the share. We need to make sure either both
6514 * name and newname contain a / character or neither of them do
6515 * as this is checked in resolve_wildcards().
6518 /* Split up the directory from the filename/mask. */
6519 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6520 &fname_src_dir, &fname_src_mask);
6521 if (!NT_STATUS_IS_OK(status)) {
6522 status = NT_STATUS_NO_MEMORY;
6523 goto out;
6527 * We should only check the mangled cache
6528 * here if unix_convert failed. This means
6529 * that the path in 'mask' doesn't exist
6530 * on the file system and so we need to look
6531 * for a possible mangle. This patch from
6532 * Tine Smukavec <valentin.smukavec@hermes.si>.
6535 if (!VALID_STAT(smb_fname_src->st) &&
6536 mangle_is_mangled(fname_src_mask, conn->params)) {
6537 char *new_mask = NULL;
6538 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6539 conn->params);
6540 if (new_mask) {
6541 TALLOC_FREE(fname_src_mask);
6542 fname_src_mask = new_mask;
6546 if (!src_has_wild) {
6547 files_struct *fsp;
6550 * Only one file needs to be renamed. Append the mask back
6551 * onto the directory.
6553 TALLOC_FREE(smb_fname_src->base_name);
6554 if (ISDOT(fname_src_dir)) {
6555 /* Ensure we use canonical names on open. */
6556 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6557 "%s",
6558 fname_src_mask);
6559 } else {
6560 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6561 "%s/%s",
6562 fname_src_dir,
6563 fname_src_mask);
6565 if (!smb_fname_src->base_name) {
6566 status = NT_STATUS_NO_MEMORY;
6567 goto out;
6570 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6571 "case_preserve = %d, short case preserve = %d, "
6572 "directory = %s, newname = %s, "
6573 "last_component_dest = %s\n",
6574 conn->case_sensitive, conn->case_preserve,
6575 conn->short_case_preserve,
6576 smb_fname_str_dbg(smb_fname_src),
6577 smb_fname_str_dbg(smb_fname_dst),
6578 smb_fname_dst->original_lcomp));
6580 /* The dest name still may have wildcards. */
6581 if (dest_has_wild) {
6582 char *fname_dst_mod = NULL;
6583 if (!resolve_wildcards(smb_fname_dst,
6584 smb_fname_src->base_name,
6585 smb_fname_dst->base_name,
6586 &fname_dst_mod)) {
6587 DEBUG(6, ("rename_internals: resolve_wildcards "
6588 "%s %s failed\n",
6589 smb_fname_src->base_name,
6590 smb_fname_dst->base_name));
6591 status = NT_STATUS_NO_MEMORY;
6592 goto out;
6594 TALLOC_FREE(smb_fname_dst->base_name);
6595 smb_fname_dst->base_name = fname_dst_mod;
6598 ZERO_STRUCT(smb_fname_src->st);
6599 if (posix_pathnames) {
6600 rc = SMB_VFS_LSTAT(conn, smb_fname_src);
6601 } else {
6602 rc = SMB_VFS_STAT(conn, smb_fname_src);
6604 if (rc == -1) {
6605 status = map_nt_error_from_unix_common(errno);
6606 goto out;
6609 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6610 create_options |= FILE_DIRECTORY_FILE;
6613 status = SMB_VFS_CREATE_FILE(
6614 conn, /* conn */
6615 req, /* req */
6616 0, /* root_dir_fid */
6617 smb_fname_src, /* fname */
6618 access_mask, /* access_mask */
6619 (FILE_SHARE_READ | /* share_access */
6620 FILE_SHARE_WRITE),
6621 FILE_OPEN, /* create_disposition*/
6622 create_options, /* create_options */
6623 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6624 0, /* oplock_request */
6625 0, /* allocation_size */
6626 0, /* private_flags */
6627 NULL, /* sd */
6628 NULL, /* ea_list */
6629 &fsp, /* result */
6630 NULL); /* pinfo */
6632 if (!NT_STATUS_IS_OK(status)) {
6633 DEBUG(3, ("Could not open rename source %s: %s\n",
6634 smb_fname_str_dbg(smb_fname_src),
6635 nt_errstr(status)));
6636 goto out;
6639 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6640 attrs, replace_if_exists);
6642 close_file(req, fsp, NORMAL_CLOSE);
6644 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
6645 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
6646 smb_fname_str_dbg(smb_fname_dst)));
6648 goto out;
6652 * Wildcards - process each file that matches.
6654 if (strequal(fname_src_mask, "????????.???")) {
6655 TALLOC_FREE(fname_src_mask);
6656 fname_src_mask = talloc_strdup(ctx, "*");
6657 if (!fname_src_mask) {
6658 status = NT_STATUS_NO_MEMORY;
6659 goto out;
6663 status = check_name(conn, fname_src_dir);
6664 if (!NT_STATUS_IS_OK(status)) {
6665 goto out;
6668 dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask,
6669 attrs);
6670 if (dir_hnd == NULL) {
6671 status = map_nt_error_from_unix(errno);
6672 goto out;
6675 status = NT_STATUS_NO_SUCH_FILE;
6677 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
6678 * - gentest fix. JRA
6681 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
6682 &talloced))) {
6683 files_struct *fsp = NULL;
6684 char *destname = NULL;
6685 bool sysdir_entry = False;
6687 /* Quick check for "." and ".." */
6688 if (ISDOT(dname) || ISDOTDOT(dname)) {
6689 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
6690 sysdir_entry = True;
6691 } else {
6692 TALLOC_FREE(talloced);
6693 continue;
6697 if (!is_visible_file(conn, fname_src_dir, dname,
6698 &smb_fname_src->st, false)) {
6699 TALLOC_FREE(talloced);
6700 continue;
6703 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
6704 TALLOC_FREE(talloced);
6705 continue;
6708 if (sysdir_entry) {
6709 status = NT_STATUS_OBJECT_NAME_INVALID;
6710 break;
6713 TALLOC_FREE(smb_fname_src->base_name);
6714 if (ISDOT(fname_src_dir)) {
6715 /* Ensure we use canonical names on open. */
6716 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6717 "%s",
6718 dname);
6719 } else {
6720 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6721 "%s/%s",
6722 fname_src_dir,
6723 dname);
6725 if (!smb_fname_src->base_name) {
6726 status = NT_STATUS_NO_MEMORY;
6727 goto out;
6730 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6731 smb_fname_dst->base_name,
6732 &destname)) {
6733 DEBUG(6, ("resolve_wildcards %s %s failed\n",
6734 smb_fname_src->base_name, destname));
6735 TALLOC_FREE(talloced);
6736 continue;
6738 if (!destname) {
6739 status = NT_STATUS_NO_MEMORY;
6740 goto out;
6743 TALLOC_FREE(smb_fname_dst->base_name);
6744 smb_fname_dst->base_name = destname;
6746 ZERO_STRUCT(smb_fname_src->st);
6747 if (posix_pathnames) {
6748 SMB_VFS_LSTAT(conn, smb_fname_src);
6749 } else {
6750 SMB_VFS_STAT(conn, smb_fname_src);
6753 create_options = 0;
6755 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6756 create_options |= FILE_DIRECTORY_FILE;
6759 status = SMB_VFS_CREATE_FILE(
6760 conn, /* conn */
6761 req, /* req */
6762 0, /* root_dir_fid */
6763 smb_fname_src, /* fname */
6764 access_mask, /* access_mask */
6765 (FILE_SHARE_READ | /* share_access */
6766 FILE_SHARE_WRITE),
6767 FILE_OPEN, /* create_disposition*/
6768 create_options, /* create_options */
6769 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6770 0, /* oplock_request */
6771 0, /* allocation_size */
6772 0, /* private_flags */
6773 NULL, /* sd */
6774 NULL, /* ea_list */
6775 &fsp, /* result */
6776 NULL); /* pinfo */
6778 if (!NT_STATUS_IS_OK(status)) {
6779 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
6780 "returned %s rename %s -> %s\n",
6781 nt_errstr(status),
6782 smb_fname_str_dbg(smb_fname_src),
6783 smb_fname_str_dbg(smb_fname_dst)));
6784 break;
6787 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6788 dname);
6789 if (!smb_fname_dst->original_lcomp) {
6790 status = NT_STATUS_NO_MEMORY;
6791 goto out;
6794 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6795 attrs, replace_if_exists);
6797 close_file(req, fsp, NORMAL_CLOSE);
6799 if (!NT_STATUS_IS_OK(status)) {
6800 DEBUG(3, ("rename_internals_fsp returned %s for "
6801 "rename %s -> %s\n", nt_errstr(status),
6802 smb_fname_str_dbg(smb_fname_src),
6803 smb_fname_str_dbg(smb_fname_dst)));
6804 break;
6807 count++;
6809 DEBUG(3,("rename_internals: doing rename on %s -> "
6810 "%s\n", smb_fname_str_dbg(smb_fname_src),
6811 smb_fname_str_dbg(smb_fname_src)));
6812 TALLOC_FREE(talloced);
6814 TALLOC_FREE(dir_hnd);
6816 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
6817 status = map_nt_error_from_unix(errno);
6820 out:
6821 TALLOC_FREE(talloced);
6822 TALLOC_FREE(fname_src_dir);
6823 TALLOC_FREE(fname_src_mask);
6824 return status;
6827 /****************************************************************************
6828 Reply to a mv.
6829 ****************************************************************************/
6831 void reply_mv(struct smb_request *req)
6833 connection_struct *conn = req->conn;
6834 char *name = NULL;
6835 char *newname = NULL;
6836 const char *p;
6837 uint32 attrs;
6838 NTSTATUS status;
6839 bool src_has_wcard = False;
6840 bool dest_has_wcard = False;
6841 TALLOC_CTX *ctx = talloc_tos();
6842 struct smb_filename *smb_fname_src = NULL;
6843 struct smb_filename *smb_fname_dst = NULL;
6844 uint32_t src_ucf_flags = lp_posix_pathnames() ? UCF_UNIX_NAME_LOOKUP : UCF_COND_ALLOW_WCARD_LCOMP;
6845 uint32_t dst_ucf_flags = UCF_SAVE_LCOMP | (lp_posix_pathnames() ? 0 : UCF_COND_ALLOW_WCARD_LCOMP);
6846 bool stream_rename = false;
6848 START_PROFILE(SMBmv);
6850 if (req->wct < 1) {
6851 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6852 goto out;
6855 attrs = SVAL(req->vwv+0, 0);
6857 p = (const char *)req->buf + 1;
6858 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
6859 &status, &src_has_wcard);
6860 if (!NT_STATUS_IS_OK(status)) {
6861 reply_nterror(req, status);
6862 goto out;
6864 p++;
6865 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
6866 &status, &dest_has_wcard);
6867 if (!NT_STATUS_IS_OK(status)) {
6868 reply_nterror(req, status);
6869 goto out;
6872 if (!lp_posix_pathnames()) {
6873 /* The newname must begin with a ':' if the
6874 name contains a ':'. */
6875 if (strchr_m(name, ':')) {
6876 if (newname[0] != ':') {
6877 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6878 goto out;
6880 stream_rename = true;
6884 status = filename_convert(ctx,
6885 conn,
6886 req->flags2 & FLAGS2_DFS_PATHNAMES,
6887 name,
6888 src_ucf_flags,
6889 &src_has_wcard,
6890 &smb_fname_src);
6892 if (!NT_STATUS_IS_OK(status)) {
6893 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6894 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6895 ERRSRV, ERRbadpath);
6896 goto out;
6898 reply_nterror(req, status);
6899 goto out;
6902 status = filename_convert(ctx,
6903 conn,
6904 req->flags2 & FLAGS2_DFS_PATHNAMES,
6905 newname,
6906 dst_ucf_flags,
6907 &dest_has_wcard,
6908 &smb_fname_dst);
6910 if (!NT_STATUS_IS_OK(status)) {
6911 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6912 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6913 ERRSRV, ERRbadpath);
6914 goto out;
6916 reply_nterror(req, status);
6917 goto out;
6920 if (stream_rename) {
6921 /* smb_fname_dst->base_name must be the same as
6922 smb_fname_src->base_name. */
6923 TALLOC_FREE(smb_fname_dst->base_name);
6924 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
6925 smb_fname_src->base_name);
6926 if (!smb_fname_dst->base_name) {
6927 reply_nterror(req, NT_STATUS_NO_MEMORY);
6928 goto out;
6932 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
6933 smb_fname_str_dbg(smb_fname_dst)));
6935 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
6936 attrs, False, src_has_wcard, dest_has_wcard,
6937 DELETE_ACCESS);
6938 if (!NT_STATUS_IS_OK(status)) {
6939 if (open_was_deferred(req->sconn, req->mid)) {
6940 /* We have re-scheduled this call. */
6941 goto out;
6943 reply_nterror(req, status);
6944 goto out;
6947 reply_outbuf(req, 0, 0);
6948 out:
6949 TALLOC_FREE(smb_fname_src);
6950 TALLOC_FREE(smb_fname_dst);
6951 END_PROFILE(SMBmv);
6952 return;
6955 /*******************************************************************
6956 Copy a file as part of a reply_copy.
6957 ******************************************************************/
6960 * TODO: check error codes on all callers
6963 NTSTATUS copy_file(TALLOC_CTX *ctx,
6964 connection_struct *conn,
6965 struct smb_filename *smb_fname_src,
6966 struct smb_filename *smb_fname_dst,
6967 int ofun,
6968 int count,
6969 bool target_is_directory)
6971 struct smb_filename *smb_fname_dst_tmp = NULL;
6972 off_t ret=-1;
6973 files_struct *fsp1,*fsp2;
6974 uint32 dosattrs;
6975 uint32 new_create_disposition;
6976 NTSTATUS status;
6979 status = copy_smb_filename(ctx, smb_fname_dst, &smb_fname_dst_tmp);
6980 if (!NT_STATUS_IS_OK(status)) {
6981 return status;
6985 * If the target is a directory, extract the last component from the
6986 * src filename and append it to the dst filename
6988 if (target_is_directory) {
6989 const char *p;
6991 /* dest/target can't be a stream if it's a directory. */
6992 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
6994 p = strrchr_m(smb_fname_src->base_name,'/');
6995 if (p) {
6996 p++;
6997 } else {
6998 p = smb_fname_src->base_name;
7000 smb_fname_dst_tmp->base_name =
7001 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
7003 if (!smb_fname_dst_tmp->base_name) {
7004 status = NT_STATUS_NO_MEMORY;
7005 goto out;
7009 status = vfs_file_exist(conn, smb_fname_src);
7010 if (!NT_STATUS_IS_OK(status)) {
7011 goto out;
7014 if (!target_is_directory && count) {
7015 new_create_disposition = FILE_OPEN;
7016 } else {
7017 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
7018 0, ofun,
7019 NULL, NULL,
7020 &new_create_disposition,
7021 NULL,
7022 NULL)) {
7023 status = NT_STATUS_INVALID_PARAMETER;
7024 goto out;
7028 /* Open the src file for reading. */
7029 status = SMB_VFS_CREATE_FILE(
7030 conn, /* conn */
7031 NULL, /* req */
7032 0, /* root_dir_fid */
7033 smb_fname_src, /* fname */
7034 FILE_GENERIC_READ, /* access_mask */
7035 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7036 FILE_OPEN, /* create_disposition*/
7037 0, /* create_options */
7038 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
7039 INTERNAL_OPEN_ONLY, /* oplock_request */
7040 0, /* allocation_size */
7041 0, /* private_flags */
7042 NULL, /* sd */
7043 NULL, /* ea_list */
7044 &fsp1, /* result */
7045 NULL); /* psbuf */
7047 if (!NT_STATUS_IS_OK(status)) {
7048 goto out;
7051 dosattrs = dos_mode(conn, smb_fname_src);
7053 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
7054 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
7057 /* Open the dst file for writing. */
7058 status = SMB_VFS_CREATE_FILE(
7059 conn, /* conn */
7060 NULL, /* req */
7061 0, /* root_dir_fid */
7062 smb_fname_dst, /* fname */
7063 FILE_GENERIC_WRITE, /* access_mask */
7064 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7065 new_create_disposition, /* create_disposition*/
7066 0, /* create_options */
7067 dosattrs, /* file_attributes */
7068 INTERNAL_OPEN_ONLY, /* oplock_request */
7069 0, /* allocation_size */
7070 0, /* private_flags */
7071 NULL, /* sd */
7072 NULL, /* ea_list */
7073 &fsp2, /* result */
7074 NULL); /* psbuf */
7076 if (!NT_STATUS_IS_OK(status)) {
7077 close_file(NULL, fsp1, ERROR_CLOSE);
7078 goto out;
7081 if (ofun & OPENX_FILE_EXISTS_OPEN) {
7082 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
7083 if (ret == -1) {
7084 DEBUG(0, ("error - vfs lseek returned error %s\n",
7085 strerror(errno)));
7086 status = map_nt_error_from_unix(errno);
7087 close_file(NULL, fsp1, ERROR_CLOSE);
7088 close_file(NULL, fsp2, ERROR_CLOSE);
7089 goto out;
7093 /* Do the actual copy. */
7094 if (smb_fname_src->st.st_ex_size) {
7095 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
7096 } else {
7097 ret = 0;
7100 close_file(NULL, fsp1, NORMAL_CLOSE);
7102 /* Ensure the modtime is set correctly on the destination file. */
7103 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
7106 * As we are opening fsp1 read-only we only expect
7107 * an error on close on fsp2 if we are out of space.
7108 * Thus we don't look at the error return from the
7109 * close of fsp1.
7111 status = close_file(NULL, fsp2, NORMAL_CLOSE);
7113 if (!NT_STATUS_IS_OK(status)) {
7114 goto out;
7117 if (ret != (off_t)smb_fname_src->st.st_ex_size) {
7118 status = NT_STATUS_DISK_FULL;
7119 goto out;
7122 status = NT_STATUS_OK;
7124 out:
7125 TALLOC_FREE(smb_fname_dst_tmp);
7126 return status;
7129 /****************************************************************************
7130 Reply to a file copy.
7131 ****************************************************************************/
7133 void reply_copy(struct smb_request *req)
7135 connection_struct *conn = req->conn;
7136 struct smb_filename *smb_fname_src = NULL;
7137 struct smb_filename *smb_fname_dst = NULL;
7138 char *fname_src = NULL;
7139 char *fname_dst = NULL;
7140 char *fname_src_mask = NULL;
7141 char *fname_src_dir = NULL;
7142 const char *p;
7143 int count=0;
7144 int error = ERRnoaccess;
7145 int tid2;
7146 int ofun;
7147 int flags;
7148 bool target_is_directory=False;
7149 bool source_has_wild = False;
7150 bool dest_has_wild = False;
7151 NTSTATUS status;
7152 TALLOC_CTX *ctx = talloc_tos();
7154 START_PROFILE(SMBcopy);
7156 if (req->wct < 3) {
7157 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7158 goto out;
7161 tid2 = SVAL(req->vwv+0, 0);
7162 ofun = SVAL(req->vwv+1, 0);
7163 flags = SVAL(req->vwv+2, 0);
7165 p = (const char *)req->buf;
7166 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
7167 &status, &source_has_wild);
7168 if (!NT_STATUS_IS_OK(status)) {
7169 reply_nterror(req, status);
7170 goto out;
7172 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
7173 &status, &dest_has_wild);
7174 if (!NT_STATUS_IS_OK(status)) {
7175 reply_nterror(req, status);
7176 goto out;
7179 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
7181 if (tid2 != conn->cnum) {
7182 /* can't currently handle inter share copies XXXX */
7183 DEBUG(3,("Rejecting inter-share copy\n"));
7184 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
7185 goto out;
7188 status = filename_convert(ctx, conn,
7189 req->flags2 & FLAGS2_DFS_PATHNAMES,
7190 fname_src,
7191 UCF_COND_ALLOW_WCARD_LCOMP,
7192 &source_has_wild,
7193 &smb_fname_src);
7194 if (!NT_STATUS_IS_OK(status)) {
7195 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7196 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7197 ERRSRV, ERRbadpath);
7198 goto out;
7200 reply_nterror(req, status);
7201 goto out;
7204 status = filename_convert(ctx, conn,
7205 req->flags2 & FLAGS2_DFS_PATHNAMES,
7206 fname_dst,
7207 UCF_COND_ALLOW_WCARD_LCOMP,
7208 &dest_has_wild,
7209 &smb_fname_dst);
7210 if (!NT_STATUS_IS_OK(status)) {
7211 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7212 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7213 ERRSRV, ERRbadpath);
7214 goto out;
7216 reply_nterror(req, status);
7217 goto out;
7220 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
7222 if ((flags&1) && target_is_directory) {
7223 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
7224 goto out;
7227 if ((flags&2) && !target_is_directory) {
7228 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
7229 goto out;
7232 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
7233 /* wants a tree copy! XXXX */
7234 DEBUG(3,("Rejecting tree copy\n"));
7235 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7236 goto out;
7239 /* Split up the directory from the filename/mask. */
7240 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7241 &fname_src_dir, &fname_src_mask);
7242 if (!NT_STATUS_IS_OK(status)) {
7243 reply_nterror(req, NT_STATUS_NO_MEMORY);
7244 goto out;
7248 * We should only check the mangled cache
7249 * here if unix_convert failed. This means
7250 * that the path in 'mask' doesn't exist
7251 * on the file system and so we need to look
7252 * for a possible mangle. This patch from
7253 * Tine Smukavec <valentin.smukavec@hermes.si>.
7255 if (!VALID_STAT(smb_fname_src->st) &&
7256 mangle_is_mangled(fname_src_mask, conn->params)) {
7257 char *new_mask = NULL;
7258 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
7259 &new_mask, conn->params);
7261 /* Use demangled name if one was successfully found. */
7262 if (new_mask) {
7263 TALLOC_FREE(fname_src_mask);
7264 fname_src_mask = new_mask;
7268 if (!source_has_wild) {
7271 * Only one file needs to be copied. Append the mask back onto
7272 * the directory.
7274 TALLOC_FREE(smb_fname_src->base_name);
7275 if (ISDOT(fname_src_dir)) {
7276 /* Ensure we use canonical names on open. */
7277 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7278 "%s",
7279 fname_src_mask);
7280 } else {
7281 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7282 "%s/%s",
7283 fname_src_dir,
7284 fname_src_mask);
7286 if (!smb_fname_src->base_name) {
7287 reply_nterror(req, NT_STATUS_NO_MEMORY);
7288 goto out;
7291 if (dest_has_wild) {
7292 char *fname_dst_mod = NULL;
7293 if (!resolve_wildcards(smb_fname_dst,
7294 smb_fname_src->base_name,
7295 smb_fname_dst->base_name,
7296 &fname_dst_mod)) {
7297 reply_nterror(req, NT_STATUS_NO_MEMORY);
7298 goto out;
7300 TALLOC_FREE(smb_fname_dst->base_name);
7301 smb_fname_dst->base_name = fname_dst_mod;
7304 status = check_name(conn, smb_fname_src->base_name);
7305 if (!NT_STATUS_IS_OK(status)) {
7306 reply_nterror(req, status);
7307 goto out;
7310 status = check_name(conn, smb_fname_dst->base_name);
7311 if (!NT_STATUS_IS_OK(status)) {
7312 reply_nterror(req, status);
7313 goto out;
7316 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7317 ofun, count, target_is_directory);
7319 if(!NT_STATUS_IS_OK(status)) {
7320 reply_nterror(req, status);
7321 goto out;
7322 } else {
7323 count++;
7325 } else {
7326 struct smb_Dir *dir_hnd = NULL;
7327 const char *dname = NULL;
7328 char *talloced = NULL;
7329 long offset = 0;
7332 * There is a wildcard that requires us to actually read the
7333 * src dir and copy each file matching the mask to the dst.
7334 * Right now streams won't be copied, but this could
7335 * presumably be added with a nested loop for reach dir entry.
7337 SMB_ASSERT(!smb_fname_src->stream_name);
7338 SMB_ASSERT(!smb_fname_dst->stream_name);
7340 smb_fname_src->stream_name = NULL;
7341 smb_fname_dst->stream_name = NULL;
7343 if (strequal(fname_src_mask,"????????.???")) {
7344 TALLOC_FREE(fname_src_mask);
7345 fname_src_mask = talloc_strdup(ctx, "*");
7346 if (!fname_src_mask) {
7347 reply_nterror(req, NT_STATUS_NO_MEMORY);
7348 goto out;
7352 status = check_name(conn, fname_src_dir);
7353 if (!NT_STATUS_IS_OK(status)) {
7354 reply_nterror(req, status);
7355 goto out;
7358 dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0);
7359 if (dir_hnd == NULL) {
7360 status = map_nt_error_from_unix(errno);
7361 reply_nterror(req, status);
7362 goto out;
7365 error = ERRbadfile;
7367 /* Iterate over the src dir copying each entry to the dst. */
7368 while ((dname = ReadDirName(dir_hnd, &offset,
7369 &smb_fname_src->st, &talloced))) {
7370 char *destname = NULL;
7372 if (ISDOT(dname) || ISDOTDOT(dname)) {
7373 TALLOC_FREE(talloced);
7374 continue;
7377 if (!is_visible_file(conn, fname_src_dir, dname,
7378 &smb_fname_src->st, false)) {
7379 TALLOC_FREE(talloced);
7380 continue;
7383 if(!mask_match(dname, fname_src_mask,
7384 conn->case_sensitive)) {
7385 TALLOC_FREE(talloced);
7386 continue;
7389 error = ERRnoaccess;
7391 /* Get the src smb_fname struct setup. */
7392 TALLOC_FREE(smb_fname_src->base_name);
7393 if (ISDOT(fname_src_dir)) {
7394 /* Ensure we use canonical names on open. */
7395 smb_fname_src->base_name =
7396 talloc_asprintf(smb_fname_src, "%s",
7397 dname);
7398 } else {
7399 smb_fname_src->base_name =
7400 talloc_asprintf(smb_fname_src, "%s/%s",
7401 fname_src_dir, dname);
7404 if (!smb_fname_src->base_name) {
7405 TALLOC_FREE(dir_hnd);
7406 TALLOC_FREE(talloced);
7407 reply_nterror(req, NT_STATUS_NO_MEMORY);
7408 goto out;
7411 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7412 smb_fname_dst->base_name,
7413 &destname)) {
7414 TALLOC_FREE(talloced);
7415 continue;
7417 if (!destname) {
7418 TALLOC_FREE(dir_hnd);
7419 TALLOC_FREE(talloced);
7420 reply_nterror(req, NT_STATUS_NO_MEMORY);
7421 goto out;
7424 TALLOC_FREE(smb_fname_dst->base_name);
7425 smb_fname_dst->base_name = destname;
7427 status = check_name(conn, smb_fname_src->base_name);
7428 if (!NT_STATUS_IS_OK(status)) {
7429 TALLOC_FREE(dir_hnd);
7430 TALLOC_FREE(talloced);
7431 reply_nterror(req, status);
7432 goto out;
7435 status = check_name(conn, smb_fname_dst->base_name);
7436 if (!NT_STATUS_IS_OK(status)) {
7437 TALLOC_FREE(dir_hnd);
7438 TALLOC_FREE(talloced);
7439 reply_nterror(req, status);
7440 goto out;
7443 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7444 smb_fname_src->base_name,
7445 smb_fname_dst->base_name));
7447 status = copy_file(ctx, conn, smb_fname_src,
7448 smb_fname_dst, ofun, count,
7449 target_is_directory);
7450 if (NT_STATUS_IS_OK(status)) {
7451 count++;
7454 TALLOC_FREE(talloced);
7456 TALLOC_FREE(dir_hnd);
7459 if (count == 0) {
7460 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7461 goto out;
7464 reply_outbuf(req, 1, 0);
7465 SSVAL(req->outbuf,smb_vwv0,count);
7466 out:
7467 TALLOC_FREE(smb_fname_src);
7468 TALLOC_FREE(smb_fname_dst);
7469 TALLOC_FREE(fname_src);
7470 TALLOC_FREE(fname_dst);
7471 TALLOC_FREE(fname_src_mask);
7472 TALLOC_FREE(fname_src_dir);
7474 END_PROFILE(SMBcopy);
7475 return;
7478 #undef DBGC_CLASS
7479 #define DBGC_CLASS DBGC_LOCKING
7481 /****************************************************************************
7482 Get a lock pid, dealing with large count requests.
7483 ****************************************************************************/
7485 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7486 bool large_file_format)
7488 if(!large_file_format)
7489 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7490 else
7491 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7494 /****************************************************************************
7495 Get a lock count, dealing with large count requests.
7496 ****************************************************************************/
7498 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7499 bool large_file_format)
7501 uint64_t count = 0;
7503 if(!large_file_format) {
7504 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7505 } else {
7507 #if defined(HAVE_LONGLONG)
7508 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7509 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7510 #else /* HAVE_LONGLONG */
7513 * NT4.x seems to be broken in that it sends large file (64 bit)
7514 * lockingX calls even if the CAP_LARGE_FILES was *not*
7515 * negotiated. For boxes without large unsigned ints truncate the
7516 * lock count by dropping the top 32 bits.
7519 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
7520 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
7521 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
7522 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
7523 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
7526 count = (uint64_t)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
7527 #endif /* HAVE_LONGLONG */
7530 return count;
7533 #if !defined(HAVE_LONGLONG)
7534 /****************************************************************************
7535 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
7536 ****************************************************************************/
7538 static uint32 map_lock_offset(uint32 high, uint32 low)
7540 unsigned int i;
7541 uint32 mask = 0;
7542 uint32 highcopy = high;
7545 * Try and find out how many significant bits there are in high.
7548 for(i = 0; highcopy; i++)
7549 highcopy >>= 1;
7552 * We use 31 bits not 32 here as POSIX
7553 * lock offsets may not be negative.
7556 mask = (~0) << (31 - i);
7558 if(low & mask)
7559 return 0; /* Fail. */
7561 high <<= (31 - i);
7563 return (high|low);
7565 #endif /* !defined(HAVE_LONGLONG) */
7567 /****************************************************************************
7568 Get a lock offset, dealing with large offset requests.
7569 ****************************************************************************/
7571 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7572 bool large_file_format, bool *err)
7574 uint64_t offset = 0;
7576 *err = False;
7578 if(!large_file_format) {
7579 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7580 } else {
7582 #if defined(HAVE_LONGLONG)
7583 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7584 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7585 #else /* HAVE_LONGLONG */
7588 * NT4.x seems to be broken in that it sends large file (64 bit)
7589 * lockingX calls even if the CAP_LARGE_FILES was *not*
7590 * negotiated. For boxes without large unsigned ints mangle the
7591 * lock offset by mapping the top 32 bits onto the lower 32.
7594 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
7595 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7596 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
7597 uint32 new_low = 0;
7599 if((new_low = map_lock_offset(high, low)) == 0) {
7600 *err = True;
7601 return (uint64_t)-1;
7604 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
7605 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
7606 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
7607 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
7610 offset = (uint64_t)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7611 #endif /* HAVE_LONGLONG */
7614 return offset;
7617 NTSTATUS smbd_do_locking(struct smb_request *req,
7618 files_struct *fsp,
7619 uint8_t type,
7620 int32_t timeout,
7621 uint16_t num_ulocks,
7622 struct smbd_lock_element *ulocks,
7623 uint16_t num_locks,
7624 struct smbd_lock_element *locks,
7625 bool *async)
7627 connection_struct *conn = req->conn;
7628 int i;
7629 NTSTATUS status = NT_STATUS_OK;
7631 *async = false;
7633 /* Data now points at the beginning of the list
7634 of smb_unlkrng structs */
7635 for(i = 0; i < (int)num_ulocks; i++) {
7636 struct smbd_lock_element *e = &ulocks[i];
7638 DEBUG(10,("smbd_do_locking: unlock start=%.0f, len=%.0f for "
7639 "pid %u, file %s\n",
7640 (double)e->offset,
7641 (double)e->count,
7642 (unsigned int)e->smblctx,
7643 fsp_str_dbg(fsp)));
7645 if (e->brltype != UNLOCK_LOCK) {
7646 /* this can only happen with SMB2 */
7647 return NT_STATUS_INVALID_PARAMETER;
7650 status = do_unlock(req->sconn->msg_ctx,
7651 fsp,
7652 e->smblctx,
7653 e->count,
7654 e->offset,
7655 WINDOWS_LOCK);
7657 DEBUG(10, ("smbd_do_locking: unlock returned %s\n",
7658 nt_errstr(status)));
7660 if (!NT_STATUS_IS_OK(status)) {
7661 return status;
7665 /* Setup the timeout in seconds. */
7667 if (!lp_blocking_locks(SNUM(conn))) {
7668 timeout = 0;
7671 /* Data now points at the beginning of the list
7672 of smb_lkrng structs */
7674 for(i = 0; i < (int)num_locks; i++) {
7675 struct smbd_lock_element *e = &locks[i];
7677 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
7678 "%llu, file %s timeout = %d\n",
7679 (double)e->offset,
7680 (double)e->count,
7681 (unsigned long long)e->smblctx,
7682 fsp_str_dbg(fsp),
7683 (int)timeout));
7685 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7686 struct blocking_lock_record *blr = NULL;
7688 if (num_locks > 1) {
7690 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
7691 * if the lock vector contains one entry. When given mutliple cancel
7692 * requests in a single PDU we expect the server to return an
7693 * error. Windows servers seem to accept the request but only
7694 * cancel the first lock.
7695 * JRA - Do what Windows does (tm) :-).
7698 #if 0
7699 /* MS-CIFS (2.2.4.32.1) behavior. */
7700 return NT_STATUS_DOS(ERRDOS,
7701 ERRcancelviolation);
7702 #else
7703 /* Windows behavior. */
7704 if (i != 0) {
7705 DEBUG(10,("smbd_do_locking: ignoring subsequent "
7706 "cancel request\n"));
7707 continue;
7709 #endif
7712 if (lp_blocking_locks(SNUM(conn))) {
7714 /* Schedule a message to ourselves to
7715 remove the blocking lock record and
7716 return the right error. */
7718 blr = blocking_lock_cancel_smb1(fsp,
7719 e->smblctx,
7720 e->offset,
7721 e->count,
7722 WINDOWS_LOCK,
7723 type,
7724 NT_STATUS_FILE_LOCK_CONFLICT);
7725 if (blr == NULL) {
7726 return NT_STATUS_DOS(
7727 ERRDOS,
7728 ERRcancelviolation);
7731 /* Remove a matching pending lock. */
7732 status = do_lock_cancel(fsp,
7733 e->smblctx,
7734 e->count,
7735 e->offset,
7736 WINDOWS_LOCK,
7737 blr);
7738 } else {
7739 bool blocking_lock = timeout ? true : false;
7740 bool defer_lock = false;
7741 struct byte_range_lock *br_lck;
7742 uint64_t block_smblctx;
7744 br_lck = do_lock(req->sconn->msg_ctx,
7745 fsp,
7746 e->smblctx,
7747 e->count,
7748 e->offset,
7749 e->brltype,
7750 WINDOWS_LOCK,
7751 blocking_lock,
7752 &status,
7753 &block_smblctx,
7754 NULL);
7756 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
7757 /* Windows internal resolution for blocking locks seems
7758 to be about 200ms... Don't wait for less than that. JRA. */
7759 if (timeout != -1 && timeout < lp_lock_spin_time()) {
7760 timeout = lp_lock_spin_time();
7762 defer_lock = true;
7765 /* If a lock sent with timeout of zero would fail, and
7766 * this lock has been requested multiple times,
7767 * according to brl_lock_failed() we convert this
7768 * request to a blocking lock with a timeout of between
7769 * 150 - 300 milliseconds.
7771 * If lp_lock_spin_time() has been set to 0, we skip
7772 * this blocking retry and fail immediately.
7774 * Replacement for do_lock_spin(). JRA. */
7776 if (!req->sconn->using_smb2 &&
7777 br_lck && lp_blocking_locks(SNUM(conn)) &&
7778 lp_lock_spin_time() && !blocking_lock &&
7779 NT_STATUS_EQUAL((status),
7780 NT_STATUS_FILE_LOCK_CONFLICT))
7782 defer_lock = true;
7783 timeout = lp_lock_spin_time();
7786 if (br_lck && defer_lock) {
7788 * A blocking lock was requested. Package up
7789 * this smb into a queued request and push it
7790 * onto the blocking lock queue.
7792 if(push_blocking_lock_request(br_lck,
7793 req,
7794 fsp,
7795 timeout,
7797 e->smblctx,
7798 e->brltype,
7799 WINDOWS_LOCK,
7800 e->offset,
7801 e->count,
7802 block_smblctx)) {
7803 TALLOC_FREE(br_lck);
7804 *async = true;
7805 return NT_STATUS_OK;
7809 TALLOC_FREE(br_lck);
7812 if (!NT_STATUS_IS_OK(status)) {
7813 break;
7817 /* If any of the above locks failed, then we must unlock
7818 all of the previous locks (X/Open spec). */
7820 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
7822 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7823 i = -1; /* we want to skip the for loop */
7827 * Ensure we don't do a remove on the lock that just failed,
7828 * as under POSIX rules, if we have a lock already there, we
7829 * will delete it (and we shouldn't) .....
7831 for(i--; i >= 0; i--) {
7832 struct smbd_lock_element *e = &locks[i];
7834 do_unlock(req->sconn->msg_ctx,
7835 fsp,
7836 e->smblctx,
7837 e->count,
7838 e->offset,
7839 WINDOWS_LOCK);
7841 return status;
7844 DEBUG(3, ("smbd_do_locking: %s type=%d num_locks=%d num_ulocks=%d\n",
7845 fsp_fnum_dbg(fsp), (unsigned int)type, num_locks, num_ulocks));
7847 return NT_STATUS_OK;
7850 /****************************************************************************
7851 Reply to a lockingX request.
7852 ****************************************************************************/
7854 void reply_lockingX(struct smb_request *req)
7856 connection_struct *conn = req->conn;
7857 files_struct *fsp;
7858 unsigned char locktype;
7859 unsigned char oplocklevel;
7860 uint16 num_ulocks;
7861 uint16 num_locks;
7862 int32 lock_timeout;
7863 int i;
7864 const uint8_t *data;
7865 bool large_file_format;
7866 bool err;
7867 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
7868 struct smbd_lock_element *ulocks;
7869 struct smbd_lock_element *locks;
7870 bool async = false;
7872 START_PROFILE(SMBlockingX);
7874 if (req->wct < 8) {
7875 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7876 END_PROFILE(SMBlockingX);
7877 return;
7880 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
7881 locktype = CVAL(req->vwv+3, 0);
7882 oplocklevel = CVAL(req->vwv+3, 1);
7883 num_ulocks = SVAL(req->vwv+6, 0);
7884 num_locks = SVAL(req->vwv+7, 0);
7885 lock_timeout = IVAL(req->vwv+4, 0);
7886 large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
7888 if (!check_fsp(conn, req, fsp)) {
7889 END_PROFILE(SMBlockingX);
7890 return;
7893 data = req->buf;
7895 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
7896 /* we don't support these - and CANCEL_LOCK makes w2k
7897 and XP reboot so I don't really want to be
7898 compatible! (tridge) */
7899 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
7900 END_PROFILE(SMBlockingX);
7901 return;
7904 /* Check if this is an oplock break on a file
7905 we have granted an oplock on.
7907 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
7908 /* Client can insist on breaking to none. */
7909 bool break_to_none = (oplocklevel == 0);
7910 bool result;
7912 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
7913 "for %s\n", (unsigned int)oplocklevel,
7914 fsp_fnum_dbg(fsp)));
7917 * Make sure we have granted an exclusive or batch oplock on
7918 * this file.
7921 if (fsp->oplock_type == 0) {
7923 /* The Samba4 nbench simulator doesn't understand
7924 the difference between break to level2 and break
7925 to none from level2 - it sends oplock break
7926 replies in both cases. Don't keep logging an error
7927 message here - just ignore it. JRA. */
7929 DEBUG(5,("reply_lockingX: Error : oplock break from "
7930 "client for %s (oplock=%d) and no "
7931 "oplock granted on this file (%s).\n",
7932 fsp_fnum_dbg(fsp), fsp->oplock_type,
7933 fsp_str_dbg(fsp)));
7935 /* if this is a pure oplock break request then don't
7936 * send a reply */
7937 if (num_locks == 0 && num_ulocks == 0) {
7938 END_PROFILE(SMBlockingX);
7939 return;
7940 } else {
7941 END_PROFILE(SMBlockingX);
7942 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
7943 return;
7947 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
7948 (break_to_none)) {
7949 result = remove_oplock(fsp);
7950 } else {
7951 result = downgrade_oplock(fsp);
7954 if (!result) {
7955 DEBUG(0, ("reply_lockingX: error in removing "
7956 "oplock on file %s\n", fsp_str_dbg(fsp)));
7957 /* Hmmm. Is this panic justified? */
7958 smb_panic("internal tdb error");
7961 reply_to_oplock_break_requests(fsp);
7963 /* if this is a pure oplock break request then don't send a
7964 * reply */
7965 if (num_locks == 0 && num_ulocks == 0) {
7966 /* Sanity check - ensure a pure oplock break is not a
7967 chained request. */
7968 if(CVAL(req->vwv+0, 0) != 0xff)
7969 DEBUG(0,("reply_lockingX: Error : pure oplock "
7970 "break is a chained %d request !\n",
7971 (unsigned int)CVAL(req->vwv+0, 0)));
7972 END_PROFILE(SMBlockingX);
7973 return;
7977 if (req->buflen <
7978 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
7979 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7980 END_PROFILE(SMBlockingX);
7981 return;
7984 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
7985 if (ulocks == NULL) {
7986 reply_nterror(req, NT_STATUS_NO_MEMORY);
7987 END_PROFILE(SMBlockingX);
7988 return;
7991 locks = talloc_array(req, struct smbd_lock_element, num_locks);
7992 if (locks == NULL) {
7993 reply_nterror(req, NT_STATUS_NO_MEMORY);
7994 END_PROFILE(SMBlockingX);
7995 return;
7998 /* Data now points at the beginning of the list
7999 of smb_unlkrng structs */
8000 for(i = 0; i < (int)num_ulocks; i++) {
8001 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
8002 ulocks[i].count = get_lock_count(data, i, large_file_format);
8003 ulocks[i].offset = get_lock_offset(data, i, large_file_format, &err);
8004 ulocks[i].brltype = UNLOCK_LOCK;
8007 * There is no error code marked "stupid client bug".... :-).
8009 if(err) {
8010 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8011 END_PROFILE(SMBlockingX);
8012 return;
8016 /* Now do any requested locks */
8017 data += ((large_file_format ? 20 : 10)*num_ulocks);
8019 /* Data now points at the beginning of the list
8020 of smb_lkrng structs */
8022 for(i = 0; i < (int)num_locks; i++) {
8023 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
8024 locks[i].count = get_lock_count(data, i, large_file_format);
8025 locks[i].offset = get_lock_offset(data, i, large_file_format, &err);
8027 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
8028 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8029 locks[i].brltype = PENDING_READ_LOCK;
8030 } else {
8031 locks[i].brltype = READ_LOCK;
8033 } else {
8034 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8035 locks[i].brltype = PENDING_WRITE_LOCK;
8036 } else {
8037 locks[i].brltype = WRITE_LOCK;
8042 * There is no error code marked "stupid client bug".... :-).
8044 if(err) {
8045 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8046 END_PROFILE(SMBlockingX);
8047 return;
8051 status = smbd_do_locking(req, fsp,
8052 locktype, lock_timeout,
8053 num_ulocks, ulocks,
8054 num_locks, locks,
8055 &async);
8056 if (!NT_STATUS_IS_OK(status)) {
8057 END_PROFILE(SMBlockingX);
8058 reply_nterror(req, status);
8059 return;
8061 if (async) {
8062 END_PROFILE(SMBlockingX);
8063 return;
8066 reply_outbuf(req, 2, 0);
8067 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
8068 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
8070 DEBUG(3, ("lockingX %s type=%d num_locks=%d num_ulocks=%d\n",
8071 fsp_fnum_dbg(fsp), (unsigned int)locktype, num_locks, num_ulocks));
8073 END_PROFILE(SMBlockingX);
8076 #undef DBGC_CLASS
8077 #define DBGC_CLASS DBGC_ALL
8079 /****************************************************************************
8080 Reply to a SMBreadbmpx (read block multiplex) request.
8081 Always reply with an error, if someone has a platform really needs this,
8082 please contact vl@samba.org
8083 ****************************************************************************/
8085 void reply_readbmpx(struct smb_request *req)
8087 START_PROFILE(SMBreadBmpx);
8088 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8089 END_PROFILE(SMBreadBmpx);
8090 return;
8093 /****************************************************************************
8094 Reply to a SMBreadbs (read block multiplex secondary) request.
8095 Always reply with an error, if someone has a platform really needs this,
8096 please contact vl@samba.org
8097 ****************************************************************************/
8099 void reply_readbs(struct smb_request *req)
8101 START_PROFILE(SMBreadBs);
8102 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8103 END_PROFILE(SMBreadBs);
8104 return;
8107 /****************************************************************************
8108 Reply to a SMBsetattrE.
8109 ****************************************************************************/
8111 void reply_setattrE(struct smb_request *req)
8113 connection_struct *conn = req->conn;
8114 struct smb_file_time ft;
8115 files_struct *fsp;
8116 NTSTATUS status;
8118 START_PROFILE(SMBsetattrE);
8119 ZERO_STRUCT(ft);
8121 if (req->wct < 7) {
8122 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8123 goto out;
8126 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8128 if(!fsp || (fsp->conn != conn)) {
8129 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8130 goto out;
8134 * Convert the DOS times into unix times.
8137 ft.atime = convert_time_t_to_timespec(
8138 srv_make_unix_date2(req->vwv+3));
8139 ft.mtime = convert_time_t_to_timespec(
8140 srv_make_unix_date2(req->vwv+5));
8141 ft.create_time = convert_time_t_to_timespec(
8142 srv_make_unix_date2(req->vwv+1));
8144 reply_outbuf(req, 0, 0);
8147 * Patch from Ray Frush <frush@engr.colostate.edu>
8148 * Sometimes times are sent as zero - ignore them.
8151 /* Ensure we have a valid stat struct for the source. */
8152 status = vfs_stat_fsp(fsp);
8153 if (!NT_STATUS_IS_OK(status)) {
8154 reply_nterror(req, status);
8155 goto out;
8158 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
8159 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8160 goto out;
8163 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
8164 if (!NT_STATUS_IS_OK(status)) {
8165 reply_nterror(req, status);
8166 goto out;
8169 DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
8170 " createtime=%u\n",
8171 fsp_fnum_dbg(fsp),
8172 (unsigned int)ft.atime.tv_sec,
8173 (unsigned int)ft.mtime.tv_sec,
8174 (unsigned int)ft.create_time.tv_sec
8176 out:
8177 END_PROFILE(SMBsetattrE);
8178 return;
8182 /* Back from the dead for OS/2..... JRA. */
8184 /****************************************************************************
8185 Reply to a SMBwritebmpx (write block multiplex primary) request.
8186 Always reply with an error, if someone has a platform really needs this,
8187 please contact vl@samba.org
8188 ****************************************************************************/
8190 void reply_writebmpx(struct smb_request *req)
8192 START_PROFILE(SMBwriteBmpx);
8193 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8194 END_PROFILE(SMBwriteBmpx);
8195 return;
8198 /****************************************************************************
8199 Reply to a SMBwritebs (write block multiplex secondary) request.
8200 Always reply with an error, if someone has a platform really needs this,
8201 please contact vl@samba.org
8202 ****************************************************************************/
8204 void reply_writebs(struct smb_request *req)
8206 START_PROFILE(SMBwriteBs);
8207 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8208 END_PROFILE(SMBwriteBs);
8209 return;
8212 /****************************************************************************
8213 Reply to a SMBgetattrE.
8214 ****************************************************************************/
8216 void reply_getattrE(struct smb_request *req)
8218 connection_struct *conn = req->conn;
8219 int mode;
8220 files_struct *fsp;
8221 struct timespec create_ts;
8223 START_PROFILE(SMBgetattrE);
8225 if (req->wct < 1) {
8226 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8227 END_PROFILE(SMBgetattrE);
8228 return;
8231 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8233 if(!fsp || (fsp->conn != conn)) {
8234 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8235 END_PROFILE(SMBgetattrE);
8236 return;
8239 /* Do an fstat on this file */
8240 if(fsp_stat(fsp)) {
8241 reply_nterror(req, map_nt_error_from_unix(errno));
8242 END_PROFILE(SMBgetattrE);
8243 return;
8246 mode = dos_mode(conn, fsp->fsp_name);
8249 * Convert the times into dos times. Set create
8250 * date to be last modify date as UNIX doesn't save
8251 * this.
8254 reply_outbuf(req, 11, 0);
8256 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
8257 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
8258 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
8259 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
8260 /* Should we check pending modtime here ? JRA */
8261 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
8262 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
8264 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
8265 SIVAL(req->outbuf, smb_vwv6, 0);
8266 SIVAL(req->outbuf, smb_vwv8, 0);
8267 } else {
8268 uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8269 SIVAL(req->outbuf, smb_vwv6, (uint32)fsp->fsp_name->st.st_ex_size);
8270 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8272 SSVAL(req->outbuf,smb_vwv10, mode);
8274 DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp)));
8276 END_PROFILE(SMBgetattrE);
8277 return;