winbindd: queryuser - only get group name if needed
[Samba.git] / source3 / smbd / reply.c
blob317143f912cd0878deef31a9f9147fe1efc6bfd5
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"
46 #include "lib/util/sys_rw_data.h"
48 /****************************************************************************
49 Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
50 path or anything including wildcards.
51 We're assuming here that '/' is not the second byte in any multibyte char
52 set (a safe assumption). '\\' *may* be the second byte in a multibyte char
53 set.
54 ****************************************************************************/
56 /* Custom version for processing POSIX paths. */
57 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
59 static NTSTATUS check_path_syntax_internal(char *path,
60 bool posix_path,
61 bool *p_last_component_contains_wcard)
63 char *d = path;
64 const char *s = path;
65 NTSTATUS ret = NT_STATUS_OK;
66 bool start_of_name_component = True;
67 bool stream_started = false;
69 *p_last_component_contains_wcard = False;
71 while (*s) {
72 if (stream_started) {
73 switch (*s) {
74 case '/':
75 case '\\':
76 return NT_STATUS_OBJECT_NAME_INVALID;
77 case ':':
78 if (s[1] == '\0') {
79 return NT_STATUS_OBJECT_NAME_INVALID;
81 if (strchr_m(&s[1], ':')) {
82 return NT_STATUS_OBJECT_NAME_INVALID;
84 break;
88 if ((*s == ':') && !posix_path && !stream_started) {
89 if (*p_last_component_contains_wcard) {
90 return NT_STATUS_OBJECT_NAME_INVALID;
92 /* Stream names allow more characters than file names.
93 We're overloading posix_path here to allow a wider
94 range of characters. If stream_started is true this
95 is still a Windows path even if posix_path is true.
96 JRA.
98 stream_started = true;
99 start_of_name_component = false;
100 posix_path = true;
102 if (s[1] == '\0') {
103 return NT_STATUS_OBJECT_NAME_INVALID;
107 if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
109 * Safe to assume is not the second part of a mb char
110 * as this is handled below.
112 /* Eat multiple '/' or '\\' */
113 while (IS_PATH_SEP(*s,posix_path)) {
114 s++;
116 if ((d != path) && (*s != '\0')) {
117 /* We only care about non-leading or trailing '/' or '\\' */
118 *d++ = '/';
121 start_of_name_component = True;
122 /* New component. */
123 *p_last_component_contains_wcard = False;
124 continue;
127 if (start_of_name_component) {
128 if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
129 /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
132 * No mb char starts with '.' so we're safe checking the directory separator here.
135 /* If we just added a '/' - delete it */
136 if ((d > path) && (*(d-1) == '/')) {
137 *(d-1) = '\0';
138 d--;
141 /* Are we at the start ? Can't go back further if so. */
142 if (d <= path) {
143 ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
144 break;
146 /* Go back one level... */
147 /* We know this is safe as '/' cannot be part of a mb sequence. */
148 /* NOTE - if this assumption is invalid we are not in good shape... */
149 /* Decrement d first as d points to the *next* char to write into. */
150 for (d--; d > path; d--) {
151 if (*d == '/')
152 break;
154 s += 2; /* Else go past the .. */
155 /* We're still at the start of a name component, just the previous one. */
156 continue;
158 } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
159 if (posix_path) {
160 /* Eat the '.' */
161 s++;
162 continue;
168 if (!(*s & 0x80)) {
169 if (!posix_path) {
170 if (*s <= 0x1f || *s == '|') {
171 return NT_STATUS_OBJECT_NAME_INVALID;
173 switch (*s) {
174 case '*':
175 case '?':
176 case '<':
177 case '>':
178 case '"':
179 *p_last_component_contains_wcard = True;
180 break;
181 default:
182 break;
185 *d++ = *s++;
186 } else {
187 size_t siz;
188 /* Get the size of the next MB character. */
189 next_codepoint(s,&siz);
190 switch(siz) {
191 case 5:
192 *d++ = *s++;
193 /*fall through*/
194 case 4:
195 *d++ = *s++;
196 /*fall through*/
197 case 3:
198 *d++ = *s++;
199 /*fall through*/
200 case 2:
201 *d++ = *s++;
202 /*fall through*/
203 case 1:
204 *d++ = *s++;
205 break;
206 default:
207 DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
208 *d = '\0';
209 return NT_STATUS_INVALID_PARAMETER;
212 start_of_name_component = False;
215 *d = '\0';
217 return ret;
220 /****************************************************************************
221 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
222 No wildcards allowed.
223 ****************************************************************************/
225 NTSTATUS check_path_syntax(char *path)
227 bool ignore;
228 return check_path_syntax_internal(path, False, &ignore);
231 /****************************************************************************
232 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
233 Wildcards allowed - p_contains_wcard returns true if the last component contained
234 a wildcard.
235 ****************************************************************************/
237 NTSTATUS check_path_syntax_wcard(char *path, bool *p_contains_wcard)
239 return check_path_syntax_internal(path, False, p_contains_wcard);
242 /****************************************************************************
243 Check the path for a POSIX client.
244 We're assuming here that '/' is not the second byte in any multibyte char
245 set (a safe assumption).
246 ****************************************************************************/
248 NTSTATUS check_path_syntax_posix(char *path)
250 bool ignore;
251 return check_path_syntax_internal(path, True, &ignore);
254 /****************************************************************************
255 Pull a string and check the path allowing a wilcard - provide for error return.
256 Passes in posix flag.
257 ****************************************************************************/
259 static size_t srvstr_get_path_wcard_internal(TALLOC_CTX *ctx,
260 const char *base_ptr,
261 uint16_t smb_flags2,
262 char **pp_dest,
263 const char *src,
264 size_t src_len,
265 int flags,
266 bool posix_pathnames,
267 NTSTATUS *err,
268 bool *contains_wcard)
270 size_t ret;
272 *pp_dest = NULL;
274 ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
275 src_len, flags);
277 if (!*pp_dest) {
278 *err = NT_STATUS_INVALID_PARAMETER;
279 return ret;
282 *contains_wcard = False;
284 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
286 * For a DFS path the function parse_dfs_path()
287 * will do the path processing, just make a copy.
289 *err = NT_STATUS_OK;
290 return ret;
293 if (posix_pathnames) {
294 *err = check_path_syntax_posix(*pp_dest);
295 } else {
296 *err = check_path_syntax_wcard(*pp_dest, contains_wcard);
299 return ret;
302 /****************************************************************************
303 Pull a string and check the path allowing a wilcard - provide for error return.
304 ****************************************************************************/
306 size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
307 const char *base_ptr,
308 uint16_t smb_flags2,
309 char **pp_dest,
310 const char *src,
311 size_t src_len,
312 int flags,
313 NTSTATUS *err,
314 bool *contains_wcard)
316 return srvstr_get_path_wcard_internal(ctx,
317 base_ptr,
318 smb_flags2,
319 pp_dest,
320 src,
321 src_len,
322 flags,
323 false,
324 err,
325 contains_wcard);
328 /****************************************************************************
329 Pull a string and check the path allowing a wilcard - provide for error return.
330 posix_pathnames version.
331 ****************************************************************************/
333 size_t srvstr_get_path_wcard_posix(TALLOC_CTX *ctx,
334 const char *base_ptr,
335 uint16_t smb_flags2,
336 char **pp_dest,
337 const char *src,
338 size_t src_len,
339 int flags,
340 NTSTATUS *err,
341 bool *contains_wcard)
343 return srvstr_get_path_wcard_internal(ctx,
344 base_ptr,
345 smb_flags2,
346 pp_dest,
347 src,
348 src_len,
349 flags,
350 true,
351 err,
352 contains_wcard);
355 /****************************************************************************
356 Pull a string and check the path - provide for error return.
357 ****************************************************************************/
359 size_t srvstr_get_path(TALLOC_CTX *ctx,
360 const char *base_ptr,
361 uint16_t smb_flags2,
362 char **pp_dest,
363 const char *src,
364 size_t src_len,
365 int flags,
366 NTSTATUS *err)
368 bool ignore;
369 return srvstr_get_path_wcard_internal(ctx,
370 base_ptr,
371 smb_flags2,
372 pp_dest,
373 src,
374 src_len,
375 flags,
376 false,
377 err,
378 &ignore);
381 /****************************************************************************
382 Pull a string and check the path - provide for error return.
383 posix_pathnames version.
384 ****************************************************************************/
386 size_t srvstr_get_path_posix(TALLOC_CTX *ctx,
387 const char *base_ptr,
388 uint16_t smb_flags2,
389 char **pp_dest,
390 const char *src,
391 size_t src_len,
392 int flags,
393 NTSTATUS *err)
395 bool ignore;
396 return srvstr_get_path_wcard_internal(ctx,
397 base_ptr,
398 smb_flags2,
399 pp_dest,
400 src,
401 src_len,
402 flags,
403 true,
404 err,
405 &ignore);
409 size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req,
410 char **pp_dest, const char *src, int flags,
411 NTSTATUS *err, bool *contains_wcard)
413 ssize_t bufrem = smbreq_bufrem(req, src);
415 if (bufrem < 0) {
416 *err = NT_STATUS_INVALID_PARAMETER;
417 return 0;
420 if (req->posix_pathnames) {
421 return srvstr_get_path_wcard_internal(mem_ctx,
422 (const char *)req->inbuf,
423 req->flags2,
424 pp_dest,
425 src,
426 bufrem,
427 flags,
428 true,
429 err,
430 contains_wcard);
431 } else {
432 return srvstr_get_path_wcard_internal(mem_ctx,
433 (const char *)req->inbuf,
434 req->flags2,
435 pp_dest,
436 src,
437 bufrem,
438 flags,
439 false,
440 err,
441 contains_wcard);
445 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
446 char **pp_dest, const char *src, int flags,
447 NTSTATUS *err)
449 bool ignore;
450 return srvstr_get_path_req_wcard(mem_ctx, req, pp_dest, src,
451 flags, err, &ignore);
455 * pull a string from the smb_buf part of a packet. In this case the
456 * string can either be null terminated or it can be terminated by the
457 * end of the smbbuf area
459 size_t srvstr_pull_req_talloc(TALLOC_CTX *ctx, struct smb_request *req,
460 char **dest, const uint8_t *src, int flags)
462 ssize_t bufrem = smbreq_bufrem(req, src);
464 if (bufrem < 0) {
465 return 0;
468 return pull_string_talloc(ctx, req->inbuf, req->flags2, dest, src,
469 bufrem, flags);
472 /****************************************************************************
473 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
474 ****************************************************************************/
476 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
477 files_struct *fsp)
479 if ((fsp == NULL) || (conn == NULL)) {
480 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
481 return False;
483 if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
484 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
485 return False;
487 return True;
490 /****************************************************************************
491 Check if we have a correct fsp pointing to a file.
492 ****************************************************************************/
494 bool check_fsp(connection_struct *conn, struct smb_request *req,
495 files_struct *fsp)
497 if (!check_fsp_open(conn, req, fsp)) {
498 return False;
500 if (fsp->is_directory) {
501 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
502 return False;
504 if (fsp->fh->fd == -1) {
505 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
506 return False;
508 fsp->num_smb_operations++;
509 return True;
512 /****************************************************************************
513 Check if we have a correct fsp pointing to a quota fake file. Replacement for
514 the CHECK_NTQUOTA_HANDLE_OK macro.
515 ****************************************************************************/
517 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
518 files_struct *fsp)
520 if (!check_fsp_open(conn, req, fsp)) {
521 return false;
524 if (fsp->is_directory) {
525 return false;
528 if (fsp->fake_file_handle == NULL) {
529 return false;
532 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
533 return false;
536 if (fsp->fake_file_handle->private_data == NULL) {
537 return false;
540 return true;
543 static bool netbios_session_retarget(struct smbXsrv_connection *xconn,
544 const char *name, int name_type)
546 char *trim_name;
547 char *trim_name_type;
548 const char *retarget_parm;
549 char *retarget;
550 char *p;
551 int retarget_type = 0x20;
552 int retarget_port = NBT_SMB_PORT;
553 struct sockaddr_storage retarget_addr;
554 struct sockaddr_in *in_addr;
555 bool ret = false;
556 uint8_t outbuf[10];
558 if (get_socket_port(xconn->transport.sock) != NBT_SMB_PORT) {
559 return false;
562 trim_name = talloc_strdup(talloc_tos(), name);
563 if (trim_name == NULL) {
564 goto fail;
566 trim_char(trim_name, ' ', ' ');
568 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
569 name_type);
570 if (trim_name_type == NULL) {
571 goto fail;
574 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
575 trim_name_type, NULL);
576 if (retarget_parm == NULL) {
577 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
578 trim_name, NULL);
580 if (retarget_parm == NULL) {
581 goto fail;
584 retarget = talloc_strdup(trim_name, retarget_parm);
585 if (retarget == NULL) {
586 goto fail;
589 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
591 p = strchr(retarget, ':');
592 if (p != NULL) {
593 *p++ = '\0';
594 retarget_port = atoi(p);
597 p = strchr_m(retarget, '#');
598 if (p != NULL) {
599 *p++ = '\0';
600 if (sscanf(p, "%x", &retarget_type) != 1) {
601 goto fail;
605 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
606 if (!ret) {
607 DEBUG(10, ("could not resolve %s\n", retarget));
608 goto fail;
611 if (retarget_addr.ss_family != AF_INET) {
612 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
613 goto fail;
616 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
618 _smb_setlen(outbuf, 6);
619 SCVAL(outbuf, 0, 0x84);
620 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
621 *(uint16_t *)(outbuf+8) = htons(retarget_port);
623 if (!srv_send_smb(xconn, (char *)outbuf, false, 0, false,
624 NULL)) {
625 exit_server_cleanly("netbios_session_retarget: srv_send_smb "
626 "failed.");
629 ret = true;
630 fail:
631 TALLOC_FREE(trim_name);
632 return ret;
635 static void reply_called_name_not_present(char *outbuf)
637 smb_setlen(outbuf, 1);
638 SCVAL(outbuf, 0, 0x83);
639 SCVAL(outbuf, 4, 0x82);
642 /****************************************************************************
643 Reply to a (netbios-level) special message.
644 ****************************************************************************/
646 void reply_special(struct smbXsrv_connection *xconn, char *inbuf, size_t inbuf_size)
648 struct smbd_server_connection *sconn = xconn->client->sconn;
649 int msg_type = CVAL(inbuf,0);
650 int msg_flags = CVAL(inbuf,1);
652 * We only really use 4 bytes of the outbuf, but for the smb_setlen
653 * calculation & friends (srv_send_smb uses that) we need the full smb
654 * header.
656 char outbuf[smb_size];
658 memset(outbuf, '\0', sizeof(outbuf));
660 smb_setlen(outbuf,0);
662 switch (msg_type) {
663 case NBSSrequest: /* session request */
665 /* inbuf_size is guarenteed to be at least 4. */
666 fstring name1,name2;
667 int name_type1, name_type2;
668 int name_len1, name_len2;
670 *name1 = *name2 = 0;
672 if (xconn->transport.nbt.got_session) {
673 exit_server_cleanly("multiple session request not permitted");
676 SCVAL(outbuf,0,NBSSpositive);
677 SCVAL(outbuf,3,0);
679 /* inbuf_size is guaranteed to be at least 4. */
680 name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
681 if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
682 DEBUG(0,("Invalid name length in session request\n"));
683 reply_called_name_not_present(outbuf);
684 break;
686 name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
687 if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
688 DEBUG(0,("Invalid name length in session request\n"));
689 reply_called_name_not_present(outbuf);
690 break;
693 name_type1 = name_extract((unsigned char *)inbuf,
694 inbuf_size,(unsigned int)4,name1);
695 name_type2 = name_extract((unsigned char *)inbuf,
696 inbuf_size,(unsigned int)(4 + name_len1),name2);
698 if (name_type1 == -1 || name_type2 == -1) {
699 DEBUG(0,("Invalid name type in session request\n"));
700 reply_called_name_not_present(outbuf);
701 break;
704 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
705 name1, name_type1, name2, name_type2));
707 if (netbios_session_retarget(xconn, name1, name_type1)) {
708 exit_server_cleanly("retargeted client");
712 * Windows NT/2k uses "*SMBSERVER" and XP uses
713 * "*SMBSERV" arrggg!!!
715 if (strequal(name1, "*SMBSERVER ")
716 || strequal(name1, "*SMBSERV ")) {
717 char *raddr;
719 raddr = tsocket_address_inet_addr_string(sconn->remote_address,
720 talloc_tos());
721 if (raddr == NULL) {
722 exit_server_cleanly("could not allocate raddr");
725 fstrcpy(name1, raddr);
728 set_local_machine_name(name1, True);
729 set_remote_machine_name(name2, True);
731 if (is_ipaddress(sconn->remote_hostname)) {
732 char *p = discard_const_p(char, sconn->remote_hostname);
734 talloc_free(p);
736 sconn->remote_hostname = talloc_strdup(sconn,
737 get_remote_machine_name());
738 if (sconn->remote_hostname == NULL) {
739 exit_server_cleanly("could not copy remote name");
741 xconn->remote_hostname = sconn->remote_hostname;
744 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
745 get_local_machine_name(), get_remote_machine_name(),
746 name_type2));
748 if (name_type2 == 'R') {
749 /* We are being asked for a pathworks session ---
750 no thanks! */
751 reply_called_name_not_present(outbuf);
752 break;
755 reload_services(sconn, conn_snum_used, true);
756 reopen_logs();
758 xconn->transport.nbt.got_session = true;
759 break;
762 case 0x89: /* session keepalive request
763 (some old clients produce this?) */
764 SCVAL(outbuf,0,NBSSkeepalive);
765 SCVAL(outbuf,3,0);
766 break;
768 case NBSSpositive: /* positive session response */
769 case NBSSnegative: /* negative session response */
770 case NBSSretarget: /* retarget session response */
771 DEBUG(0,("Unexpected session response\n"));
772 break;
774 case NBSSkeepalive: /* session keepalive */
775 default:
776 return;
779 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
780 msg_type, msg_flags));
782 if (!srv_send_smb(xconn, outbuf, false, 0, false, NULL)) {
783 exit_server_cleanly("reply_special: srv_send_smb failed.");
786 if (CVAL(outbuf, 0) != 0x82) {
787 exit_server_cleanly("invalid netbios session");
789 return;
792 /****************************************************************************
793 Reply to a tcon.
794 conn POINTER CAN BE NULL HERE !
795 ****************************************************************************/
797 void reply_tcon(struct smb_request *req)
799 connection_struct *conn = req->conn;
800 const char *service;
801 char *service_buf = NULL;
802 char *password = NULL;
803 char *dev = NULL;
804 int pwlen=0;
805 NTSTATUS nt_status;
806 const uint8_t *p;
807 const char *p2;
808 TALLOC_CTX *ctx = talloc_tos();
809 struct smbXsrv_connection *xconn = req->xconn;
810 NTTIME now = timeval_to_nttime(&req->request_time);
812 START_PROFILE(SMBtcon);
814 if (req->buflen < 4) {
815 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
816 END_PROFILE(SMBtcon);
817 return;
820 p = req->buf + 1;
821 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
822 p += 1;
823 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
824 p += pwlen+1;
825 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
826 p += 1;
828 if (service_buf == NULL || password == NULL || dev == NULL) {
829 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
830 END_PROFILE(SMBtcon);
831 return;
833 p2 = strrchr_m(service_buf,'\\');
834 if (p2) {
835 service = p2+1;
836 } else {
837 service = service_buf;
840 conn = make_connection(req, now, service, dev,
841 req->vuid,&nt_status);
842 req->conn = conn;
844 if (!conn) {
845 reply_nterror(req, nt_status);
846 END_PROFILE(SMBtcon);
847 return;
850 reply_outbuf(req, 2, 0);
851 SSVAL(req->outbuf,smb_vwv0,xconn->smb1.negprot.max_recv);
852 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
853 SSVAL(req->outbuf,smb_tid,conn->cnum);
855 DEBUG(3,("tcon service=%s cnum=%d\n",
856 service, conn->cnum));
858 END_PROFILE(SMBtcon);
859 return;
862 /****************************************************************************
863 Reply to a tcon and X.
864 conn POINTER CAN BE NULL HERE !
865 ****************************************************************************/
867 void reply_tcon_and_X(struct smb_request *req)
869 connection_struct *conn = req->conn;
870 const char *service = NULL;
871 TALLOC_CTX *ctx = talloc_tos();
872 /* what the client thinks the device is */
873 char *client_devicetype = NULL;
874 /* what the server tells the client the share represents */
875 const char *server_devicetype;
876 NTSTATUS nt_status;
877 int passlen;
878 char *path = NULL;
879 const uint8_t *p;
880 const char *q;
881 uint16_t tcon_flags;
882 struct smbXsrv_session *session = NULL;
883 NTTIME now = timeval_to_nttime(&req->request_time);
884 bool session_key_updated = false;
885 uint16_t optional_support = 0;
886 struct smbXsrv_connection *xconn = req->xconn;
888 START_PROFILE(SMBtconX);
890 if (req->wct < 4) {
891 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
892 END_PROFILE(SMBtconX);
893 return;
896 passlen = SVAL(req->vwv+3, 0);
897 tcon_flags = SVAL(req->vwv+2, 0);
899 /* we might have to close an old one */
900 if ((tcon_flags & TCONX_FLAG_DISCONNECT_TID) && conn) {
901 struct smbXsrv_tcon *tcon;
902 NTSTATUS status;
904 tcon = conn->tcon;
905 req->conn = NULL;
906 conn = NULL;
909 * TODO: cancel all outstanding requests on the tcon
911 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
912 if (!NT_STATUS_IS_OK(status)) {
913 DEBUG(0, ("reply_tcon_and_X: "
914 "smbXsrv_tcon_disconnect() failed: %s\n",
915 nt_errstr(status)));
917 * If we hit this case, there is something completely
918 * wrong, so we better disconnect the transport connection.
920 END_PROFILE(SMBtconX);
921 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
922 return;
925 TALLOC_FREE(tcon);
928 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
929 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
930 END_PROFILE(SMBtconX);
931 return;
934 if (xconn->smb1.negprot.encrypted_passwords) {
935 p = req->buf + passlen;
936 } else {
937 p = req->buf + passlen + 1;
940 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
942 if (path == NULL) {
943 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
944 END_PROFILE(SMBtconX);
945 return;
949 * the service name can be either: \\server\share
950 * or share directly like on the DELL PowerVault 705
952 if (*path=='\\') {
953 q = strchr_m(path+2,'\\');
954 if (!q) {
955 reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
956 END_PROFILE(SMBtconX);
957 return;
959 service = q+1;
960 } else {
961 service = path;
964 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
965 &client_devicetype, p,
966 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
968 if (client_devicetype == NULL) {
969 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
970 END_PROFILE(SMBtconX);
971 return;
974 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
976 nt_status = smb1srv_session_lookup(xconn,
977 req->vuid, now, &session);
978 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_USER_SESSION_DELETED)) {
979 reply_force_doserror(req, ERRSRV, ERRbaduid);
980 END_PROFILE(SMBtconX);
981 return;
983 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
984 reply_nterror(req, nt_status);
985 END_PROFILE(SMBtconX);
986 return;
988 if (!NT_STATUS_IS_OK(nt_status)) {
989 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
990 END_PROFILE(SMBtconX);
991 return;
994 if (session->global->auth_session_info == NULL) {
995 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
996 END_PROFILE(SMBtconX);
997 return;
1001 * If there is no application key defined yet
1002 * we create one.
1004 * This means we setup the application key on the
1005 * first tcon that happens via the given session.
1007 * Once the application key is defined, it does not
1008 * change any more.
1010 if (session->global->application_key.length == 0 &&
1011 session->global->signing_key.length > 0)
1013 struct smbXsrv_session *x = session;
1014 struct auth_session_info *session_info =
1015 session->global->auth_session_info;
1016 uint8_t session_key[16];
1018 ZERO_STRUCT(session_key);
1019 memcpy(session_key, x->global->signing_key.data,
1020 MIN(x->global->signing_key.length, sizeof(session_key)));
1023 * The application key is truncated/padded to 16 bytes
1025 x->global->application_key = data_blob_talloc(x->global,
1026 session_key,
1027 sizeof(session_key));
1028 ZERO_STRUCT(session_key);
1029 if (x->global->application_key.data == NULL) {
1030 reply_nterror(req, NT_STATUS_NO_MEMORY);
1031 END_PROFILE(SMBtconX);
1032 return;
1035 if (tcon_flags & TCONX_FLAG_EXTENDED_SIGNATURES) {
1036 smb_key_derivation(x->global->application_key.data,
1037 x->global->application_key.length,
1038 x->global->application_key.data);
1039 optional_support |= SMB_EXTENDED_SIGNATURES;
1043 * Place the application key into the session_info
1045 data_blob_clear_free(&session_info->session_key);
1046 session_info->session_key = data_blob_dup_talloc(session_info,
1047 x->global->application_key);
1048 if (session_info->session_key.data == NULL) {
1049 data_blob_clear_free(&x->global->application_key);
1050 reply_nterror(req, NT_STATUS_NO_MEMORY);
1051 END_PROFILE(SMBtconX);
1052 return;
1054 session_key_updated = true;
1057 conn = make_connection(req, now, service, client_devicetype,
1058 req->vuid, &nt_status);
1059 req->conn =conn;
1061 if (!conn) {
1062 if (session_key_updated) {
1063 struct smbXsrv_session *x = session;
1064 struct auth_session_info *session_info =
1065 session->global->auth_session_info;
1066 data_blob_clear_free(&x->global->application_key);
1067 data_blob_clear_free(&session_info->session_key);
1069 reply_nterror(req, nt_status);
1070 END_PROFILE(SMBtconX);
1071 return;
1074 if ( IS_IPC(conn) )
1075 server_devicetype = "IPC";
1076 else if ( IS_PRINT(conn) )
1077 server_devicetype = "LPT1:";
1078 else
1079 server_devicetype = "A:";
1081 if (get_Protocol() < PROTOCOL_NT1) {
1082 reply_outbuf(req, 2, 0);
1083 if (message_push_string(&req->outbuf, server_devicetype,
1084 STR_TERMINATE|STR_ASCII) == -1) {
1085 reply_nterror(req, NT_STATUS_NO_MEMORY);
1086 END_PROFILE(SMBtconX);
1087 return;
1089 } else {
1090 /* NT sets the fstype of IPC$ to the null string */
1091 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
1093 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
1094 /* Return permissions. */
1095 uint32_t perm1 = 0;
1096 uint32_t perm2 = 0;
1098 reply_outbuf(req, 7, 0);
1100 if (IS_IPC(conn)) {
1101 perm1 = FILE_ALL_ACCESS;
1102 perm2 = FILE_ALL_ACCESS;
1103 } else {
1104 perm1 = conn->share_access;
1107 SIVAL(req->outbuf, smb_vwv3, perm1);
1108 SIVAL(req->outbuf, smb_vwv5, perm2);
1109 } else {
1110 reply_outbuf(req, 3, 0);
1113 if ((message_push_string(&req->outbuf, server_devicetype,
1114 STR_TERMINATE|STR_ASCII) == -1)
1115 || (message_push_string(&req->outbuf, fstype,
1116 STR_TERMINATE) == -1)) {
1117 reply_nterror(req, NT_STATUS_NO_MEMORY);
1118 END_PROFILE(SMBtconX);
1119 return;
1122 /* what does setting this bit do? It is set by NT4 and
1123 may affect the ability to autorun mounted cdroms */
1124 optional_support |= SMB_SUPPORT_SEARCH_BITS;
1125 optional_support |=
1126 (lp_csc_policy(SNUM(conn)) << SMB_CSC_POLICY_SHIFT);
1128 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
1129 DEBUG(2,("Serving %s as a Dfs root\n",
1130 lp_servicename(ctx, SNUM(conn)) ));
1131 optional_support |= SMB_SHARE_IN_DFS;
1134 SSVAL(req->outbuf, smb_vwv2, optional_support);
1137 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
1138 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
1140 DEBUG(3,("tconX service=%s \n",
1141 service));
1143 /* set the incoming and outgoing tid to the just created one */
1144 SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
1145 SSVAL(req->outbuf,smb_tid,conn->cnum);
1147 END_PROFILE(SMBtconX);
1149 req->tid = conn->cnum;
1152 /****************************************************************************
1153 Reply to an unknown type.
1154 ****************************************************************************/
1156 void reply_unknown_new(struct smb_request *req, uint8_t type)
1158 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
1159 smb_fn_name(type), type, type));
1160 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
1161 return;
1164 /****************************************************************************
1165 Reply to an ioctl.
1166 conn POINTER CAN BE NULL HERE !
1167 ****************************************************************************/
1169 void reply_ioctl(struct smb_request *req)
1171 connection_struct *conn = req->conn;
1172 uint16_t device;
1173 uint16_t function;
1174 uint32_t ioctl_code;
1175 int replysize;
1176 char *p;
1178 START_PROFILE(SMBioctl);
1180 if (req->wct < 3) {
1181 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1182 END_PROFILE(SMBioctl);
1183 return;
1186 device = SVAL(req->vwv+1, 0);
1187 function = SVAL(req->vwv+2, 0);
1188 ioctl_code = (device << 16) + function;
1190 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
1192 switch (ioctl_code) {
1193 case IOCTL_QUERY_JOB_INFO:
1194 replysize = 32;
1195 break;
1196 default:
1197 reply_force_doserror(req, ERRSRV, ERRnosupport);
1198 END_PROFILE(SMBioctl);
1199 return;
1202 reply_outbuf(req, 8, replysize+1);
1203 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
1204 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
1205 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
1206 p = smb_buf(req->outbuf);
1207 memset(p, '\0', replysize+1); /* valgrind-safe. */
1208 p += 1; /* Allow for alignment */
1210 switch (ioctl_code) {
1211 case IOCTL_QUERY_JOB_INFO:
1213 NTSTATUS status;
1214 size_t len = 0;
1215 files_struct *fsp = file_fsp(
1216 req, SVAL(req->vwv+0, 0));
1217 if (!fsp) {
1218 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
1219 END_PROFILE(SMBioctl);
1220 return;
1222 /* Job number */
1223 SSVAL(p, 0, print_spool_rap_jobid(fsp->print_file));
1225 status = srvstr_push((char *)req->outbuf, req->flags2, p+2,
1226 lp_netbios_name(), 15,
1227 STR_TERMINATE|STR_ASCII, &len);
1228 if (!NT_STATUS_IS_OK(status)) {
1229 reply_nterror(req, status);
1230 END_PROFILE(SMBioctl);
1231 return;
1233 if (conn) {
1234 status = srvstr_push((char *)req->outbuf, req->flags2,
1235 p+18,
1236 lp_servicename(talloc_tos(),
1237 SNUM(conn)),
1238 13, STR_TERMINATE|STR_ASCII, &len);
1239 if (!NT_STATUS_IS_OK(status)) {
1240 reply_nterror(req, status);
1241 END_PROFILE(SMBioctl);
1242 return;
1244 } else {
1245 memset(p+18, 0, 13);
1247 break;
1251 END_PROFILE(SMBioctl);
1252 return;
1255 /****************************************************************************
1256 Strange checkpath NTSTATUS mapping.
1257 ****************************************************************************/
1259 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
1261 /* Strange DOS error code semantics only for checkpath... */
1262 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
1263 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
1264 /* We need to map to ERRbadpath */
1265 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1268 return status;
1271 /****************************************************************************
1272 Reply to a checkpath.
1273 ****************************************************************************/
1275 void reply_checkpath(struct smb_request *req)
1277 connection_struct *conn = req->conn;
1278 struct smb_filename *smb_fname = NULL;
1279 char *name = NULL;
1280 NTSTATUS status;
1281 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
1282 TALLOC_CTX *ctx = talloc_tos();
1284 START_PROFILE(SMBcheckpath);
1286 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
1287 STR_TERMINATE, &status);
1289 if (!NT_STATUS_IS_OK(status)) {
1290 status = map_checkpath_error(req->flags2, status);
1291 reply_nterror(req, status);
1292 END_PROFILE(SMBcheckpath);
1293 return;
1296 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1298 status = filename_convert(ctx,
1299 conn,
1300 name,
1301 ucf_flags,
1302 NULL,
1303 &smb_fname);
1305 if (!NT_STATUS_IS_OK(status)) {
1306 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1307 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1308 ERRSRV, ERRbadpath);
1309 END_PROFILE(SMBcheckpath);
1310 return;
1312 goto path_err;
1315 if (!VALID_STAT(smb_fname->st) &&
1316 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1317 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1318 smb_fname_str_dbg(smb_fname), strerror(errno)));
1319 status = map_nt_error_from_unix(errno);
1320 goto path_err;
1323 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1324 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1325 ERRDOS, ERRbadpath);
1326 goto out;
1329 reply_outbuf(req, 0, 0);
1331 path_err:
1332 /* We special case this - as when a Windows machine
1333 is parsing a path is steps through the components
1334 one at a time - if a component fails it expects
1335 ERRbadpath, not ERRbadfile.
1337 status = map_checkpath_error(req->flags2, status);
1338 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1340 * Windows returns different error codes if
1341 * the parent directory is valid but not the
1342 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1343 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1344 * if the path is invalid.
1346 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1347 ERRDOS, ERRbadpath);
1348 goto out;
1351 reply_nterror(req, status);
1353 out:
1354 TALLOC_FREE(smb_fname);
1355 END_PROFILE(SMBcheckpath);
1356 return;
1359 /****************************************************************************
1360 Reply to a getatr.
1361 ****************************************************************************/
1363 void reply_getatr(struct smb_request *req)
1365 connection_struct *conn = req->conn;
1366 struct smb_filename *smb_fname = NULL;
1367 char *fname = NULL;
1368 int mode=0;
1369 off_t size=0;
1370 time_t mtime=0;
1371 const char *p;
1372 NTSTATUS status;
1373 TALLOC_CTX *ctx = talloc_tos();
1374 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1376 START_PROFILE(SMBgetatr);
1378 p = (const char *)req->buf + 1;
1379 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1380 if (!NT_STATUS_IS_OK(status)) {
1381 reply_nterror(req, status);
1382 goto out;
1385 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1386 under WfWg - weird! */
1387 if (*fname == '\0') {
1388 mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1389 if (!CAN_WRITE(conn)) {
1390 mode |= FILE_ATTRIBUTE_READONLY;
1392 size = 0;
1393 mtime = 0;
1394 } else {
1395 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
1396 status = filename_convert(ctx,
1397 conn,
1398 fname,
1399 ucf_flags,
1400 NULL,
1401 &smb_fname);
1402 if (!NT_STATUS_IS_OK(status)) {
1403 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1404 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1405 ERRSRV, ERRbadpath);
1406 goto out;
1408 reply_nterror(req, status);
1409 goto out;
1411 if (!VALID_STAT(smb_fname->st) &&
1412 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1413 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1414 smb_fname_str_dbg(smb_fname),
1415 strerror(errno)));
1416 reply_nterror(req, map_nt_error_from_unix(errno));
1417 goto out;
1420 mode = dos_mode(conn, smb_fname);
1421 size = smb_fname->st.st_ex_size;
1423 if (ask_sharemode) {
1424 struct timespec write_time_ts;
1425 struct file_id fileid;
1427 ZERO_STRUCT(write_time_ts);
1428 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1429 get_file_infos(fileid, 0, NULL, &write_time_ts);
1430 if (!null_timespec(write_time_ts)) {
1431 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1435 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1436 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1437 size = 0;
1441 reply_outbuf(req, 10, 0);
1443 SSVAL(req->outbuf,smb_vwv0,mode);
1444 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1445 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1446 } else {
1447 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1449 SIVAL(req->outbuf,smb_vwv3,(uint32_t)size);
1451 if (get_Protocol() >= PROTOCOL_NT1) {
1452 SSVAL(req->outbuf, smb_flg2,
1453 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1456 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1457 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1459 out:
1460 TALLOC_FREE(smb_fname);
1461 TALLOC_FREE(fname);
1462 END_PROFILE(SMBgetatr);
1463 return;
1466 /****************************************************************************
1467 Reply to a setatr.
1468 ****************************************************************************/
1470 void reply_setatr(struct smb_request *req)
1472 struct smb_file_time ft;
1473 connection_struct *conn = req->conn;
1474 struct smb_filename *smb_fname = NULL;
1475 char *fname = NULL;
1476 int mode;
1477 time_t mtime;
1478 const char *p;
1479 NTSTATUS status;
1480 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
1481 TALLOC_CTX *ctx = talloc_tos();
1483 START_PROFILE(SMBsetatr);
1485 ZERO_STRUCT(ft);
1487 if (req->wct < 2) {
1488 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1489 goto out;
1492 p = (const char *)req->buf + 1;
1493 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1494 if (!NT_STATUS_IS_OK(status)) {
1495 reply_nterror(req, status);
1496 goto out;
1499 status = filename_convert(ctx,
1500 conn,
1501 fname,
1502 ucf_flags,
1503 NULL,
1504 &smb_fname);
1505 if (!NT_STATUS_IS_OK(status)) {
1506 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1507 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1508 ERRSRV, ERRbadpath);
1509 goto out;
1511 reply_nterror(req, status);
1512 goto out;
1515 if (smb_fname->base_name[0] == '.' &&
1516 smb_fname->base_name[1] == '\0') {
1518 * Not sure here is the right place to catch this
1519 * condition. Might be moved to somewhere else later -- vl
1521 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1522 goto out;
1525 mode = SVAL(req->vwv+0, 0);
1526 mtime = srv_make_unix_date3(req->vwv+1);
1528 if (mode != FILE_ATTRIBUTE_NORMAL) {
1529 if (VALID_STAT_OF_DIR(smb_fname->st))
1530 mode |= FILE_ATTRIBUTE_DIRECTORY;
1531 else
1532 mode &= ~FILE_ATTRIBUTE_DIRECTORY;
1534 status = check_access(conn, NULL, smb_fname,
1535 FILE_WRITE_ATTRIBUTES);
1536 if (!NT_STATUS_IS_OK(status)) {
1537 reply_nterror(req, status);
1538 goto out;
1541 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1542 false) != 0) {
1543 reply_nterror(req, map_nt_error_from_unix(errno));
1544 goto out;
1548 ft.mtime = convert_time_t_to_timespec(mtime);
1549 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1550 if (!NT_STATUS_IS_OK(status)) {
1551 reply_nterror(req, status);
1552 goto out;
1555 reply_outbuf(req, 0, 0);
1557 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1558 mode));
1559 out:
1560 TALLOC_FREE(smb_fname);
1561 END_PROFILE(SMBsetatr);
1562 return;
1565 /****************************************************************************
1566 Reply to a dskattr.
1567 ****************************************************************************/
1569 void reply_dskattr(struct smb_request *req)
1571 connection_struct *conn = req->conn;
1572 uint64_t ret;
1573 uint64_t dfree,dsize,bsize;
1574 struct smb_filename smb_fname;
1575 START_PROFILE(SMBdskattr);
1577 ZERO_STRUCT(smb_fname);
1578 smb_fname.base_name = discard_const_p(char, ".");
1580 if (SMB_VFS_STAT(conn, &smb_fname) != 0) {
1581 reply_nterror(req, map_nt_error_from_unix(errno));
1582 DBG_WARNING("stat of . failed (%s)\n", strerror(errno));
1583 END_PROFILE(SMBdskattr);
1584 return;
1587 ret = get_dfree_info(conn, &smb_fname, &bsize, &dfree, &dsize);
1588 if (ret == (uint64_t)-1) {
1589 reply_nterror(req, map_nt_error_from_unix(errno));
1590 END_PROFILE(SMBdskattr);
1591 return;
1595 * Force max to fit in 16 bit fields.
1597 while (dfree > WORDMAX || dsize > WORDMAX || bsize < 512) {
1598 dfree /= 2;
1599 dsize /= 2;
1600 bsize *= 2;
1601 if (bsize > (WORDMAX*512)) {
1602 bsize = (WORDMAX*512);
1603 if (dsize > WORDMAX)
1604 dsize = WORDMAX;
1605 if (dfree > WORDMAX)
1606 dfree = WORDMAX;
1607 break;
1611 reply_outbuf(req, 5, 0);
1613 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1614 double total_space, free_space;
1615 /* we need to scale this to a number that DOS6 can handle. We
1616 use floating point so we can handle large drives on systems
1617 that don't have 64 bit integers
1619 we end up displaying a maximum of 2G to DOS systems
1621 total_space = dsize * (double)bsize;
1622 free_space = dfree * (double)bsize;
1624 dsize = (uint64_t)((total_space+63*512) / (64*512));
1625 dfree = (uint64_t)((free_space+63*512) / (64*512));
1627 if (dsize > 0xFFFF) dsize = 0xFFFF;
1628 if (dfree > 0xFFFF) dfree = 0xFFFF;
1630 SSVAL(req->outbuf,smb_vwv0,dsize);
1631 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1632 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1633 SSVAL(req->outbuf,smb_vwv3,dfree);
1634 } else {
1635 SSVAL(req->outbuf,smb_vwv0,dsize);
1636 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1637 SSVAL(req->outbuf,smb_vwv2,512);
1638 SSVAL(req->outbuf,smb_vwv3,dfree);
1641 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1643 END_PROFILE(SMBdskattr);
1644 return;
1648 * Utility function to split the filename from the directory.
1650 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1651 char **fname_dir_out,
1652 char **fname_mask_out)
1654 const char *p = NULL;
1655 char *fname_dir = NULL;
1656 char *fname_mask = NULL;
1658 p = strrchr_m(fname_in, '/');
1659 if (!p) {
1660 fname_dir = talloc_strdup(ctx, ".");
1661 fname_mask = talloc_strdup(ctx, fname_in);
1662 } else {
1663 fname_dir = talloc_strndup(ctx, fname_in,
1664 PTR_DIFF(p, fname_in));
1665 fname_mask = talloc_strdup(ctx, p+1);
1668 if (!fname_dir || !fname_mask) {
1669 TALLOC_FREE(fname_dir);
1670 TALLOC_FREE(fname_mask);
1671 return NT_STATUS_NO_MEMORY;
1674 *fname_dir_out = fname_dir;
1675 *fname_mask_out = fname_mask;
1676 return NT_STATUS_OK;
1679 /****************************************************************************
1680 Make a dir struct.
1681 ****************************************************************************/
1683 static bool make_dir_struct(TALLOC_CTX *ctx,
1684 char *buf,
1685 const char *mask,
1686 const char *fname,
1687 off_t size,
1688 uint32_t mode,
1689 time_t date,
1690 bool uc)
1692 char *p;
1693 char *mask2 = talloc_strdup(ctx, mask);
1695 if (!mask2) {
1696 return False;
1699 if ((mode & FILE_ATTRIBUTE_DIRECTORY) != 0) {
1700 size = 0;
1703 memset(buf+1,' ',11);
1704 if ((p = strchr_m(mask2,'.')) != NULL) {
1705 *p = 0;
1706 push_ascii(buf+1,mask2,8, 0);
1707 push_ascii(buf+9,p+1,3, 0);
1708 *p = '.';
1709 } else {
1710 push_ascii(buf+1,mask2,11, 0);
1713 memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
1714 SCVAL(buf,21,mode);
1715 srv_put_dos_date(buf,22,date);
1716 SSVAL(buf,26,size & 0xFFFF);
1717 SSVAL(buf,28,(size >> 16)&0xFFFF);
1718 /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
1719 Strange, but verified on W2K3. Needed for OS/2. JRA. */
1720 push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
1721 DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
1722 return True;
1725 /****************************************************************************
1726 Reply to a search.
1727 Can be called from SMBsearch, SMBffirst or SMBfunique.
1728 ****************************************************************************/
1730 void reply_search(struct smb_request *req)
1732 connection_struct *conn = req->conn;
1733 char *path = NULL;
1734 char *mask = NULL;
1735 char *directory = NULL;
1736 struct smb_filename *smb_fname = NULL;
1737 char *fname = NULL;
1738 off_t size;
1739 uint32_t mode;
1740 struct timespec date;
1741 uint32_t dirtype;
1742 unsigned int numentries = 0;
1743 unsigned int maxentries = 0;
1744 bool finished = False;
1745 const char *p;
1746 int status_len;
1747 char status[21];
1748 int dptr_num= -1;
1749 bool check_descend = False;
1750 bool expect_close = False;
1751 NTSTATUS nt_status;
1752 bool mask_contains_wcard = False;
1753 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1754 TALLOC_CTX *ctx = talloc_tos();
1755 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1756 struct dptr_struct *dirptr = NULL;
1757 struct smbXsrv_connection *xconn = req->xconn;
1758 struct smbd_server_connection *sconn = req->sconn;
1760 START_PROFILE(SMBsearch);
1762 if (req->wct < 2) {
1763 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1764 goto out;
1767 if (req->posix_pathnames) {
1768 reply_unknown_new(req, req->cmd);
1769 goto out;
1772 /* If we were called as SMBffirst then we must expect close. */
1773 if(req->cmd == SMBffirst) {
1774 expect_close = True;
1777 reply_outbuf(req, 1, 3);
1778 maxentries = SVAL(req->vwv+0, 0);
1779 dirtype = SVAL(req->vwv+1, 0);
1780 p = (const char *)req->buf + 1;
1781 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1782 &nt_status, &mask_contains_wcard);
1783 if (!NT_STATUS_IS_OK(nt_status)) {
1784 reply_nterror(req, nt_status);
1785 goto out;
1788 p++;
1789 status_len = SVAL(p, 0);
1790 p += 2;
1792 /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1794 if (status_len == 0) {
1795 struct smb_filename *smb_dname = NULL;
1796 uint32_t ucf_flags = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
1797 ucf_flags_from_smb_request(req);
1798 nt_status = filename_convert(ctx, conn,
1799 path,
1800 ucf_flags,
1801 &mask_contains_wcard,
1802 &smb_fname);
1803 if (!NT_STATUS_IS_OK(nt_status)) {
1804 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1805 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1806 ERRSRV, ERRbadpath);
1807 goto out;
1809 reply_nterror(req, nt_status);
1810 goto out;
1813 directory = smb_fname->base_name;
1815 p = strrchr_m(directory,'/');
1816 if ((p != NULL) && (*directory != '/')) {
1817 mask = talloc_strdup(ctx, p + 1);
1818 directory = talloc_strndup(ctx, directory,
1819 PTR_DIFF(p, directory));
1820 } else {
1821 mask = talloc_strdup(ctx, directory);
1822 directory = talloc_strdup(ctx,".");
1825 if (!directory) {
1826 reply_nterror(req, NT_STATUS_NO_MEMORY);
1827 goto out;
1830 memset((char *)status,'\0',21);
1831 SCVAL(status,0,(dirtype & 0x1F));
1833 smb_dname = synthetic_smb_fname(talloc_tos(),
1834 directory,
1835 NULL,
1836 NULL,
1837 smb_fname->flags);
1838 if (smb_dname == NULL) {
1839 reply_nterror(req, NT_STATUS_NO_MEMORY);
1840 goto out;
1843 nt_status = dptr_create(conn,
1844 NULL, /* req */
1845 NULL, /* fsp */
1846 smb_dname,
1847 True,
1848 expect_close,
1849 req->smbpid,
1850 mask,
1851 mask_contains_wcard,
1852 dirtype,
1853 &dirptr);
1855 TALLOC_FREE(smb_dname);
1857 if (!NT_STATUS_IS_OK(nt_status)) {
1858 reply_nterror(req, nt_status);
1859 goto out;
1861 dptr_num = dptr_dnum(dirptr);
1862 } else {
1863 int status_dirtype;
1864 const char *dirpath;
1866 memcpy(status,p,21);
1867 status_dirtype = CVAL(status,0) & 0x1F;
1868 if (status_dirtype != (dirtype & 0x1F)) {
1869 dirtype = status_dirtype;
1872 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1873 if (!dirptr) {
1874 goto SearchEmpty;
1876 dirpath = dptr_path(sconn, dptr_num);
1877 directory = talloc_strdup(ctx, dirpath);
1878 if (!directory) {
1879 reply_nterror(req, NT_STATUS_NO_MEMORY);
1880 goto out;
1883 mask = talloc_strdup(ctx, dptr_wcard(sconn, dptr_num));
1884 if (!mask) {
1885 goto SearchEmpty;
1888 * For a 'continue' search we have no string. So
1889 * check from the initial saved string.
1891 if (!req->posix_pathnames) {
1892 mask_contains_wcard = ms_has_wild(mask);
1894 dirtype = dptr_attr(sconn, dptr_num);
1897 DEBUG(4,("dptr_num is %d\n",dptr_num));
1899 /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
1900 dptr_init_search_op(dirptr);
1902 if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1903 char buf[DIR_STRUCT_SIZE];
1904 memcpy(buf,status,21);
1905 if (!make_dir_struct(ctx,buf,"???????????",volume_label(ctx, SNUM(conn)),
1906 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1907 reply_nterror(req, NT_STATUS_NO_MEMORY);
1908 goto out;
1910 dptr_fill(sconn, buf+12,dptr_num);
1911 if (dptr_zero(buf+12) && (status_len==0)) {
1912 numentries = 1;
1913 } else {
1914 numentries = 0;
1916 if (message_push_blob(&req->outbuf,
1917 data_blob_const(buf, sizeof(buf)))
1918 == -1) {
1919 reply_nterror(req, NT_STATUS_NO_MEMORY);
1920 goto out;
1922 } else {
1923 unsigned int i;
1924 size_t hdr_size = ((uint8_t *)smb_buf(req->outbuf) + 3 - req->outbuf);
1925 size_t available_space = xconn->smb1.sessions.max_send - hdr_size;
1927 maxentries = MIN(maxentries, available_space/DIR_STRUCT_SIZE);
1929 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1930 directory,lp_dont_descend(ctx, SNUM(conn))));
1931 if (in_list(directory, lp_dont_descend(ctx, SNUM(conn)),True)) {
1932 check_descend = True;
1935 for (i=numentries;(i<maxentries) && !finished;i++) {
1936 finished = !get_dir_entry(ctx,
1937 dirptr,
1938 mask,
1939 dirtype,
1940 &fname,
1941 &size,
1942 &mode,
1943 &date,
1944 check_descend,
1945 ask_sharemode);
1946 if (!finished) {
1947 char buf[DIR_STRUCT_SIZE];
1948 memcpy(buf,status,21);
1949 if (!make_dir_struct(ctx,
1950 buf,
1951 mask,
1952 fname,
1953 size,
1954 mode,
1955 convert_timespec_to_time_t(date),
1956 !allow_long_path_components)) {
1957 reply_nterror(req, NT_STATUS_NO_MEMORY);
1958 goto out;
1960 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1961 break;
1963 if (message_push_blob(&req->outbuf,
1964 data_blob_const(buf, sizeof(buf)))
1965 == -1) {
1966 reply_nterror(req, NT_STATUS_NO_MEMORY);
1967 goto out;
1969 numentries++;
1974 SearchEmpty:
1976 /* If we were called as SMBffirst with smb_search_id == NULL
1977 and no entries were found then return error and close dirptr
1978 (X/Open spec) */
1980 if (numentries == 0) {
1981 dptr_close(sconn, &dptr_num);
1982 } else if(expect_close && status_len == 0) {
1983 /* Close the dptr - we know it's gone */
1984 dptr_close(sconn, &dptr_num);
1987 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1988 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1989 dptr_close(sconn, &dptr_num);
1992 if ((numentries == 0) && !mask_contains_wcard) {
1993 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1994 goto out;
1997 SSVAL(req->outbuf,smb_vwv0,numentries);
1998 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1999 SCVAL(smb_buf(req->outbuf),0,5);
2000 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
2002 /* The replies here are never long name. */
2003 SSVAL(req->outbuf, smb_flg2,
2004 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
2005 if (!allow_long_path_components) {
2006 SSVAL(req->outbuf, smb_flg2,
2007 SVAL(req->outbuf, smb_flg2)
2008 & (~FLAGS2_LONG_PATH_COMPONENTS));
2011 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
2012 SSVAL(req->outbuf, smb_flg2,
2013 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
2015 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
2016 smb_fn_name(req->cmd),
2017 mask,
2018 directory,
2019 dirtype,
2020 numentries,
2021 maxentries ));
2022 out:
2023 TALLOC_FREE(directory);
2024 TALLOC_FREE(mask);
2025 TALLOC_FREE(smb_fname);
2026 END_PROFILE(SMBsearch);
2027 return;
2030 /****************************************************************************
2031 Reply to a fclose (stop directory search).
2032 ****************************************************************************/
2034 void reply_fclose(struct smb_request *req)
2036 int status_len;
2037 char status[21];
2038 int dptr_num= -2;
2039 const char *p;
2040 char *path = NULL;
2041 NTSTATUS err;
2042 bool path_contains_wcard = False;
2043 TALLOC_CTX *ctx = talloc_tos();
2044 struct smbd_server_connection *sconn = req->sconn;
2046 START_PROFILE(SMBfclose);
2048 if (req->posix_pathnames) {
2049 reply_unknown_new(req, req->cmd);
2050 END_PROFILE(SMBfclose);
2051 return;
2054 p = (const char *)req->buf + 1;
2055 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
2056 &err, &path_contains_wcard);
2057 if (!NT_STATUS_IS_OK(err)) {
2058 reply_nterror(req, err);
2059 END_PROFILE(SMBfclose);
2060 return;
2062 p++;
2063 status_len = SVAL(p,0);
2064 p += 2;
2066 if (status_len == 0) {
2067 reply_force_doserror(req, ERRSRV, ERRsrverror);
2068 END_PROFILE(SMBfclose);
2069 return;
2072 memcpy(status,p,21);
2074 if(dptr_fetch(sconn, status+12,&dptr_num)) {
2075 /* Close the dptr - we know it's gone */
2076 dptr_close(sconn, &dptr_num);
2079 reply_outbuf(req, 1, 0);
2080 SSVAL(req->outbuf,smb_vwv0,0);
2082 DEBUG(3,("search close\n"));
2084 END_PROFILE(SMBfclose);
2085 return;
2088 /****************************************************************************
2089 Reply to an open.
2090 ****************************************************************************/
2092 void reply_open(struct smb_request *req)
2094 connection_struct *conn = req->conn;
2095 struct smb_filename *smb_fname = NULL;
2096 char *fname = NULL;
2097 uint32_t fattr=0;
2098 off_t size = 0;
2099 time_t mtime=0;
2100 int info;
2101 files_struct *fsp;
2102 int oplock_request;
2103 int deny_mode;
2104 uint32_t dos_attr;
2105 uint32_t access_mask;
2106 uint32_t share_mode;
2107 uint32_t create_disposition;
2108 uint32_t create_options = 0;
2109 uint32_t private_flags = 0;
2110 NTSTATUS status;
2111 uint32_t ucf_flags;
2112 TALLOC_CTX *ctx = talloc_tos();
2114 START_PROFILE(SMBopen);
2116 if (req->wct < 2) {
2117 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2118 goto out;
2121 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2122 deny_mode = SVAL(req->vwv+0, 0);
2123 dos_attr = SVAL(req->vwv+1, 0);
2125 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
2126 STR_TERMINATE, &status);
2127 if (!NT_STATUS_IS_OK(status)) {
2128 reply_nterror(req, status);
2129 goto out;
2132 if (!map_open_params_to_ntcreate(fname, deny_mode,
2133 OPENX_FILE_EXISTS_OPEN, &access_mask,
2134 &share_mode, &create_disposition,
2135 &create_options, &private_flags)) {
2136 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2137 goto out;
2140 ucf_flags = filename_create_ucf_flags(req, create_disposition);
2142 status = filename_convert(ctx,
2143 conn,
2144 fname,
2145 ucf_flags,
2146 NULL,
2147 &smb_fname);
2148 if (!NT_STATUS_IS_OK(status)) {
2149 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2150 reply_botherror(req,
2151 NT_STATUS_PATH_NOT_COVERED,
2152 ERRSRV, ERRbadpath);
2153 goto out;
2155 reply_nterror(req, status);
2156 goto out;
2159 status = SMB_VFS_CREATE_FILE(
2160 conn, /* conn */
2161 req, /* req */
2162 0, /* root_dir_fid */
2163 smb_fname, /* fname */
2164 access_mask, /* access_mask */
2165 share_mode, /* share_access */
2166 create_disposition, /* create_disposition*/
2167 create_options, /* create_options */
2168 dos_attr, /* file_attributes */
2169 oplock_request, /* oplock_request */
2170 NULL, /* lease */
2171 0, /* allocation_size */
2172 private_flags,
2173 NULL, /* sd */
2174 NULL, /* ea_list */
2175 &fsp, /* result */
2176 &info, /* pinfo */
2177 NULL, NULL); /* create context */
2179 if (!NT_STATUS_IS_OK(status)) {
2180 if (open_was_deferred(req->xconn, req->mid)) {
2181 /* We have re-scheduled this call. */
2182 goto out;
2184 reply_openerror(req, status);
2185 goto out;
2188 /* Ensure we're pointing at the correct stat struct. */
2189 TALLOC_FREE(smb_fname);
2190 smb_fname = fsp->fsp_name;
2192 size = smb_fname->st.st_ex_size;
2193 fattr = dos_mode(conn, smb_fname);
2195 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
2197 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2198 DEBUG(3,("attempt to open a directory %s\n",
2199 fsp_str_dbg(fsp)));
2200 close_file(req, fsp, ERROR_CLOSE);
2201 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
2202 ERRDOS, ERRnoaccess);
2203 goto out;
2206 reply_outbuf(req, 7, 0);
2207 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2208 SSVAL(req->outbuf,smb_vwv1,fattr);
2209 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2210 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
2211 } else {
2212 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
2214 SIVAL(req->outbuf,smb_vwv4,(uint32_t)size);
2215 SSVAL(req->outbuf,smb_vwv6,deny_mode);
2217 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2218 SCVAL(req->outbuf,smb_flg,
2219 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2222 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2223 SCVAL(req->outbuf,smb_flg,
2224 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2226 out:
2227 END_PROFILE(SMBopen);
2228 return;
2231 /****************************************************************************
2232 Reply to an open and X.
2233 ****************************************************************************/
2235 void reply_open_and_X(struct smb_request *req)
2237 connection_struct *conn = req->conn;
2238 struct smb_filename *smb_fname = NULL;
2239 char *fname = NULL;
2240 uint16_t open_flags;
2241 int deny_mode;
2242 uint32_t smb_attr;
2243 /* Breakout the oplock request bits so we can set the
2244 reply bits separately. */
2245 int ex_oplock_request;
2246 int core_oplock_request;
2247 int oplock_request;
2248 #if 0
2249 int smb_sattr = SVAL(req->vwv+4, 0);
2250 uint32_t smb_time = make_unix_date3(req->vwv+6);
2251 #endif
2252 int smb_ofun;
2253 uint32_t fattr=0;
2254 int mtime=0;
2255 int smb_action = 0;
2256 files_struct *fsp;
2257 NTSTATUS status;
2258 uint64_t allocation_size;
2259 ssize_t retval = -1;
2260 uint32_t access_mask;
2261 uint32_t share_mode;
2262 uint32_t create_disposition;
2263 uint32_t create_options = 0;
2264 uint32_t private_flags = 0;
2265 uint32_t ucf_flags;
2266 TALLOC_CTX *ctx = talloc_tos();
2268 START_PROFILE(SMBopenX);
2270 if (req->wct < 15) {
2271 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2272 goto out;
2275 open_flags = SVAL(req->vwv+2, 0);
2276 deny_mode = SVAL(req->vwv+3, 0);
2277 smb_attr = SVAL(req->vwv+5, 0);
2278 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
2279 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2280 oplock_request = ex_oplock_request | core_oplock_request;
2281 smb_ofun = SVAL(req->vwv+8, 0);
2282 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
2284 /* If it's an IPC, pass off the pipe handler. */
2285 if (IS_IPC(conn)) {
2286 if (lp_nt_pipe_support()) {
2287 reply_open_pipe_and_X(conn, req);
2288 } else {
2289 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
2291 goto out;
2294 /* XXXX we need to handle passed times, sattr and flags */
2295 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
2296 STR_TERMINATE, &status);
2297 if (!NT_STATUS_IS_OK(status)) {
2298 reply_nterror(req, status);
2299 goto out;
2302 if (!map_open_params_to_ntcreate(fname, deny_mode,
2303 smb_ofun,
2304 &access_mask, &share_mode,
2305 &create_disposition,
2306 &create_options,
2307 &private_flags)) {
2308 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2309 goto out;
2312 ucf_flags = filename_create_ucf_flags(req, create_disposition);
2314 status = filename_convert(ctx,
2315 conn,
2316 fname,
2317 ucf_flags,
2318 NULL,
2319 &smb_fname);
2320 if (!NT_STATUS_IS_OK(status)) {
2321 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2322 reply_botherror(req,
2323 NT_STATUS_PATH_NOT_COVERED,
2324 ERRSRV, ERRbadpath);
2325 goto out;
2327 reply_nterror(req, status);
2328 goto out;
2331 status = SMB_VFS_CREATE_FILE(
2332 conn, /* conn */
2333 req, /* req */
2334 0, /* root_dir_fid */
2335 smb_fname, /* fname */
2336 access_mask, /* access_mask */
2337 share_mode, /* share_access */
2338 create_disposition, /* create_disposition*/
2339 create_options, /* create_options */
2340 smb_attr, /* file_attributes */
2341 oplock_request, /* oplock_request */
2342 NULL, /* lease */
2343 0, /* allocation_size */
2344 private_flags,
2345 NULL, /* sd */
2346 NULL, /* ea_list */
2347 &fsp, /* result */
2348 &smb_action, /* pinfo */
2349 NULL, NULL); /* create context */
2351 if (!NT_STATUS_IS_OK(status)) {
2352 if (open_was_deferred(req->xconn, req->mid)) {
2353 /* We have re-scheduled this call. */
2354 goto out;
2356 reply_openerror(req, status);
2357 goto out;
2360 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2361 if the file is truncated or created. */
2362 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2363 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2364 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2365 close_file(req, fsp, ERROR_CLOSE);
2366 reply_nterror(req, NT_STATUS_DISK_FULL);
2367 goto out;
2369 retval = vfs_set_filelen(fsp, (off_t)allocation_size);
2370 if (retval < 0) {
2371 close_file(req, fsp, ERROR_CLOSE);
2372 reply_nterror(req, NT_STATUS_DISK_FULL);
2373 goto out;
2375 status = vfs_stat_fsp(fsp);
2376 if (!NT_STATUS_IS_OK(status)) {
2377 close_file(req, fsp, ERROR_CLOSE);
2378 reply_nterror(req, status);
2379 goto out;
2383 fattr = dos_mode(conn, fsp->fsp_name);
2384 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2385 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2386 close_file(req, fsp, ERROR_CLOSE);
2387 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2388 goto out;
2391 /* If the caller set the extended oplock request bit
2392 and we granted one (by whatever means) - set the
2393 correct bit for extended oplock reply.
2396 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2397 smb_action |= EXTENDED_OPLOCK_GRANTED;
2400 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2401 smb_action |= EXTENDED_OPLOCK_GRANTED;
2404 /* If the caller set the core oplock request bit
2405 and we granted one (by whatever means) - set the
2406 correct bit for core oplock reply.
2409 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2410 reply_outbuf(req, 19, 0);
2411 } else {
2412 reply_outbuf(req, 15, 0);
2415 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2416 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2418 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2419 SCVAL(req->outbuf, smb_flg,
2420 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2423 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2424 SCVAL(req->outbuf, smb_flg,
2425 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2428 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2429 SSVAL(req->outbuf,smb_vwv3,fattr);
2430 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2431 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2432 } else {
2433 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2435 SIVAL(req->outbuf,smb_vwv6,(uint32_t)fsp->fsp_name->st.st_ex_size);
2436 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2437 SSVAL(req->outbuf,smb_vwv11,smb_action);
2439 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2440 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2443 out:
2444 TALLOC_FREE(smb_fname);
2445 END_PROFILE(SMBopenX);
2446 return;
2449 /****************************************************************************
2450 Reply to a SMBulogoffX.
2451 ****************************************************************************/
2453 void reply_ulogoffX(struct smb_request *req)
2455 struct smbd_server_connection *sconn = req->sconn;
2456 struct user_struct *vuser;
2457 struct smbXsrv_session *session = NULL;
2458 NTSTATUS status;
2460 START_PROFILE(SMBulogoffX);
2462 vuser = get_valid_user_struct(sconn, req->vuid);
2464 if(vuser == NULL) {
2465 DEBUG(3,("ulogoff, vuser id %llu does not map to user.\n",
2466 (unsigned long long)req->vuid));
2468 req->vuid = UID_FIELD_INVALID;
2469 reply_force_doserror(req, ERRSRV, ERRbaduid);
2470 END_PROFILE(SMBulogoffX);
2471 return;
2474 session = vuser->session;
2475 vuser = NULL;
2478 * TODO: cancel all outstanding requests on the session
2480 status = smbXsrv_session_logoff(session);
2481 if (!NT_STATUS_IS_OK(status)) {
2482 DEBUG(0, ("reply_ulogoff: "
2483 "smbXsrv_session_logoff() failed: %s\n",
2484 nt_errstr(status)));
2486 * If we hit this case, there is something completely
2487 * wrong, so we better disconnect the transport connection.
2489 END_PROFILE(SMBulogoffX);
2490 exit_server(__location__ ": smbXsrv_session_logoff failed");
2491 return;
2494 TALLOC_FREE(session);
2496 reply_outbuf(req, 2, 0);
2497 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2498 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2500 DEBUG(3, ("ulogoffX vuid=%llu\n",
2501 (unsigned long long)req->vuid));
2503 END_PROFILE(SMBulogoffX);
2504 req->vuid = UID_FIELD_INVALID;
2507 /****************************************************************************
2508 Reply to a mknew or a create.
2509 ****************************************************************************/
2511 void reply_mknew(struct smb_request *req)
2513 connection_struct *conn = req->conn;
2514 struct smb_filename *smb_fname = NULL;
2515 char *fname = NULL;
2516 uint32_t fattr = 0;
2517 struct smb_file_time ft;
2518 files_struct *fsp;
2519 int oplock_request = 0;
2520 NTSTATUS status;
2521 uint32_t access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2522 uint32_t share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2523 uint32_t create_disposition;
2524 uint32_t create_options = 0;
2525 uint32_t ucf_flags;
2526 TALLOC_CTX *ctx = talloc_tos();
2528 START_PROFILE(SMBcreate);
2529 ZERO_STRUCT(ft);
2531 if (req->wct < 3) {
2532 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2533 goto out;
2536 fattr = SVAL(req->vwv+0, 0);
2537 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2539 if (req->cmd == SMBmknew) {
2540 /* We should fail if file exists. */
2541 create_disposition = FILE_CREATE;
2542 } else {
2543 /* Create if file doesn't exist, truncate if it does. */
2544 create_disposition = FILE_OVERWRITE_IF;
2547 /* mtime. */
2548 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2550 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2551 STR_TERMINATE, &status);
2552 if (!NT_STATUS_IS_OK(status)) {
2553 reply_nterror(req, status);
2554 goto out;
2557 ucf_flags = filename_create_ucf_flags(req, create_disposition);
2558 status = filename_convert(ctx,
2559 conn,
2560 fname,
2561 ucf_flags,
2562 NULL,
2563 &smb_fname);
2564 if (!NT_STATUS_IS_OK(status)) {
2565 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2566 reply_botherror(req,
2567 NT_STATUS_PATH_NOT_COVERED,
2568 ERRSRV, ERRbadpath);
2569 goto out;
2571 reply_nterror(req, status);
2572 goto out;
2575 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2576 DEBUG(0,("Attempt to create file (%s) with volid set - "
2577 "please report this\n",
2578 smb_fname_str_dbg(smb_fname)));
2581 status = SMB_VFS_CREATE_FILE(
2582 conn, /* conn */
2583 req, /* req */
2584 0, /* root_dir_fid */
2585 smb_fname, /* fname */
2586 access_mask, /* access_mask */
2587 share_mode, /* share_access */
2588 create_disposition, /* create_disposition*/
2589 create_options, /* create_options */
2590 fattr, /* file_attributes */
2591 oplock_request, /* oplock_request */
2592 NULL, /* lease */
2593 0, /* allocation_size */
2594 0, /* private_flags */
2595 NULL, /* sd */
2596 NULL, /* ea_list */
2597 &fsp, /* result */
2598 NULL, /* pinfo */
2599 NULL, NULL); /* create context */
2601 if (!NT_STATUS_IS_OK(status)) {
2602 if (open_was_deferred(req->xconn, req->mid)) {
2603 /* We have re-scheduled this call. */
2604 goto out;
2606 reply_openerror(req, status);
2607 goto out;
2610 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2611 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2612 if (!NT_STATUS_IS_OK(status)) {
2613 END_PROFILE(SMBcreate);
2614 goto out;
2617 reply_outbuf(req, 1, 0);
2618 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2620 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2621 SCVAL(req->outbuf,smb_flg,
2622 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2625 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2626 SCVAL(req->outbuf,smb_flg,
2627 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2630 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2631 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2632 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2633 (unsigned int)fattr));
2635 out:
2636 TALLOC_FREE(smb_fname);
2637 END_PROFILE(SMBcreate);
2638 return;
2641 /****************************************************************************
2642 Reply to a create temporary file.
2643 ****************************************************************************/
2645 void reply_ctemp(struct smb_request *req)
2647 connection_struct *conn = req->conn;
2648 struct smb_filename *smb_fname = NULL;
2649 char *wire_name = NULL;
2650 char *fname = NULL;
2651 uint32_t fattr;
2652 files_struct *fsp;
2653 int oplock_request;
2654 char *s;
2655 NTSTATUS status;
2656 int i;
2657 uint32_t ucf_flags;
2658 TALLOC_CTX *ctx = talloc_tos();
2660 START_PROFILE(SMBctemp);
2662 if (req->wct < 3) {
2663 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2664 goto out;
2667 fattr = SVAL(req->vwv+0, 0);
2668 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2670 srvstr_get_path_req(ctx, req, &wire_name, (const char *)req->buf+1,
2671 STR_TERMINATE, &status);
2672 if (!NT_STATUS_IS_OK(status)) {
2673 reply_nterror(req, status);
2674 goto out;
2677 for (i = 0; i < 10; i++) {
2678 if (*wire_name) {
2679 fname = talloc_asprintf(ctx,
2680 "%s/TMP%s",
2681 wire_name,
2682 generate_random_str_list(ctx, 5, "0123456789"));
2683 } else {
2684 fname = talloc_asprintf(ctx,
2685 "TMP%s",
2686 generate_random_str_list(ctx, 5, "0123456789"));
2689 if (!fname) {
2690 reply_nterror(req, NT_STATUS_NO_MEMORY);
2691 goto out;
2694 ucf_flags = filename_create_ucf_flags(req, FILE_CREATE);
2695 status = filename_convert(ctx, conn,
2696 fname,
2697 ucf_flags,
2698 NULL,
2699 &smb_fname);
2700 if (!NT_STATUS_IS_OK(status)) {
2701 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2702 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2703 ERRSRV, ERRbadpath);
2704 goto out;
2706 reply_nterror(req, status);
2707 goto out;
2710 /* Create the file. */
2711 status = SMB_VFS_CREATE_FILE(
2712 conn, /* conn */
2713 req, /* req */
2714 0, /* root_dir_fid */
2715 smb_fname, /* fname */
2716 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2717 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2718 FILE_CREATE, /* create_disposition*/
2719 0, /* create_options */
2720 fattr, /* file_attributes */
2721 oplock_request, /* oplock_request */
2722 NULL, /* lease */
2723 0, /* allocation_size */
2724 0, /* private_flags */
2725 NULL, /* sd */
2726 NULL, /* ea_list */
2727 &fsp, /* result */
2728 NULL, /* pinfo */
2729 NULL, NULL); /* create context */
2731 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
2732 TALLOC_FREE(fname);
2733 TALLOC_FREE(smb_fname);
2734 continue;
2737 if (!NT_STATUS_IS_OK(status)) {
2738 if (open_was_deferred(req->xconn, req->mid)) {
2739 /* We have re-scheduled this call. */
2740 goto out;
2742 reply_openerror(req, status);
2743 goto out;
2746 break;
2749 if (i == 10) {
2750 /* Collision after 10 times... */
2751 reply_nterror(req, status);
2752 goto out;
2755 reply_outbuf(req, 1, 0);
2756 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2758 /* the returned filename is relative to the directory */
2759 s = strrchr_m(fsp->fsp_name->base_name, '/');
2760 if (!s) {
2761 s = fsp->fsp_name->base_name;
2762 } else {
2763 s++;
2766 #if 0
2767 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2768 thing in the byte section. JRA */
2769 SSVALS(p, 0, -1); /* what is this? not in spec */
2770 #endif
2771 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2772 == -1) {
2773 reply_nterror(req, NT_STATUS_NO_MEMORY);
2774 goto out;
2777 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2778 SCVAL(req->outbuf, smb_flg,
2779 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2782 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2783 SCVAL(req->outbuf, smb_flg,
2784 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2787 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2788 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2789 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2790 out:
2791 TALLOC_FREE(smb_fname);
2792 TALLOC_FREE(wire_name);
2793 END_PROFILE(SMBctemp);
2794 return;
2797 /*******************************************************************
2798 Check if a user is allowed to rename a file.
2799 ********************************************************************/
2801 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2802 uint16_t dirtype)
2804 if (!CAN_WRITE(conn)) {
2805 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2808 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
2809 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2810 /* Only bother to read the DOS attribute if we might deny the
2811 rename on the grounds of attribute mismatch. */
2812 uint32_t fmode = dos_mode(conn, fsp->fsp_name);
2813 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2814 return NT_STATUS_NO_SUCH_FILE;
2818 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2819 if (fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) {
2820 return NT_STATUS_OK;
2823 /* If no pathnames are open below this
2824 directory, allow the rename. */
2826 if (lp_strict_rename(SNUM(conn))) {
2828 * Strict rename, check open file db.
2830 if (have_file_open_below(fsp->conn, fsp->fsp_name)) {
2831 return NT_STATUS_ACCESS_DENIED;
2833 } else if (file_find_subpath(fsp)) {
2835 * No strict rename, just look in local process.
2837 return NT_STATUS_ACCESS_DENIED;
2839 return NT_STATUS_OK;
2842 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2843 return NT_STATUS_OK;
2846 return NT_STATUS_ACCESS_DENIED;
2849 /*******************************************************************
2850 * unlink a file with all relevant access checks
2851 *******************************************************************/
2853 static NTSTATUS do_unlink(connection_struct *conn,
2854 struct smb_request *req,
2855 struct smb_filename *smb_fname,
2856 uint32_t dirtype)
2858 uint32_t fattr;
2859 files_struct *fsp;
2860 uint32_t dirtype_orig = dirtype;
2861 NTSTATUS status;
2862 int ret;
2863 bool posix_paths = (req != NULL && req->posix_pathnames);
2865 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2866 smb_fname_str_dbg(smb_fname),
2867 dirtype));
2869 if (!CAN_WRITE(conn)) {
2870 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2873 if (posix_paths) {
2874 ret = SMB_VFS_LSTAT(conn, smb_fname);
2875 } else {
2876 ret = SMB_VFS_STAT(conn, smb_fname);
2878 if (ret != 0) {
2879 return map_nt_error_from_unix(errno);
2882 fattr = dos_mode(conn, smb_fname);
2884 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2885 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
2888 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
2889 if (!dirtype) {
2890 return NT_STATUS_NO_SUCH_FILE;
2893 if (!dir_check_ftype(fattr, dirtype)) {
2894 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2895 return NT_STATUS_FILE_IS_A_DIRECTORY;
2897 return NT_STATUS_NO_SUCH_FILE;
2900 if (dirtype_orig & 0x8000) {
2901 /* These will never be set for POSIX. */
2902 return NT_STATUS_NO_SUCH_FILE;
2905 #if 0
2906 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2907 return NT_STATUS_FILE_IS_A_DIRECTORY;
2910 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2911 return NT_STATUS_NO_SUCH_FILE;
2914 if (dirtype & 0xFF00) {
2915 /* These will never be set for POSIX. */
2916 return NT_STATUS_NO_SUCH_FILE;
2919 dirtype &= 0xFF;
2920 if (!dirtype) {
2921 return NT_STATUS_NO_SUCH_FILE;
2924 /* Can't delete a directory. */
2925 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2926 return NT_STATUS_FILE_IS_A_DIRECTORY;
2928 #endif
2930 #if 0 /* JRATEST */
2931 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
2932 return NT_STATUS_OBJECT_NAME_INVALID;
2933 #endif /* JRATEST */
2935 /* On open checks the open itself will check the share mode, so
2936 don't do it here as we'll get it wrong. */
2938 status = SMB_VFS_CREATE_FILE
2939 (conn, /* conn */
2940 req, /* req */
2941 0, /* root_dir_fid */
2942 smb_fname, /* fname */
2943 DELETE_ACCESS, /* access_mask */
2944 FILE_SHARE_NONE, /* share_access */
2945 FILE_OPEN, /* create_disposition*/
2946 FILE_NON_DIRECTORY_FILE, /* create_options */
2947 /* file_attributes */
2948 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2949 FILE_ATTRIBUTE_NORMAL,
2950 0, /* oplock_request */
2951 NULL, /* lease */
2952 0, /* allocation_size */
2953 0, /* private_flags */
2954 NULL, /* sd */
2955 NULL, /* ea_list */
2956 &fsp, /* result */
2957 NULL, /* pinfo */
2958 NULL, NULL); /* create context */
2960 if (!NT_STATUS_IS_OK(status)) {
2961 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2962 nt_errstr(status)));
2963 return status;
2966 status = can_set_delete_on_close(fsp, fattr);
2967 if (!NT_STATUS_IS_OK(status)) {
2968 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2969 "(%s)\n",
2970 smb_fname_str_dbg(smb_fname),
2971 nt_errstr(status)));
2972 close_file(req, fsp, NORMAL_CLOSE);
2973 return status;
2976 /* The set is across all open files on this dev/inode pair. */
2977 if (!set_delete_on_close(fsp, True,
2978 conn->session_info->security_token,
2979 conn->session_info->unix_token)) {
2980 close_file(req, fsp, NORMAL_CLOSE);
2981 return NT_STATUS_ACCESS_DENIED;
2984 return close_file(req, fsp, NORMAL_CLOSE);
2987 /****************************************************************************
2988 The guts of the unlink command, split out so it may be called by the NT SMB
2989 code.
2990 ****************************************************************************/
2992 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2993 uint32_t dirtype, struct smb_filename *smb_fname,
2994 bool has_wild)
2996 char *fname_dir = NULL;
2997 char *fname_mask = NULL;
2998 int count=0;
2999 NTSTATUS status = NT_STATUS_OK;
3000 struct smb_filename *smb_fname_dir = NULL;
3001 TALLOC_CTX *ctx = talloc_tos();
3003 /* Split up the directory from the filename/mask. */
3004 status = split_fname_dir_mask(ctx, smb_fname->base_name,
3005 &fname_dir, &fname_mask);
3006 if (!NT_STATUS_IS_OK(status)) {
3007 goto out;
3011 * We should only check the mangled cache
3012 * here if unix_convert failed. This means
3013 * that the path in 'mask' doesn't exist
3014 * on the file system and so we need to look
3015 * for a possible mangle. This patch from
3016 * Tine Smukavec <valentin.smukavec@hermes.si>.
3019 if (!VALID_STAT(smb_fname->st) &&
3020 mangle_is_mangled(fname_mask, conn->params)) {
3021 char *new_mask = NULL;
3022 mangle_lookup_name_from_8_3(ctx, fname_mask,
3023 &new_mask, conn->params);
3024 if (new_mask) {
3025 TALLOC_FREE(fname_mask);
3026 fname_mask = new_mask;
3030 if (!has_wild) {
3033 * Only one file needs to be unlinked. Append the mask back
3034 * onto the directory.
3036 TALLOC_FREE(smb_fname->base_name);
3037 if (ISDOT(fname_dir)) {
3038 /* Ensure we use canonical names on open. */
3039 smb_fname->base_name = talloc_asprintf(smb_fname,
3040 "%s",
3041 fname_mask);
3042 } else {
3043 smb_fname->base_name = talloc_asprintf(smb_fname,
3044 "%s/%s",
3045 fname_dir,
3046 fname_mask);
3048 if (!smb_fname->base_name) {
3049 status = NT_STATUS_NO_MEMORY;
3050 goto out;
3052 if (dirtype == 0) {
3053 dirtype = FILE_ATTRIBUTE_NORMAL;
3056 status = check_name(conn, smb_fname);
3057 if (!NT_STATUS_IS_OK(status)) {
3058 goto out;
3061 status = do_unlink(conn, req, smb_fname, dirtype);
3062 if (!NT_STATUS_IS_OK(status)) {
3063 goto out;
3066 count++;
3067 } else {
3068 struct smb_Dir *dir_hnd = NULL;
3069 long offset = 0;
3070 const char *dname = NULL;
3071 char *talloced = NULL;
3073 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
3074 status = NT_STATUS_OBJECT_NAME_INVALID;
3075 goto out;
3077 if (dirtype == 0) {
3078 dirtype = FILE_ATTRIBUTE_NORMAL;
3081 if (strequal(fname_mask,"????????.???")) {
3082 TALLOC_FREE(fname_mask);
3083 fname_mask = talloc_strdup(ctx, "*");
3084 if (!fname_mask) {
3085 status = NT_STATUS_NO_MEMORY;
3086 goto out;
3090 smb_fname_dir = synthetic_smb_fname(talloc_tos(),
3091 fname_dir,
3092 NULL,
3093 NULL,
3094 smb_fname->flags);
3095 if (smb_fname_dir == NULL) {
3096 status = NT_STATUS_NO_MEMORY;
3097 goto out;
3100 status = check_name(conn, smb_fname_dir);
3101 if (!NT_STATUS_IS_OK(status)) {
3102 goto out;
3105 dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_dir, fname_mask,
3106 dirtype);
3107 if (dir_hnd == NULL) {
3108 status = map_nt_error_from_unix(errno);
3109 goto out;
3112 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
3113 the pattern matches against the long name, otherwise the short name
3114 We don't implement this yet XXXX
3117 status = NT_STATUS_NO_SUCH_FILE;
3119 while ((dname = ReadDirName(dir_hnd, &offset,
3120 &smb_fname->st, &talloced))) {
3121 TALLOC_CTX *frame = talloc_stackframe();
3123 if (!is_visible_file(conn, fname_dir, dname,
3124 &smb_fname->st, true)) {
3125 TALLOC_FREE(frame);
3126 TALLOC_FREE(talloced);
3127 continue;
3130 /* Quick check for "." and ".." */
3131 if (ISDOT(dname) || ISDOTDOT(dname)) {
3132 TALLOC_FREE(frame);
3133 TALLOC_FREE(talloced);
3134 continue;
3137 if(!mask_match(dname, fname_mask,
3138 conn->case_sensitive)) {
3139 TALLOC_FREE(frame);
3140 TALLOC_FREE(talloced);
3141 continue;
3144 TALLOC_FREE(smb_fname->base_name);
3145 if (ISDOT(fname_dir)) {
3146 /* Ensure we use canonical names on open. */
3147 smb_fname->base_name =
3148 talloc_asprintf(smb_fname, "%s",
3149 dname);
3150 } else {
3151 smb_fname->base_name =
3152 talloc_asprintf(smb_fname, "%s/%s",
3153 fname_dir, dname);
3156 if (!smb_fname->base_name) {
3157 TALLOC_FREE(dir_hnd);
3158 status = NT_STATUS_NO_MEMORY;
3159 TALLOC_FREE(frame);
3160 TALLOC_FREE(talloced);
3161 goto out;
3164 status = check_name(conn, smb_fname);
3165 if (!NT_STATUS_IS_OK(status)) {
3166 TALLOC_FREE(dir_hnd);
3167 TALLOC_FREE(frame);
3168 TALLOC_FREE(talloced);
3169 goto out;
3172 status = do_unlink(conn, req, smb_fname, dirtype);
3173 if (!NT_STATUS_IS_OK(status)) {
3174 TALLOC_FREE(dir_hnd);
3175 TALLOC_FREE(frame);
3176 TALLOC_FREE(talloced);
3177 goto out;
3180 count++;
3181 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
3182 smb_fname->base_name));
3184 TALLOC_FREE(frame);
3185 TALLOC_FREE(talloced);
3187 TALLOC_FREE(dir_hnd);
3190 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
3191 status = map_nt_error_from_unix(errno);
3194 out:
3195 TALLOC_FREE(smb_fname_dir);
3196 TALLOC_FREE(fname_dir);
3197 TALLOC_FREE(fname_mask);
3198 return status;
3201 /****************************************************************************
3202 Reply to a unlink
3203 ****************************************************************************/
3205 void reply_unlink(struct smb_request *req)
3207 connection_struct *conn = req->conn;
3208 char *name = NULL;
3209 struct smb_filename *smb_fname = NULL;
3210 uint32_t dirtype;
3211 NTSTATUS status;
3212 bool path_contains_wcard = False;
3213 uint32_t ucf_flags = UCF_COND_ALLOW_WCARD_LCOMP |
3214 ucf_flags_from_smb_request(req);
3215 TALLOC_CTX *ctx = talloc_tos();
3217 START_PROFILE(SMBunlink);
3219 if (req->wct < 1) {
3220 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3221 goto out;
3224 dirtype = SVAL(req->vwv+0, 0);
3226 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
3227 STR_TERMINATE, &status,
3228 &path_contains_wcard);
3229 if (!NT_STATUS_IS_OK(status)) {
3230 reply_nterror(req, status);
3231 goto out;
3234 status = filename_convert(ctx, conn,
3235 name,
3236 ucf_flags,
3237 &path_contains_wcard,
3238 &smb_fname);
3239 if (!NT_STATUS_IS_OK(status)) {
3240 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
3241 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
3242 ERRSRV, ERRbadpath);
3243 goto out;
3245 reply_nterror(req, status);
3246 goto out;
3249 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
3251 status = unlink_internals(conn, req, dirtype, smb_fname,
3252 path_contains_wcard);
3253 if (!NT_STATUS_IS_OK(status)) {
3254 if (open_was_deferred(req->xconn, req->mid)) {
3255 /* We have re-scheduled this call. */
3256 goto out;
3258 reply_nterror(req, status);
3259 goto out;
3262 reply_outbuf(req, 0, 0);
3263 out:
3264 TALLOC_FREE(smb_fname);
3265 END_PROFILE(SMBunlink);
3266 return;
3269 /****************************************************************************
3270 Fail for readbraw.
3271 ****************************************************************************/
3273 static void fail_readraw(void)
3275 const char *errstr = talloc_asprintf(talloc_tos(),
3276 "FAIL ! reply_readbraw: socket write fail (%s)",
3277 strerror(errno));
3278 if (!errstr) {
3279 errstr = "";
3281 exit_server_cleanly(errstr);
3284 /****************************************************************************
3285 Fake (read/write) sendfile. Returns -1 on read or write fail.
3286 ****************************************************************************/
3288 ssize_t fake_sendfile(struct smbXsrv_connection *xconn, files_struct *fsp,
3289 off_t startpos, size_t nread)
3291 size_t bufsize;
3292 size_t tosend = nread;
3293 char *buf;
3295 if (nread == 0) {
3296 return 0;
3299 bufsize = MIN(nread, 65536);
3301 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
3302 return -1;
3305 while (tosend > 0) {
3306 ssize_t ret;
3307 size_t cur_read;
3309 cur_read = MIN(tosend, bufsize);
3310 ret = read_file(fsp,buf,startpos,cur_read);
3311 if (ret == -1) {
3312 SAFE_FREE(buf);
3313 return -1;
3316 /* If we had a short read, fill with zeros. */
3317 if (ret < cur_read) {
3318 memset(buf + ret, '\0', cur_read - ret);
3321 ret = write_data(xconn->transport.sock, buf, cur_read);
3322 if (ret != cur_read) {
3323 int saved_errno = errno;
3325 * Try and give an error message saying what
3326 * client failed.
3328 DEBUG(0, ("write_data failed for client %s. "
3329 "Error %s\n",
3330 smbXsrv_connection_dbg(xconn),
3331 strerror(saved_errno)));
3332 SAFE_FREE(buf);
3333 errno = saved_errno;
3334 return -1;
3336 tosend -= cur_read;
3337 startpos += cur_read;
3340 SAFE_FREE(buf);
3341 return (ssize_t)nread;
3344 /****************************************************************************
3345 Deal with the case of sendfile reading less bytes from the file than
3346 requested. Fill with zeros (all we can do). Returns 0 on success
3347 ****************************************************************************/
3349 ssize_t sendfile_short_send(struct smbXsrv_connection *xconn,
3350 files_struct *fsp,
3351 ssize_t nread,
3352 size_t headersize,
3353 size_t smb_maxcnt)
3355 #define SHORT_SEND_BUFSIZE 1024
3356 if (nread < headersize) {
3357 DEBUG(0,("sendfile_short_send: sendfile failed to send "
3358 "header for file %s (%s). Terminating\n",
3359 fsp_str_dbg(fsp), strerror(errno)));
3360 return -1;
3363 nread -= headersize;
3365 if (nread < smb_maxcnt) {
3366 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
3367 if (!buf) {
3368 DEBUG(0,("sendfile_short_send: malloc failed "
3369 "for file %s (%s). Terminating\n",
3370 fsp_str_dbg(fsp), strerror(errno)));
3371 return -1;
3374 DEBUG(0,("sendfile_short_send: filling truncated file %s "
3375 "with zeros !\n", fsp_str_dbg(fsp)));
3377 while (nread < smb_maxcnt) {
3379 * We asked for the real file size and told sendfile
3380 * to not go beyond the end of the file. But it can
3381 * happen that in between our fstat call and the
3382 * sendfile call the file was truncated. This is very
3383 * bad because we have already announced the larger
3384 * number of bytes to the client.
3386 * The best we can do now is to send 0-bytes, just as
3387 * a read from a hole in a sparse file would do.
3389 * This should happen rarely enough that I don't care
3390 * about efficiency here :-)
3392 size_t to_write;
3393 ssize_t ret;
3395 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
3396 ret = write_data(xconn->transport.sock, buf, to_write);
3397 if (ret != to_write) {
3398 int saved_errno = errno;
3400 * Try and give an error message saying what
3401 * client failed.
3403 DEBUG(0, ("write_data failed for client %s. "
3404 "Error %s\n",
3405 smbXsrv_connection_dbg(xconn),
3406 strerror(saved_errno)));
3407 errno = saved_errno;
3408 return -1;
3410 nread += to_write;
3412 SAFE_FREE(buf);
3415 return 0;
3418 /****************************************************************************
3419 Return a readbraw error (4 bytes of zero).
3420 ****************************************************************************/
3422 static void reply_readbraw_error(struct smbXsrv_connection *xconn)
3424 char header[4];
3426 SIVAL(header,0,0);
3428 smbd_lock_socket(xconn);
3429 if (write_data(xconn->transport.sock,header,4) != 4) {
3430 int saved_errno = errno;
3432 * Try and give an error message saying what
3433 * client failed.
3435 DEBUG(0, ("write_data failed for client %s. "
3436 "Error %s\n",
3437 smbXsrv_connection_dbg(xconn),
3438 strerror(saved_errno)));
3439 errno = saved_errno;
3441 fail_readraw();
3443 smbd_unlock_socket(xconn);
3446 /****************************************************************************
3447 Use sendfile in readbraw.
3448 ****************************************************************************/
3450 static void send_file_readbraw(connection_struct *conn,
3451 struct smb_request *req,
3452 files_struct *fsp,
3453 off_t startpos,
3454 size_t nread,
3455 ssize_t mincount)
3457 struct smbXsrv_connection *xconn = req->xconn;
3458 char *outbuf = NULL;
3459 ssize_t ret=0;
3462 * We can only use sendfile on a non-chained packet
3463 * but we can use on a non-oplocked file. tridge proved this
3464 * on a train in Germany :-). JRA.
3465 * reply_readbraw has already checked the length.
3468 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3469 (fsp->wcp == NULL) &&
3470 lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
3471 ssize_t sendfile_read = -1;
3472 char header[4];
3473 DATA_BLOB header_blob;
3475 _smb_setlen(header,nread);
3476 header_blob = data_blob_const(header, 4);
3478 sendfile_read = SMB_VFS_SENDFILE(xconn->transport.sock, fsp,
3479 &header_blob, startpos,
3480 nread);
3481 if (sendfile_read == -1) {
3482 /* Returning ENOSYS means no data at all was sent.
3483 * Do this as a normal read. */
3484 if (errno == ENOSYS) {
3485 goto normal_readbraw;
3489 * Special hack for broken Linux with no working sendfile. If we
3490 * return EINTR we sent the header but not the rest of the data.
3491 * Fake this up by doing read/write calls.
3493 if (errno == EINTR) {
3494 /* Ensure we don't do this again. */
3495 set_use_sendfile(SNUM(conn), False);
3496 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3498 if (fake_sendfile(xconn, fsp, startpos, nread) == -1) {
3499 DEBUG(0,("send_file_readbraw: "
3500 "fake_sendfile failed for "
3501 "file %s (%s).\n",
3502 fsp_str_dbg(fsp),
3503 strerror(errno)));
3504 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3506 return;
3509 DEBUG(0,("send_file_readbraw: sendfile failed for "
3510 "file %s (%s). Terminating\n",
3511 fsp_str_dbg(fsp), strerror(errno)));
3512 exit_server_cleanly("send_file_readbraw sendfile failed");
3513 } else if (sendfile_read == 0) {
3515 * Some sendfile implementations return 0 to indicate
3516 * that there was a short read, but nothing was
3517 * actually written to the socket. In this case,
3518 * fallback to the normal read path so the header gets
3519 * the correct byte count.
3521 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3522 "bytes falling back to the normal read: "
3523 "%s\n", fsp_str_dbg(fsp)));
3524 goto normal_readbraw;
3527 /* Deal with possible short send. */
3528 if (sendfile_read != 4+nread) {
3529 ret = sendfile_short_send(xconn, fsp,
3530 sendfile_read, 4, nread);
3531 if (ret == -1) {
3532 fail_readraw();
3535 return;
3538 normal_readbraw:
3540 outbuf = talloc_array(NULL, char, nread+4);
3541 if (!outbuf) {
3542 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3543 (unsigned)(nread+4)));
3544 reply_readbraw_error(xconn);
3545 return;
3548 if (nread > 0) {
3549 ret = read_file(fsp,outbuf+4,startpos,nread);
3550 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3551 if (ret < mincount)
3552 ret = 0;
3553 #else
3554 if (ret < nread)
3555 ret = 0;
3556 #endif
3559 _smb_setlen(outbuf,ret);
3560 if (write_data(xconn->transport.sock, outbuf, 4+ret) != 4+ret) {
3561 int saved_errno = errno;
3563 * Try and give an error message saying what
3564 * client failed.
3566 DEBUG(0, ("write_data failed for client %s. Error %s\n",
3567 smbXsrv_connection_dbg(xconn),
3568 strerror(saved_errno)));
3569 errno = saved_errno;
3571 fail_readraw();
3574 TALLOC_FREE(outbuf);
3577 /****************************************************************************
3578 Reply to a readbraw (core+ protocol).
3579 ****************************************************************************/
3581 void reply_readbraw(struct smb_request *req)
3583 connection_struct *conn = req->conn;
3584 struct smbXsrv_connection *xconn = req->xconn;
3585 ssize_t maxcount,mincount;
3586 size_t nread = 0;
3587 off_t startpos;
3588 files_struct *fsp;
3589 struct lock_struct lock;
3590 off_t size = 0;
3592 START_PROFILE(SMBreadbraw);
3594 if (srv_is_signing_active(xconn) || req->encrypted) {
3595 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3596 "raw reads/writes are disallowed.");
3599 if (req->wct < 8) {
3600 reply_readbraw_error(xconn);
3601 END_PROFILE(SMBreadbraw);
3602 return;
3605 if (xconn->smb1.echo_handler.trusted_fde) {
3606 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3607 "'async smb echo handler = yes'\n"));
3608 reply_readbraw_error(xconn);
3609 END_PROFILE(SMBreadbraw);
3610 return;
3614 * Special check if an oplock break has been issued
3615 * and the readraw request croses on the wire, we must
3616 * return a zero length response here.
3619 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3622 * We have to do a check_fsp by hand here, as
3623 * we must always return 4 zero bytes on error,
3624 * not a NTSTATUS.
3627 if (!fsp || !conn || conn != fsp->conn ||
3628 req->vuid != fsp->vuid ||
3629 fsp->is_directory || fsp->fh->fd == -1) {
3631 * fsp could be NULL here so use the value from the packet. JRA.
3633 DEBUG(3,("reply_readbraw: fnum %d not valid "
3634 "- cache prime?\n",
3635 (int)SVAL(req->vwv+0, 0)));
3636 reply_readbraw_error(xconn);
3637 END_PROFILE(SMBreadbraw);
3638 return;
3641 /* Do a "by hand" version of CHECK_READ. */
3642 if (!(fsp->can_read ||
3643 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3644 (fsp->access_mask & FILE_EXECUTE)))) {
3645 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3646 (int)SVAL(req->vwv+0, 0)));
3647 reply_readbraw_error(xconn);
3648 END_PROFILE(SMBreadbraw);
3649 return;
3652 flush_write_cache(fsp, SAMBA_READRAW_FLUSH);
3654 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3655 if(req->wct == 10) {
3657 * This is a large offset (64 bit) read.
3660 startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32);
3662 if(startpos < 0) {
3663 DEBUG(0,("reply_readbraw: negative 64 bit "
3664 "readraw offset (%.0f) !\n",
3665 (double)startpos ));
3666 reply_readbraw_error(xconn);
3667 END_PROFILE(SMBreadbraw);
3668 return;
3672 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3673 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3675 /* ensure we don't overrun the packet size */
3676 maxcount = MIN(65535,maxcount);
3678 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3679 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3680 &lock);
3682 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
3683 reply_readbraw_error(xconn);
3684 END_PROFILE(SMBreadbraw);
3685 return;
3688 if (fsp_stat(fsp) == 0) {
3689 size = fsp->fsp_name->st.st_ex_size;
3692 if (startpos >= size) {
3693 nread = 0;
3694 } else {
3695 nread = MIN(maxcount,(size - startpos));
3698 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3699 if (nread < mincount)
3700 nread = 0;
3701 #endif
3703 DEBUG( 3, ( "reply_readbraw: %s start=%.0f max=%lu "
3704 "min=%lu nread=%lu\n",
3705 fsp_fnum_dbg(fsp), (double)startpos,
3706 (unsigned long)maxcount,
3707 (unsigned long)mincount,
3708 (unsigned long)nread ) );
3710 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3712 DEBUG(5,("reply_readbraw finished\n"));
3714 END_PROFILE(SMBreadbraw);
3715 return;
3718 #undef DBGC_CLASS
3719 #define DBGC_CLASS DBGC_LOCKING
3721 /****************************************************************************
3722 Reply to a lockread (core+ protocol).
3723 ****************************************************************************/
3725 void reply_lockread(struct smb_request *req)
3727 connection_struct *conn = req->conn;
3728 ssize_t nread = -1;
3729 char *data;
3730 off_t startpos;
3731 size_t numtoread;
3732 size_t maxtoread;
3733 NTSTATUS status;
3734 files_struct *fsp;
3735 struct byte_range_lock *br_lck = NULL;
3736 char *p = NULL;
3737 struct smbXsrv_connection *xconn = req->xconn;
3739 START_PROFILE(SMBlockread);
3741 if (req->wct < 5) {
3742 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3743 END_PROFILE(SMBlockread);
3744 return;
3747 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3749 if (!check_fsp(conn, req, fsp)) {
3750 END_PROFILE(SMBlockread);
3751 return;
3754 if (!CHECK_READ(fsp,req)) {
3755 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3756 END_PROFILE(SMBlockread);
3757 return;
3760 numtoread = SVAL(req->vwv+1, 0);
3761 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3764 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3765 * protocol request that predates the read/write lock concept.
3766 * Thus instead of asking for a read lock here we need to ask
3767 * for a write lock. JRA.
3768 * Note that the requested lock size is unaffected by max_send.
3771 br_lck = do_lock(req->sconn->msg_ctx,
3772 fsp,
3773 (uint64_t)req->smbpid,
3774 (uint64_t)numtoread,
3775 (uint64_t)startpos,
3776 WRITE_LOCK,
3777 WINDOWS_LOCK,
3778 False, /* Non-blocking lock. */
3779 &status,
3780 NULL);
3781 TALLOC_FREE(br_lck);
3783 if (NT_STATUS_V(status)) {
3784 reply_nterror(req, status);
3785 END_PROFILE(SMBlockread);
3786 return;
3790 * However the requested READ size IS affected by max_send. Insanity.... JRA.
3792 maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
3794 if (numtoread > maxtoread) {
3795 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u/%u). \
3796 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3797 (unsigned int)numtoread, (unsigned int)maxtoread,
3798 (unsigned int)xconn->smb1.sessions.max_send));
3799 numtoread = maxtoread;
3802 reply_outbuf(req, 5, numtoread + 3);
3804 data = smb_buf(req->outbuf) + 3;
3806 nread = read_file(fsp,data,startpos,numtoread);
3808 if (nread < 0) {
3809 reply_nterror(req, map_nt_error_from_unix(errno));
3810 END_PROFILE(SMBlockread);
3811 return;
3814 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3816 SSVAL(req->outbuf,smb_vwv0,nread);
3817 SSVAL(req->outbuf,smb_vwv5,nread+3);
3818 p = smb_buf(req->outbuf);
3819 SCVAL(p,0,0); /* pad byte. */
3820 SSVAL(p,1,nread);
3822 DEBUG(3,("lockread %s num=%d nread=%d\n",
3823 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3825 END_PROFILE(SMBlockread);
3826 return;
3829 #undef DBGC_CLASS
3830 #define DBGC_CLASS DBGC_ALL
3832 /****************************************************************************
3833 Reply to a read.
3834 ****************************************************************************/
3836 void reply_read(struct smb_request *req)
3838 connection_struct *conn = req->conn;
3839 size_t numtoread;
3840 size_t maxtoread;
3841 ssize_t nread = 0;
3842 char *data;
3843 off_t startpos;
3844 files_struct *fsp;
3845 struct lock_struct lock;
3846 struct smbXsrv_connection *xconn = req->xconn;
3848 START_PROFILE(SMBread);
3850 if (req->wct < 3) {
3851 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3852 END_PROFILE(SMBread);
3853 return;
3856 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3858 if (!check_fsp(conn, req, fsp)) {
3859 END_PROFILE(SMBread);
3860 return;
3863 if (!CHECK_READ(fsp,req)) {
3864 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3865 END_PROFILE(SMBread);
3866 return;
3869 numtoread = SVAL(req->vwv+1, 0);
3870 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3873 * The requested read size cannot be greater than max_send. JRA.
3875 maxtoread = xconn->smb1.sessions.max_send - (smb_size + 5*2 + 3);
3877 if (numtoread > maxtoread) {
3878 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u/%u). \
3879 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3880 (unsigned int)numtoread, (unsigned int)maxtoread,
3881 (unsigned int)xconn->smb1.sessions.max_send));
3882 numtoread = maxtoread;
3885 reply_outbuf(req, 5, numtoread+3);
3887 data = smb_buf(req->outbuf) + 3;
3889 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3890 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3891 &lock);
3893 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
3894 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3895 END_PROFILE(SMBread);
3896 return;
3899 if (numtoread > 0)
3900 nread = read_file(fsp,data,startpos,numtoread);
3902 if (nread < 0) {
3903 reply_nterror(req, map_nt_error_from_unix(errno));
3904 goto out;
3907 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3909 SSVAL(req->outbuf,smb_vwv0,nread);
3910 SSVAL(req->outbuf,smb_vwv5,nread+3);
3911 SCVAL(smb_buf(req->outbuf),0,1);
3912 SSVAL(smb_buf(req->outbuf),1,nread);
3914 DEBUG(3, ("read %s num=%d nread=%d\n",
3915 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3917 out:
3918 END_PROFILE(SMBread);
3919 return;
3922 /****************************************************************************
3923 Setup readX header.
3924 ****************************************************************************/
3926 int setup_readX_header(char *outbuf, size_t smb_maxcnt)
3928 int outsize;
3930 outsize = srv_set_message(outbuf,12,smb_maxcnt + 1 /* padding byte */,
3931 False);
3933 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3935 SCVAL(outbuf,smb_vwv0,0xFF);
3936 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3937 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3938 SSVAL(outbuf,smb_vwv6,
3939 (smb_wct - 4) /* offset from smb header to wct */
3940 + 1 /* the wct field */
3941 + 12 * sizeof(uint16_t) /* vwv */
3942 + 2 /* the buflen field */
3943 + 1); /* padding byte */
3944 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3945 SCVAL(smb_buf(outbuf), 0, 0); /* padding byte */
3946 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3947 _smb_setlen_large(outbuf,
3948 smb_size + 12*2 + smb_maxcnt - 4 + 1 /* pad */);
3949 return outsize;
3952 /****************************************************************************
3953 Reply to a read and X - possibly using sendfile.
3954 ****************************************************************************/
3956 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3957 files_struct *fsp, off_t startpos,
3958 size_t smb_maxcnt)
3960 struct smbXsrv_connection *xconn = req->xconn;
3961 ssize_t nread = -1;
3962 struct lock_struct lock;
3963 int saved_errno = 0;
3965 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3966 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3967 &lock);
3969 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
3970 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3971 return;
3975 * We can only use sendfile on a non-chained packet
3976 * but we can use on a non-oplocked file. tridge proved this
3977 * on a train in Germany :-). JRA.
3980 if (!req_is_in_chain(req) &&
3981 !req->encrypted &&
3982 (fsp->base_fsp == NULL) &&
3983 (fsp->wcp == NULL) &&
3984 lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
3985 uint8_t headerbuf[smb_size + 12 * 2 + 1 /* padding byte */];
3986 DATA_BLOB header;
3988 if(fsp_stat(fsp) == -1) {
3989 reply_nterror(req, map_nt_error_from_unix(errno));
3990 goto out;
3993 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3994 (startpos > fsp->fsp_name->st.st_ex_size) ||
3995 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3997 * We already know that we would do a short read, so don't
3998 * try the sendfile() path.
4000 goto nosendfile_read;
4004 * Set up the packet header before send. We
4005 * assume here the sendfile will work (get the
4006 * correct amount of data).
4009 header = data_blob_const(headerbuf, sizeof(headerbuf));
4011 construct_reply_common_req(req, (char *)headerbuf);
4012 setup_readX_header((char *)headerbuf, smb_maxcnt);
4014 nread = SMB_VFS_SENDFILE(xconn->transport.sock, fsp, &header,
4015 startpos, smb_maxcnt);
4016 if (nread == -1) {
4017 saved_errno = errno;
4019 /* Returning ENOSYS means no data at all was sent.
4020 Do this as a normal read. */
4021 if (errno == ENOSYS) {
4022 goto normal_read;
4026 * Special hack for broken Linux with no working sendfile. If we
4027 * return EINTR we sent the header but not the rest of the data.
4028 * Fake this up by doing read/write calls.
4031 if (errno == EINTR) {
4032 /* Ensure we don't do this again. */
4033 set_use_sendfile(SNUM(conn), False);
4034 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
4035 nread = fake_sendfile(xconn, fsp, startpos,
4036 smb_maxcnt);
4037 if (nread == -1) {
4038 saved_errno = errno;
4039 DEBUG(0,("send_file_readX: "
4040 "fake_sendfile failed for "
4041 "file %s (%s) for client %s. "
4042 "Terminating\n",
4043 fsp_str_dbg(fsp),
4044 smbXsrv_connection_dbg(xconn),
4045 strerror(saved_errno)));
4046 errno = saved_errno;
4047 exit_server_cleanly("send_file_readX: fake_sendfile failed");
4049 DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
4050 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4051 /* No outbuf here means successful sendfile. */
4052 goto out;
4055 DEBUG(0,("send_file_readX: sendfile failed for file "
4056 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
4057 strerror(errno)));
4058 exit_server_cleanly("send_file_readX sendfile failed");
4059 } else if (nread == 0) {
4061 * Some sendfile implementations return 0 to indicate
4062 * that there was a short read, but nothing was
4063 * actually written to the socket. In this case,
4064 * fallback to the normal read path so the header gets
4065 * the correct byte count.
4067 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
4068 "falling back to the normal read: %s\n",
4069 fsp_str_dbg(fsp)));
4070 goto normal_read;
4073 DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n",
4074 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4076 /* Deal with possible short send. */
4077 if (nread != smb_maxcnt + sizeof(headerbuf)) {
4078 ssize_t ret;
4080 ret = sendfile_short_send(xconn, fsp, nread,
4081 sizeof(headerbuf), smb_maxcnt);
4082 if (ret == -1) {
4083 const char *r;
4084 r = "send_file_readX: sendfile_short_send failed";
4085 DEBUG(0,("%s for file %s (%s).\n",
4086 r, fsp_str_dbg(fsp), strerror(errno)));
4087 exit_server_cleanly(r);
4090 /* No outbuf here means successful sendfile. */
4091 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
4092 SMB_PERFCOUNT_END(&req->pcd);
4093 goto out;
4096 normal_read:
4098 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
4099 uint8_t headerbuf[smb_size + 2*12 + 1 /* padding byte */];
4100 ssize_t ret;
4102 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
4103 (startpos > fsp->fsp_name->st.st_ex_size) ||
4104 (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
4106 * We already know that we would do a short
4107 * read, so don't try the sendfile() path.
4109 goto nosendfile_read;
4112 construct_reply_common_req(req, (char *)headerbuf);
4113 setup_readX_header((char *)headerbuf, smb_maxcnt);
4115 /* Send out the header. */
4116 ret = write_data(xconn->transport.sock, (char *)headerbuf,
4117 sizeof(headerbuf));
4118 if (ret != sizeof(headerbuf)) {
4119 saved_errno = errno;
4121 * Try and give an error message saying what
4122 * client failed.
4124 DEBUG(0,("send_file_readX: write_data failed for file "
4125 "%s (%s) for client %s. Terminating\n",
4126 fsp_str_dbg(fsp),
4127 smbXsrv_connection_dbg(xconn),
4128 strerror(saved_errno)));
4129 errno = saved_errno;
4130 exit_server_cleanly("send_file_readX sendfile failed");
4132 nread = fake_sendfile(xconn, fsp, startpos, smb_maxcnt);
4133 if (nread == -1) {
4134 saved_errno = errno;
4135 DEBUG(0,("send_file_readX: fake_sendfile failed for file "
4136 "%s (%s) for client %s. Terminating\n",
4137 fsp_str_dbg(fsp),
4138 smbXsrv_connection_dbg(xconn),
4139 strerror(saved_errno)));
4140 errno = saved_errno;
4141 exit_server_cleanly("send_file_readX: fake_sendfile failed");
4143 goto out;
4146 nosendfile_read:
4148 reply_outbuf(req, 12, smb_maxcnt + 1 /* padding byte */);
4149 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
4150 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
4152 nread = read_file(fsp, smb_buf(req->outbuf) + 1 /* padding byte */,
4153 startpos, smb_maxcnt);
4154 saved_errno = errno;
4156 if (nread < 0) {
4157 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4158 return;
4161 setup_readX_header((char *)req->outbuf, nread);
4163 DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
4164 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
4165 return;
4167 out:
4168 TALLOC_FREE(req->outbuf);
4169 return;
4172 /****************************************************************************
4173 Work out how much space we have for a read return.
4174 ****************************************************************************/
4176 static size_t calc_max_read_pdu(const struct smb_request *req)
4178 struct smbXsrv_connection *xconn = req->xconn;
4180 if (xconn->protocol < PROTOCOL_NT1) {
4181 return xconn->smb1.sessions.max_send;
4184 if (!lp_large_readwrite()) {
4185 return xconn->smb1.sessions.max_send;
4188 if (req_is_in_chain(req)) {
4189 return xconn->smb1.sessions.max_send;
4192 if (req->encrypted) {
4194 * Don't take encrypted traffic up to the
4195 * limit. There are padding considerations
4196 * that make that tricky.
4198 return xconn->smb1.sessions.max_send;
4201 if (srv_is_signing_active(xconn)) {
4202 return 0x1FFFF;
4205 if (!lp_unix_extensions()) {
4206 return 0x1FFFF;
4210 * We can do ultra-large POSIX reads.
4212 return 0xFFFFFF;
4215 /****************************************************************************
4216 Calculate how big a read can be. Copes with all clients. It's always
4217 safe to return a short read - Windows does this.
4218 ****************************************************************************/
4220 static size_t calc_read_size(const struct smb_request *req,
4221 size_t upper_size,
4222 size_t lower_size)
4224 struct smbXsrv_connection *xconn = req->xconn;
4225 size_t max_pdu = calc_max_read_pdu(req);
4226 size_t total_size = 0;
4227 size_t hdr_len = MIN_SMB_SIZE + VWV(12);
4228 size_t max_len = max_pdu - hdr_len - 1 /* padding byte */;
4231 * Windows explicitly ignores upper size of 0xFFFF.
4232 * See [MS-SMB].pdf <26> Section 2.2.4.2.1:
4233 * We must do the same as these will never fit even in
4234 * an extended size NetBIOS packet.
4236 if (upper_size == 0xFFFF) {
4237 upper_size = 0;
4240 if (xconn->protocol < PROTOCOL_NT1) {
4241 upper_size = 0;
4244 total_size = ((upper_size<<16) | lower_size);
4247 * LARGE_READX test shows it's always safe to return
4248 * a short read. Windows does so.
4250 return MIN(total_size, max_len);
4253 /****************************************************************************
4254 Reply to a read and X.
4255 ****************************************************************************/
4257 void reply_read_and_X(struct smb_request *req)
4259 connection_struct *conn = req->conn;
4260 files_struct *fsp;
4261 off_t startpos;
4262 size_t smb_maxcnt;
4263 size_t upper_size;
4264 bool big_readX = False;
4265 #if 0
4266 size_t smb_mincnt = SVAL(req->vwv+6, 0);
4267 #endif
4269 START_PROFILE(SMBreadX);
4271 if ((req->wct != 10) && (req->wct != 12)) {
4272 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4273 return;
4276 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4277 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4278 smb_maxcnt = SVAL(req->vwv+5, 0);
4280 /* If it's an IPC, pass off the pipe handler. */
4281 if (IS_IPC(conn)) {
4282 reply_pipe_read_and_X(req);
4283 END_PROFILE(SMBreadX);
4284 return;
4287 if (!check_fsp(conn, req, fsp)) {
4288 END_PROFILE(SMBreadX);
4289 return;
4292 if (!CHECK_READ(fsp,req)) {
4293 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4294 END_PROFILE(SMBreadX);
4295 return;
4298 upper_size = SVAL(req->vwv+7, 0);
4299 smb_maxcnt = calc_read_size(req, upper_size, smb_maxcnt);
4300 if (smb_maxcnt > (0x1FFFF - (MIN_SMB_SIZE + VWV(12)))) {
4302 * This is a heuristic to avoid keeping large
4303 * outgoing buffers around over long-lived aio
4304 * requests.
4306 big_readX = True;
4309 if (req->wct == 12) {
4311 * This is a large offset (64 bit) read.
4313 startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
4317 if (!big_readX) {
4318 NTSTATUS status = schedule_aio_read_and_X(conn,
4319 req,
4320 fsp,
4321 startpos,
4322 smb_maxcnt);
4323 if (NT_STATUS_IS_OK(status)) {
4324 /* Read scheduled - we're done. */
4325 goto out;
4327 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4328 /* Real error - report to client. */
4329 END_PROFILE(SMBreadX);
4330 reply_nterror(req, status);
4331 return;
4333 /* NT_STATUS_RETRY - fall back to sync read. */
4336 smbd_lock_socket(req->xconn);
4337 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
4338 smbd_unlock_socket(req->xconn);
4340 out:
4341 END_PROFILE(SMBreadX);
4342 return;
4345 /****************************************************************************
4346 Error replies to writebraw must have smb_wct == 1. Fix this up.
4347 ****************************************************************************/
4349 void error_to_writebrawerr(struct smb_request *req)
4351 uint8_t *old_outbuf = req->outbuf;
4353 reply_outbuf(req, 1, 0);
4355 memcpy(req->outbuf, old_outbuf, smb_size);
4356 TALLOC_FREE(old_outbuf);
4359 /****************************************************************************
4360 Read 4 bytes of a smb packet and return the smb length of the packet.
4361 Store the result in the buffer. This version of the function will
4362 never return a session keepalive (length of zero).
4363 Timeout is in milliseconds.
4364 ****************************************************************************/
4366 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
4367 size_t *len)
4369 uint8_t msgtype = NBSSkeepalive;
4371 while (msgtype == NBSSkeepalive) {
4372 NTSTATUS status;
4374 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
4375 len);
4376 if (!NT_STATUS_IS_OK(status)) {
4377 char addr[INET6_ADDRSTRLEN];
4378 /* Try and give an error message
4379 * saying what client failed. */
4380 DEBUG(0, ("read_fd_with_timeout failed for "
4381 "client %s read error = %s.\n",
4382 get_peer_addr(fd,addr,sizeof(addr)),
4383 nt_errstr(status)));
4384 return status;
4387 msgtype = CVAL(inbuf, 0);
4390 DEBUG(10,("read_smb_length: got smb length of %lu\n",
4391 (unsigned long)len));
4393 return NT_STATUS_OK;
4396 /****************************************************************************
4397 Reply to a writebraw (core+ or LANMAN1.0 protocol).
4398 ****************************************************************************/
4400 void reply_writebraw(struct smb_request *req)
4402 connection_struct *conn = req->conn;
4403 struct smbXsrv_connection *xconn = req->xconn;
4404 char *buf = NULL;
4405 ssize_t nwritten=0;
4406 ssize_t total_written=0;
4407 size_t numtowrite=0;
4408 size_t tcount;
4409 off_t startpos;
4410 const char *data=NULL;
4411 bool write_through;
4412 files_struct *fsp;
4413 struct lock_struct lock;
4414 NTSTATUS status;
4416 START_PROFILE(SMBwritebraw);
4419 * If we ever reply with an error, it must have the SMB command
4420 * type of SMBwritec, not SMBwriteBraw, as this tells the client
4421 * we're finished.
4423 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
4425 if (srv_is_signing_active(xconn)) {
4426 END_PROFILE(SMBwritebraw);
4427 exit_server_cleanly("reply_writebraw: SMB signing is active - "
4428 "raw reads/writes are disallowed.");
4431 if (req->wct < 12) {
4432 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4433 error_to_writebrawerr(req);
4434 END_PROFILE(SMBwritebraw);
4435 return;
4438 if (xconn->smb1.echo_handler.trusted_fde) {
4439 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
4440 "'async smb echo handler = yes'\n"));
4441 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
4442 error_to_writebrawerr(req);
4443 END_PROFILE(SMBwritebraw);
4444 return;
4447 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4448 if (!check_fsp(conn, req, fsp)) {
4449 error_to_writebrawerr(req);
4450 END_PROFILE(SMBwritebraw);
4451 return;
4454 if (!CHECK_WRITE(fsp)) {
4455 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4456 error_to_writebrawerr(req);
4457 END_PROFILE(SMBwritebraw);
4458 return;
4461 tcount = IVAL(req->vwv+1, 0);
4462 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4463 write_through = BITSETW(req->vwv+7,0);
4465 /* We have to deal with slightly different formats depending
4466 on whether we are using the core+ or lanman1.0 protocol */
4468 if(get_Protocol() <= PROTOCOL_COREPLUS) {
4469 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
4470 data = smb_buf_const(req->inbuf);
4471 } else {
4472 numtowrite = SVAL(req->vwv+10, 0);
4473 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
4476 /* Ensure we don't write bytes past the end of this packet. */
4477 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
4478 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4479 error_to_writebrawerr(req);
4480 END_PROFILE(SMBwritebraw);
4481 return;
4484 if (!fsp->print_file) {
4485 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4486 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4487 &lock);
4489 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4490 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4491 error_to_writebrawerr(req);
4492 END_PROFILE(SMBwritebraw);
4493 return;
4497 if (numtowrite>0) {
4498 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4501 DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d "
4502 "wrote=%d sync=%d\n",
4503 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4504 (int)nwritten, (int)write_through));
4506 if (nwritten < (ssize_t)numtowrite) {
4507 reply_nterror(req, NT_STATUS_DISK_FULL);
4508 error_to_writebrawerr(req);
4509 goto out;
4512 total_written = nwritten;
4514 /* Allocate a buffer of 64k + length. */
4515 buf = talloc_array(NULL, char, 65540);
4516 if (!buf) {
4517 reply_nterror(req, NT_STATUS_NO_MEMORY);
4518 error_to_writebrawerr(req);
4519 goto out;
4522 /* Return a SMBwritebraw message to the redirector to tell
4523 * it to send more bytes */
4525 memcpy(buf, req->inbuf, smb_size);
4526 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4527 SCVAL(buf,smb_com,SMBwritebraw);
4528 SSVALS(buf,smb_vwv0,0xFFFF);
4529 show_msg(buf);
4530 if (!srv_send_smb(req->xconn,
4531 buf,
4532 false, 0, /* no signing */
4533 IS_CONN_ENCRYPTED(conn),
4534 &req->pcd)) {
4535 exit_server_cleanly("reply_writebraw: srv_send_smb "
4536 "failed.");
4539 /* Now read the raw data into the buffer and write it */
4540 status = read_smb_length(xconn->transport.sock, buf, SMB_SECONDARY_WAIT,
4541 &numtowrite);
4542 if (!NT_STATUS_IS_OK(status)) {
4543 exit_server_cleanly("secondary writebraw failed");
4546 /* Set up outbuf to return the correct size */
4547 reply_outbuf(req, 1, 0);
4549 if (numtowrite != 0) {
4551 if (numtowrite > 0xFFFF) {
4552 DEBUG(0,("reply_writebraw: Oversize secondary write "
4553 "raw requested (%u). Terminating\n",
4554 (unsigned int)numtowrite ));
4555 exit_server_cleanly("secondary writebraw failed");
4558 if (tcount > nwritten+numtowrite) {
4559 DEBUG(3,("reply_writebraw: Client overestimated the "
4560 "write %d %d %d\n",
4561 (int)tcount,(int)nwritten,(int)numtowrite));
4564 status = read_data_ntstatus(xconn->transport.sock, buf+4,
4565 numtowrite);
4567 if (!NT_STATUS_IS_OK(status)) {
4568 /* Try and give an error message
4569 * saying what client failed. */
4570 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4571 "raw read failed (%s) for client %s. "
4572 "Terminating\n", nt_errstr(status),
4573 smbXsrv_connection_dbg(xconn)));
4574 exit_server_cleanly("secondary writebraw failed");
4577 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4578 if (nwritten == -1) {
4579 TALLOC_FREE(buf);
4580 reply_nterror(req, map_nt_error_from_unix(errno));
4581 error_to_writebrawerr(req);
4582 goto out;
4585 if (nwritten < (ssize_t)numtowrite) {
4586 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4587 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4590 if (nwritten > 0) {
4591 total_written += nwritten;
4595 TALLOC_FREE(buf);
4596 SSVAL(req->outbuf,smb_vwv0,total_written);
4598 status = sync_file(conn, fsp, write_through);
4599 if (!NT_STATUS_IS_OK(status)) {
4600 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4601 fsp_str_dbg(fsp), nt_errstr(status)));
4602 reply_nterror(req, status);
4603 error_to_writebrawerr(req);
4604 goto out;
4607 DEBUG(3,("reply_writebraw: secondart write %s start=%.0f num=%d "
4608 "wrote=%d\n",
4609 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4610 (int)total_written));
4612 /* We won't return a status if write through is not selected - this
4613 * follows what WfWg does */
4614 END_PROFILE(SMBwritebraw);
4616 if (!write_through && total_written==tcount) {
4618 #if RABBIT_PELLET_FIX
4620 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4621 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4622 * JRA.
4624 if (!send_keepalive(xconn->transport.sock)) {
4625 exit_server_cleanly("reply_writebraw: send of "
4626 "keepalive failed");
4628 #endif
4629 TALLOC_FREE(req->outbuf);
4631 return;
4633 out:
4634 END_PROFILE(SMBwritebraw);
4635 return;
4638 #undef DBGC_CLASS
4639 #define DBGC_CLASS DBGC_LOCKING
4641 /****************************************************************************
4642 Reply to a writeunlock (core+).
4643 ****************************************************************************/
4645 void reply_writeunlock(struct smb_request *req)
4647 connection_struct *conn = req->conn;
4648 ssize_t nwritten = -1;
4649 size_t numtowrite;
4650 off_t startpos;
4651 const char *data;
4652 NTSTATUS status = NT_STATUS_OK;
4653 files_struct *fsp;
4654 struct lock_struct lock;
4655 int saved_errno = 0;
4657 START_PROFILE(SMBwriteunlock);
4659 if (req->wct < 5) {
4660 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4661 END_PROFILE(SMBwriteunlock);
4662 return;
4665 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4667 if (!check_fsp(conn, req, fsp)) {
4668 END_PROFILE(SMBwriteunlock);
4669 return;
4672 if (!CHECK_WRITE(fsp)) {
4673 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4674 END_PROFILE(SMBwriteunlock);
4675 return;
4678 numtowrite = SVAL(req->vwv+1, 0);
4679 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4680 data = (const char *)req->buf + 3;
4682 if (!fsp->print_file && numtowrite > 0) {
4683 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4684 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4685 &lock);
4687 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4688 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4689 END_PROFILE(SMBwriteunlock);
4690 return;
4694 /* The special X/Open SMB protocol handling of
4695 zero length writes is *NOT* done for
4696 this call */
4697 if(numtowrite == 0) {
4698 nwritten = 0;
4699 } else {
4700 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4701 saved_errno = errno;
4704 status = sync_file(conn, fsp, False /* write through */);
4705 if (!NT_STATUS_IS_OK(status)) {
4706 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4707 fsp_str_dbg(fsp), nt_errstr(status)));
4708 reply_nterror(req, status);
4709 goto out;
4712 if(nwritten < 0) {
4713 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4714 goto out;
4717 if((nwritten < numtowrite) && (numtowrite != 0)) {
4718 reply_nterror(req, NT_STATUS_DISK_FULL);
4719 goto out;
4722 if (numtowrite && !fsp->print_file) {
4723 status = do_unlock(req->sconn->msg_ctx,
4724 fsp,
4725 (uint64_t)req->smbpid,
4726 (uint64_t)numtowrite,
4727 (uint64_t)startpos,
4728 WINDOWS_LOCK);
4730 if (NT_STATUS_V(status)) {
4731 reply_nterror(req, status);
4732 goto out;
4736 reply_outbuf(req, 1, 0);
4738 SSVAL(req->outbuf,smb_vwv0,nwritten);
4740 DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
4741 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4743 out:
4744 END_PROFILE(SMBwriteunlock);
4745 return;
4748 #undef DBGC_CLASS
4749 #define DBGC_CLASS DBGC_ALL
4751 /****************************************************************************
4752 Reply to a write.
4753 ****************************************************************************/
4755 void reply_write(struct smb_request *req)
4757 connection_struct *conn = req->conn;
4758 size_t numtowrite;
4759 ssize_t nwritten = -1;
4760 off_t startpos;
4761 const char *data;
4762 files_struct *fsp;
4763 struct lock_struct lock;
4764 NTSTATUS status;
4765 int saved_errno = 0;
4767 START_PROFILE(SMBwrite);
4769 if (req->wct < 5) {
4770 END_PROFILE(SMBwrite);
4771 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4772 return;
4775 /* If it's an IPC, pass off the pipe handler. */
4776 if (IS_IPC(conn)) {
4777 reply_pipe_write(req);
4778 END_PROFILE(SMBwrite);
4779 return;
4782 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4784 if (!check_fsp(conn, req, fsp)) {
4785 END_PROFILE(SMBwrite);
4786 return;
4789 if (!CHECK_WRITE(fsp)) {
4790 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4791 END_PROFILE(SMBwrite);
4792 return;
4795 numtowrite = SVAL(req->vwv+1, 0);
4796 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4797 data = (const char *)req->buf + 3;
4799 if (!fsp->print_file) {
4800 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4801 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4802 &lock);
4804 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
4805 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4806 END_PROFILE(SMBwrite);
4807 return;
4812 * X/Open SMB protocol says that if smb_vwv1 is
4813 * zero then the file size should be extended or
4814 * truncated to the size given in smb_vwv[2-3].
4817 if(numtowrite == 0) {
4819 * This is actually an allocate call, and set EOF. JRA.
4821 nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
4822 if (nwritten < 0) {
4823 reply_nterror(req, NT_STATUS_DISK_FULL);
4824 goto out;
4826 nwritten = vfs_set_filelen(fsp, (off_t)startpos);
4827 if (nwritten < 0) {
4828 reply_nterror(req, NT_STATUS_DISK_FULL);
4829 goto out;
4831 trigger_write_time_update_immediate(fsp);
4832 } else {
4833 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4836 status = sync_file(conn, fsp, False);
4837 if (!NT_STATUS_IS_OK(status)) {
4838 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4839 fsp_str_dbg(fsp), nt_errstr(status)));
4840 reply_nterror(req, status);
4841 goto out;
4844 if(nwritten < 0) {
4845 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4846 goto out;
4849 if((nwritten == 0) && (numtowrite != 0)) {
4850 reply_nterror(req, NT_STATUS_DISK_FULL);
4851 goto out;
4854 reply_outbuf(req, 1, 0);
4856 SSVAL(req->outbuf,smb_vwv0,nwritten);
4858 if (nwritten < (ssize_t)numtowrite) {
4859 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4860 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4863 DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4865 out:
4866 END_PROFILE(SMBwrite);
4867 return;
4870 /****************************************************************************
4871 Ensure a buffer is a valid writeX for recvfile purposes.
4872 ****************************************************************************/
4874 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4875 (2*14) + /* word count (including bcc) */ \
4876 1 /* pad byte */)
4878 bool is_valid_writeX_buffer(struct smbXsrv_connection *xconn,
4879 const uint8_t *inbuf)
4881 size_t numtowrite;
4882 unsigned int doff = 0;
4883 size_t len = smb_len_large(inbuf);
4884 uint16_t fnum;
4885 struct smbXsrv_open *op = NULL;
4886 struct files_struct *fsp = NULL;
4887 NTSTATUS status;
4889 if (is_encrypted_packet(inbuf)) {
4890 /* Can't do this on encrypted
4891 * connections. */
4892 return false;
4895 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4896 return false;
4899 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4900 CVAL(inbuf,smb_wct) != 14) {
4901 DEBUG(10,("is_valid_writeX_buffer: chained or "
4902 "invalid word length.\n"));
4903 return false;
4906 fnum = SVAL(inbuf, smb_vwv2);
4907 status = smb1srv_open_lookup(xconn,
4908 fnum,
4909 0, /* now */
4910 &op);
4911 if (!NT_STATUS_IS_OK(status)) {
4912 DEBUG(10,("is_valid_writeX_buffer: bad fnum\n"));
4913 return false;
4915 fsp = op->compat;
4916 if (fsp == NULL) {
4917 DEBUG(10,("is_valid_writeX_buffer: bad fsp\n"));
4918 return false;
4920 if (fsp->conn == NULL) {
4921 DEBUG(10,("is_valid_writeX_buffer: bad fsp->conn\n"));
4922 return false;
4925 if (IS_IPC(fsp->conn)) {
4926 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4927 return false;
4929 if (IS_PRINT(fsp->conn)) {
4930 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4931 return false;
4933 doff = SVAL(inbuf,smb_vwv11);
4935 numtowrite = SVAL(inbuf,smb_vwv10);
4937 if (len > doff && len - doff > 0xFFFF) {
4938 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4941 if (numtowrite == 0) {
4942 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4943 return false;
4946 /* Ensure the sizes match up. */
4947 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4948 /* no pad byte...old smbclient :-( */
4949 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4950 (unsigned int)doff,
4951 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4952 return false;
4955 if (len - doff != numtowrite) {
4956 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4957 "len = %u, doff = %u, numtowrite = %u\n",
4958 (unsigned int)len,
4959 (unsigned int)doff,
4960 (unsigned int)numtowrite ));
4961 return false;
4964 DEBUG(10,("is_valid_writeX_buffer: true "
4965 "len = %u, doff = %u, numtowrite = %u\n",
4966 (unsigned int)len,
4967 (unsigned int)doff,
4968 (unsigned int)numtowrite ));
4970 return true;
4973 /****************************************************************************
4974 Reply to a write and X.
4975 ****************************************************************************/
4977 void reply_write_and_X(struct smb_request *req)
4979 connection_struct *conn = req->conn;
4980 struct smbXsrv_connection *xconn = req->xconn;
4981 files_struct *fsp;
4982 struct lock_struct lock;
4983 off_t startpos;
4984 size_t numtowrite;
4985 bool write_through;
4986 ssize_t nwritten;
4987 unsigned int smb_doff;
4988 unsigned int smblen;
4989 const char *data;
4990 NTSTATUS status;
4991 int saved_errno = 0;
4993 START_PROFILE(SMBwriteX);
4995 if ((req->wct != 12) && (req->wct != 14)) {
4996 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4997 goto out;
5000 numtowrite = SVAL(req->vwv+10, 0);
5001 smb_doff = SVAL(req->vwv+11, 0);
5002 smblen = smb_len(req->inbuf);
5004 if (req->unread_bytes > 0xFFFF ||
5005 (smblen > smb_doff &&
5006 smblen - smb_doff > 0xFFFF)) {
5007 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
5010 if (req->unread_bytes) {
5011 /* Can't do a recvfile write on IPC$ */
5012 if (IS_IPC(conn)) {
5013 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5014 goto out;
5016 if (numtowrite != req->unread_bytes) {
5017 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5018 goto out;
5020 } else {
5021 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
5022 smb_doff + numtowrite > smblen) {
5023 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5024 goto out;
5028 /* If it's an IPC, pass off the pipe handler. */
5029 if (IS_IPC(conn)) {
5030 if (req->unread_bytes) {
5031 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5032 goto out;
5034 reply_pipe_write_and_X(req);
5035 goto out;
5038 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
5039 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
5040 write_through = BITSETW(req->vwv+7,0);
5042 if (!check_fsp(conn, req, fsp)) {
5043 goto out;
5046 if (!CHECK_WRITE(fsp)) {
5047 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5048 goto out;
5051 data = smb_base(req->inbuf) + smb_doff;
5053 if(req->wct == 14) {
5055 * This is a large offset (64 bit) write.
5057 startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
5061 /* X/Open SMB protocol says that, unlike SMBwrite
5062 if the length is zero then NO truncation is
5063 done, just a write of zero. To truncate a file,
5064 use SMBwrite. */
5066 if(numtowrite == 0) {
5067 nwritten = 0;
5068 } else {
5069 if (req->unread_bytes == 0) {
5070 status = schedule_aio_write_and_X(conn,
5071 req,
5072 fsp,
5073 data,
5074 startpos,
5075 numtowrite);
5077 if (NT_STATUS_IS_OK(status)) {
5078 /* write scheduled - we're done. */
5079 goto out;
5081 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
5082 /* Real error - report to client. */
5083 reply_nterror(req, status);
5084 goto out;
5086 /* NT_STATUS_RETRY - fall through to sync write. */
5089 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5090 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5091 &lock);
5093 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
5094 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5095 goto out;
5098 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5099 saved_errno = errno;
5102 if(nwritten < 0) {
5103 reply_nterror(req, map_nt_error_from_unix(saved_errno));
5104 goto out;
5107 if((nwritten == 0) && (numtowrite != 0)) {
5108 reply_nterror(req, NT_STATUS_DISK_FULL);
5109 goto out;
5112 reply_outbuf(req, 6, 0);
5113 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
5114 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
5115 SSVAL(req->outbuf,smb_vwv2,nwritten);
5116 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
5118 DEBUG(3,("writeX %s num=%d wrote=%d\n",
5119 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
5121 status = sync_file(conn, fsp, write_through);
5122 if (!NT_STATUS_IS_OK(status)) {
5123 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
5124 fsp_str_dbg(fsp), nt_errstr(status)));
5125 reply_nterror(req, status);
5126 goto out;
5129 END_PROFILE(SMBwriteX);
5130 return;
5132 out:
5133 if (req->unread_bytes) {
5134 /* writeX failed. drain socket. */
5135 if (drain_socket(xconn->transport.sock, req->unread_bytes) !=
5136 req->unread_bytes) {
5137 smb_panic("failed to drain pending bytes");
5139 req->unread_bytes = 0;
5142 END_PROFILE(SMBwriteX);
5143 return;
5146 /****************************************************************************
5147 Reply to a lseek.
5148 ****************************************************************************/
5150 void reply_lseek(struct smb_request *req)
5152 connection_struct *conn = req->conn;
5153 off_t startpos;
5154 off_t res= -1;
5155 int mode,umode;
5156 files_struct *fsp;
5158 START_PROFILE(SMBlseek);
5160 if (req->wct < 4) {
5161 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5162 END_PROFILE(SMBlseek);
5163 return;
5166 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5168 if (!check_fsp(conn, req, fsp)) {
5169 return;
5172 flush_write_cache(fsp, SAMBA_SEEK_FLUSH);
5174 mode = SVAL(req->vwv+1, 0) & 3;
5175 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
5176 startpos = (off_t)IVALS(req->vwv+2, 0);
5178 switch (mode) {
5179 case 0:
5180 umode = SEEK_SET;
5181 res = startpos;
5182 break;
5183 case 1:
5184 umode = SEEK_CUR;
5185 res = fsp->fh->pos + startpos;
5186 break;
5187 case 2:
5188 umode = SEEK_END;
5189 break;
5190 default:
5191 umode = SEEK_SET;
5192 res = startpos;
5193 break;
5196 if (umode == SEEK_END) {
5197 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
5198 if(errno == EINVAL) {
5199 off_t current_pos = startpos;
5201 if(fsp_stat(fsp) == -1) {
5202 reply_nterror(req,
5203 map_nt_error_from_unix(errno));
5204 END_PROFILE(SMBlseek);
5205 return;
5208 current_pos += fsp->fsp_name->st.st_ex_size;
5209 if(current_pos < 0)
5210 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
5214 if(res == -1) {
5215 reply_nterror(req, map_nt_error_from_unix(errno));
5216 END_PROFILE(SMBlseek);
5217 return;
5221 fsp->fh->pos = res;
5223 reply_outbuf(req, 2, 0);
5224 SIVAL(req->outbuf,smb_vwv0,res);
5226 DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n",
5227 fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode));
5229 END_PROFILE(SMBlseek);
5230 return;
5233 /****************************************************************************
5234 Reply to a flush.
5235 ****************************************************************************/
5237 void reply_flush(struct smb_request *req)
5239 connection_struct *conn = req->conn;
5240 uint16_t fnum;
5241 files_struct *fsp;
5243 START_PROFILE(SMBflush);
5245 if (req->wct < 1) {
5246 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5247 return;
5250 fnum = SVAL(req->vwv+0, 0);
5251 fsp = file_fsp(req, fnum);
5253 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
5254 return;
5257 if (!fsp) {
5258 file_sync_all(conn);
5259 } else {
5260 NTSTATUS status = sync_file(conn, fsp, True);
5261 if (!NT_STATUS_IS_OK(status)) {
5262 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
5263 fsp_str_dbg(fsp), nt_errstr(status)));
5264 reply_nterror(req, status);
5265 END_PROFILE(SMBflush);
5266 return;
5270 reply_outbuf(req, 0, 0);
5272 DEBUG(3,("flush\n"));
5273 END_PROFILE(SMBflush);
5274 return;
5277 /****************************************************************************
5278 Reply to a exit.
5279 conn POINTER CAN BE NULL HERE !
5280 ****************************************************************************/
5282 void reply_exit(struct smb_request *req)
5284 START_PROFILE(SMBexit);
5286 file_close_pid(req->sconn, req->smbpid, req->vuid);
5288 reply_outbuf(req, 0, 0);
5290 DEBUG(3,("exit\n"));
5292 END_PROFILE(SMBexit);
5293 return;
5296 struct reply_close_state {
5297 files_struct *fsp;
5298 struct smb_request *smbreq;
5301 static void do_smb1_close(struct tevent_req *req);
5303 void reply_close(struct smb_request *req)
5305 connection_struct *conn = req->conn;
5306 NTSTATUS status = NT_STATUS_OK;
5307 files_struct *fsp = NULL;
5308 START_PROFILE(SMBclose);
5310 if (req->wct < 3) {
5311 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5312 END_PROFILE(SMBclose);
5313 return;
5316 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5319 * We can only use check_fsp if we know it's not a directory.
5322 if (!check_fsp_open(conn, req, fsp)) {
5323 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
5324 END_PROFILE(SMBclose);
5325 return;
5328 DEBUG(3, ("Close %s fd=%d %s (numopen=%d)\n",
5329 fsp->is_directory ? "directory" : "file",
5330 fsp->fh->fd, fsp_fnum_dbg(fsp),
5331 conn->num_files_open));
5333 if (!fsp->is_directory) {
5334 time_t t;
5337 * Take care of any time sent in the close.
5340 t = srv_make_unix_date3(req->vwv+1);
5341 set_close_write_time(fsp, convert_time_t_to_timespec(t));
5344 if (fsp->num_aio_requests != 0) {
5346 struct reply_close_state *state;
5348 DEBUG(10, ("closing with aio %u requests pending\n",
5349 fsp->num_aio_requests));
5352 * We depend on the aio_extra destructor to take care of this
5353 * close request once fsp->num_aio_request drops to 0.
5356 fsp->deferred_close = tevent_wait_send(
5357 fsp, fsp->conn->sconn->ev_ctx);
5358 if (fsp->deferred_close == NULL) {
5359 status = NT_STATUS_NO_MEMORY;
5360 goto done;
5363 state = talloc(fsp, struct reply_close_state);
5364 if (state == NULL) {
5365 TALLOC_FREE(fsp->deferred_close);
5366 status = NT_STATUS_NO_MEMORY;
5367 goto done;
5369 state->fsp = fsp;
5370 state->smbreq = talloc_move(fsp, &req);
5371 tevent_req_set_callback(fsp->deferred_close, do_smb1_close,
5372 state);
5373 END_PROFILE(SMBclose);
5374 return;
5378 * close_file() returns the unix errno if an error was detected on
5379 * close - normally this is due to a disk full error. If not then it
5380 * was probably an I/O error.
5383 status = close_file(req, fsp, NORMAL_CLOSE);
5384 done:
5385 if (!NT_STATUS_IS_OK(status)) {
5386 reply_nterror(req, status);
5387 END_PROFILE(SMBclose);
5388 return;
5391 reply_outbuf(req, 0, 0);
5392 END_PROFILE(SMBclose);
5393 return;
5396 static void do_smb1_close(struct tevent_req *req)
5398 struct reply_close_state *state = tevent_req_callback_data(
5399 req, struct reply_close_state);
5400 struct smb_request *smbreq;
5401 NTSTATUS status;
5402 int ret;
5404 ret = tevent_wait_recv(req);
5405 TALLOC_FREE(req);
5406 if (ret != 0) {
5407 DEBUG(10, ("tevent_wait_recv returned %s\n",
5408 strerror(ret)));
5410 * Continue anyway, this should never happen
5415 * fsp->smb2_close_request right now is a talloc grandchild of
5416 * fsp. When we close_file(fsp), it would go with it. No chance to
5417 * reply...
5419 smbreq = talloc_move(talloc_tos(), &state->smbreq);
5421 status = close_file(smbreq, state->fsp, NORMAL_CLOSE);
5422 if (NT_STATUS_IS_OK(status)) {
5423 reply_outbuf(smbreq, 0, 0);
5424 } else {
5425 reply_nterror(smbreq, status);
5427 if (!srv_send_smb(smbreq->xconn,
5428 (char *)smbreq->outbuf,
5429 true,
5430 smbreq->seqnum+1,
5431 IS_CONN_ENCRYPTED(smbreq->conn)||smbreq->encrypted,
5432 NULL)) {
5433 exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
5434 "failed.");
5436 TALLOC_FREE(smbreq);
5439 /****************************************************************************
5440 Reply to a writeclose (Core+ protocol).
5441 ****************************************************************************/
5443 void reply_writeclose(struct smb_request *req)
5445 connection_struct *conn = req->conn;
5446 size_t numtowrite;
5447 ssize_t nwritten = -1;
5448 NTSTATUS close_status = NT_STATUS_OK;
5449 off_t startpos;
5450 const char *data;
5451 struct timespec mtime;
5452 files_struct *fsp;
5453 struct lock_struct lock;
5455 START_PROFILE(SMBwriteclose);
5457 if (req->wct < 6) {
5458 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5459 END_PROFILE(SMBwriteclose);
5460 return;
5463 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5465 if (!check_fsp(conn, req, fsp)) {
5466 END_PROFILE(SMBwriteclose);
5467 return;
5469 if (!CHECK_WRITE(fsp)) {
5470 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5471 END_PROFILE(SMBwriteclose);
5472 return;
5475 numtowrite = SVAL(req->vwv+1, 0);
5476 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5477 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
5478 data = (const char *)req->buf + 1;
5480 if (fsp->print_file == NULL) {
5481 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5482 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5483 &lock);
5485 if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
5486 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5487 END_PROFILE(SMBwriteclose);
5488 return;
5492 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5494 set_close_write_time(fsp, mtime);
5497 * More insanity. W2K only closes the file if writelen > 0.
5498 * JRA.
5501 DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
5502 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
5503 (numtowrite) ? conn->num_files_open - 1 : conn->num_files_open));
5505 if (numtowrite) {
5506 DEBUG(3,("reply_writeclose: zero length write doesn't close "
5507 "file %s\n", fsp_str_dbg(fsp)));
5508 close_status = close_file(req, fsp, NORMAL_CLOSE);
5509 fsp = NULL;
5512 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
5513 reply_nterror(req, NT_STATUS_DISK_FULL);
5514 goto out;
5517 if(!NT_STATUS_IS_OK(close_status)) {
5518 reply_nterror(req, close_status);
5519 goto out;
5522 reply_outbuf(req, 1, 0);
5524 SSVAL(req->outbuf,smb_vwv0,nwritten);
5526 out:
5528 END_PROFILE(SMBwriteclose);
5529 return;
5532 #undef DBGC_CLASS
5533 #define DBGC_CLASS DBGC_LOCKING
5535 /****************************************************************************
5536 Reply to a lock.
5537 ****************************************************************************/
5539 void reply_lock(struct smb_request *req)
5541 connection_struct *conn = req->conn;
5542 uint64_t count,offset;
5543 NTSTATUS status;
5544 files_struct *fsp;
5545 struct byte_range_lock *br_lck = NULL;
5547 START_PROFILE(SMBlock);
5549 if (req->wct < 5) {
5550 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5551 END_PROFILE(SMBlock);
5552 return;
5555 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5557 if (!check_fsp(conn, req, fsp)) {
5558 END_PROFILE(SMBlock);
5559 return;
5562 count = (uint64_t)IVAL(req->vwv+1, 0);
5563 offset = (uint64_t)IVAL(req->vwv+3, 0);
5565 DEBUG(3,("lock fd=%d %s offset=%.0f count=%.0f\n",
5566 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count));
5568 br_lck = do_lock(req->sconn->msg_ctx,
5569 fsp,
5570 (uint64_t)req->smbpid,
5571 count,
5572 offset,
5573 WRITE_LOCK,
5574 WINDOWS_LOCK,
5575 False, /* Non-blocking lock. */
5576 &status,
5577 NULL);
5579 TALLOC_FREE(br_lck);
5581 if (NT_STATUS_V(status)) {
5582 reply_nterror(req, status);
5583 END_PROFILE(SMBlock);
5584 return;
5587 reply_outbuf(req, 0, 0);
5589 END_PROFILE(SMBlock);
5590 return;
5593 /****************************************************************************
5594 Reply to a unlock.
5595 ****************************************************************************/
5597 void reply_unlock(struct smb_request *req)
5599 connection_struct *conn = req->conn;
5600 uint64_t count,offset;
5601 NTSTATUS status;
5602 files_struct *fsp;
5604 START_PROFILE(SMBunlock);
5606 if (req->wct < 5) {
5607 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5608 END_PROFILE(SMBunlock);
5609 return;
5612 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5614 if (!check_fsp(conn, req, fsp)) {
5615 END_PROFILE(SMBunlock);
5616 return;
5619 count = (uint64_t)IVAL(req->vwv+1, 0);
5620 offset = (uint64_t)IVAL(req->vwv+3, 0);
5622 status = do_unlock(req->sconn->msg_ctx,
5623 fsp,
5624 (uint64_t)req->smbpid,
5625 count,
5626 offset,
5627 WINDOWS_LOCK);
5629 if (NT_STATUS_V(status)) {
5630 reply_nterror(req, status);
5631 END_PROFILE(SMBunlock);
5632 return;
5635 DEBUG( 3, ( "unlock fd=%d %s offset=%.0f count=%.0f\n",
5636 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count ) );
5638 reply_outbuf(req, 0, 0);
5640 END_PROFILE(SMBunlock);
5641 return;
5644 #undef DBGC_CLASS
5645 #define DBGC_CLASS DBGC_ALL
5647 /****************************************************************************
5648 Reply to a tdis.
5649 conn POINTER CAN BE NULL HERE !
5650 ****************************************************************************/
5652 void reply_tdis(struct smb_request *req)
5654 NTSTATUS status;
5655 connection_struct *conn = req->conn;
5656 struct smbXsrv_tcon *tcon;
5658 START_PROFILE(SMBtdis);
5660 if (!conn) {
5661 DEBUG(4,("Invalid connection in tdis\n"));
5662 reply_force_doserror(req, ERRSRV, ERRinvnid);
5663 END_PROFILE(SMBtdis);
5664 return;
5667 tcon = conn->tcon;
5668 req->conn = NULL;
5671 * TODO: cancel all outstanding requests on the tcon
5673 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
5674 if (!NT_STATUS_IS_OK(status)) {
5675 DEBUG(0, ("reply_tdis: "
5676 "smbXsrv_tcon_disconnect() failed: %s\n",
5677 nt_errstr(status)));
5679 * If we hit this case, there is something completely
5680 * wrong, so we better disconnect the transport connection.
5682 END_PROFILE(SMBtdis);
5683 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
5684 return;
5687 TALLOC_FREE(tcon);
5689 reply_outbuf(req, 0, 0);
5690 END_PROFILE(SMBtdis);
5691 return;
5694 /****************************************************************************
5695 Reply to a echo.
5696 conn POINTER CAN BE NULL HERE !
5697 ****************************************************************************/
5699 void reply_echo(struct smb_request *req)
5701 connection_struct *conn = req->conn;
5702 struct smb_perfcount_data local_pcd;
5703 struct smb_perfcount_data *cur_pcd;
5704 int smb_reverb;
5705 int seq_num;
5707 START_PROFILE(SMBecho);
5709 smb_init_perfcount_data(&local_pcd);
5711 if (req->wct < 1) {
5712 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5713 END_PROFILE(SMBecho);
5714 return;
5717 smb_reverb = SVAL(req->vwv+0, 0);
5719 reply_outbuf(req, 1, req->buflen);
5721 /* copy any incoming data back out */
5722 if (req->buflen > 0) {
5723 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5726 if (smb_reverb > 100) {
5727 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5728 smb_reverb = 100;
5731 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5733 /* this makes sure we catch the request pcd */
5734 if (seq_num == smb_reverb) {
5735 cur_pcd = &req->pcd;
5736 } else {
5737 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5738 cur_pcd = &local_pcd;
5741 SSVAL(req->outbuf,smb_vwv0,seq_num);
5743 show_msg((char *)req->outbuf);
5744 if (!srv_send_smb(req->xconn,
5745 (char *)req->outbuf,
5746 true, req->seqnum+1,
5747 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5748 cur_pcd))
5749 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5752 DEBUG(3,("echo %d times\n", smb_reverb));
5754 TALLOC_FREE(req->outbuf);
5756 END_PROFILE(SMBecho);
5757 return;
5760 /****************************************************************************
5761 Reply to a printopen.
5762 ****************************************************************************/
5764 void reply_printopen(struct smb_request *req)
5766 connection_struct *conn = req->conn;
5767 files_struct *fsp;
5768 NTSTATUS status;
5770 START_PROFILE(SMBsplopen);
5772 if (req->wct < 2) {
5773 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5774 END_PROFILE(SMBsplopen);
5775 return;
5778 if (!CAN_PRINT(conn)) {
5779 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5780 END_PROFILE(SMBsplopen);
5781 return;
5784 status = file_new(req, conn, &fsp);
5785 if(!NT_STATUS_IS_OK(status)) {
5786 reply_nterror(req, status);
5787 END_PROFILE(SMBsplopen);
5788 return;
5791 /* Open for exclusive use, write only. */
5792 status = print_spool_open(fsp, NULL, req->vuid);
5794 if (!NT_STATUS_IS_OK(status)) {
5795 file_free(req, fsp);
5796 reply_nterror(req, status);
5797 END_PROFILE(SMBsplopen);
5798 return;
5801 reply_outbuf(req, 1, 0);
5802 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5804 DEBUG(3,("openprint fd=%d %s\n",
5805 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5807 END_PROFILE(SMBsplopen);
5808 return;
5811 /****************************************************************************
5812 Reply to a printclose.
5813 ****************************************************************************/
5815 void reply_printclose(struct smb_request *req)
5817 connection_struct *conn = req->conn;
5818 files_struct *fsp;
5819 NTSTATUS status;
5821 START_PROFILE(SMBsplclose);
5823 if (req->wct < 1) {
5824 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5825 END_PROFILE(SMBsplclose);
5826 return;
5829 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5831 if (!check_fsp(conn, req, fsp)) {
5832 END_PROFILE(SMBsplclose);
5833 return;
5836 if (!CAN_PRINT(conn)) {
5837 reply_force_doserror(req, ERRSRV, ERRerror);
5838 END_PROFILE(SMBsplclose);
5839 return;
5842 DEBUG(3,("printclose fd=%d %s\n",
5843 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5845 status = close_file(req, fsp, NORMAL_CLOSE);
5847 if(!NT_STATUS_IS_OK(status)) {
5848 reply_nterror(req, status);
5849 END_PROFILE(SMBsplclose);
5850 return;
5853 reply_outbuf(req, 0, 0);
5855 END_PROFILE(SMBsplclose);
5856 return;
5859 /****************************************************************************
5860 Reply to a printqueue.
5861 ****************************************************************************/
5863 void reply_printqueue(struct smb_request *req)
5865 connection_struct *conn = req->conn;
5866 int max_count;
5867 int start_index;
5869 START_PROFILE(SMBsplretq);
5871 if (req->wct < 2) {
5872 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5873 END_PROFILE(SMBsplretq);
5874 return;
5877 max_count = SVAL(req->vwv+0, 0);
5878 start_index = SVAL(req->vwv+1, 0);
5880 /* we used to allow the client to get the cnum wrong, but that
5881 is really quite gross and only worked when there was only
5882 one printer - I think we should now only accept it if they
5883 get it right (tridge) */
5884 if (!CAN_PRINT(conn)) {
5885 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5886 END_PROFILE(SMBsplretq);
5887 return;
5890 reply_outbuf(req, 2, 3);
5891 SSVAL(req->outbuf,smb_vwv0,0);
5892 SSVAL(req->outbuf,smb_vwv1,0);
5893 SCVAL(smb_buf(req->outbuf),0,1);
5894 SSVAL(smb_buf(req->outbuf),1,0);
5896 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5897 start_index, max_count));
5900 TALLOC_CTX *mem_ctx = talloc_tos();
5901 NTSTATUS status;
5902 WERROR werr;
5903 const char *sharename = lp_servicename(mem_ctx, SNUM(conn));
5904 struct rpc_pipe_client *cli = NULL;
5905 struct dcerpc_binding_handle *b = NULL;
5906 struct policy_handle handle;
5907 struct spoolss_DevmodeContainer devmode_ctr;
5908 union spoolss_JobInfo *info;
5909 uint32_t count;
5910 uint32_t num_to_get;
5911 uint32_t first;
5912 uint32_t i;
5914 ZERO_STRUCT(handle);
5916 status = rpc_pipe_open_interface(mem_ctx,
5917 &ndr_table_spoolss,
5918 conn->session_info,
5919 conn->sconn->remote_address,
5920 conn->sconn->local_address,
5921 conn->sconn->msg_ctx,
5922 &cli);
5923 if (!NT_STATUS_IS_OK(status)) {
5924 DEBUG(0, ("reply_printqueue: "
5925 "could not connect to spoolss: %s\n",
5926 nt_errstr(status)));
5927 reply_nterror(req, status);
5928 goto out;
5930 b = cli->binding_handle;
5932 ZERO_STRUCT(devmode_ctr);
5934 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5935 sharename,
5936 NULL, devmode_ctr,
5937 SEC_FLAG_MAXIMUM_ALLOWED,
5938 &handle,
5939 &werr);
5940 if (!NT_STATUS_IS_OK(status)) {
5941 reply_nterror(req, status);
5942 goto out;
5944 if (!W_ERROR_IS_OK(werr)) {
5945 reply_nterror(req, werror_to_ntstatus(werr));
5946 goto out;
5949 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5950 &handle,
5951 0, /* firstjob */
5952 0xff, /* numjobs */
5953 2, /* level */
5954 0, /* offered */
5955 &count,
5956 &info);
5957 if (!W_ERROR_IS_OK(werr)) {
5958 reply_nterror(req, werror_to_ntstatus(werr));
5959 goto out;
5962 if (max_count > 0) {
5963 first = start_index;
5964 } else {
5965 first = start_index + max_count + 1;
5968 if (first >= count) {
5969 num_to_get = first;
5970 } else {
5971 num_to_get = first + MIN(ABS(max_count), count - first);
5974 for (i = first; i < num_to_get; i++) {
5975 char blob[28];
5976 char *p = blob;
5977 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
5978 int qstatus;
5979 size_t len = 0;
5980 uint16_t qrapjobid = pjobid_to_rap(sharename,
5981 info[i].info2.job_id);
5983 if (info[i].info2.status == JOB_STATUS_PRINTING) {
5984 qstatus = 2;
5985 } else {
5986 qstatus = 3;
5989 srv_put_dos_date2(p, 0, qtime);
5990 SCVAL(p, 4, qstatus);
5991 SSVAL(p, 5, qrapjobid);
5992 SIVAL(p, 7, info[i].info2.size);
5993 SCVAL(p, 11, 0);
5994 status = srvstr_push(blob, req->flags2, p+12,
5995 info[i].info2.notify_name, 16, STR_ASCII, &len);
5996 if (!NT_STATUS_IS_OK(status)) {
5997 reply_nterror(req, status);
5998 goto out;
6000 if (message_push_blob(
6001 &req->outbuf,
6002 data_blob_const(
6003 blob, sizeof(blob))) == -1) {
6004 reply_nterror(req, NT_STATUS_NO_MEMORY);
6005 goto out;
6009 if (count > 0) {
6010 SSVAL(req->outbuf,smb_vwv0,count);
6011 SSVAL(req->outbuf,smb_vwv1,
6012 (max_count>0?first+count:first-1));
6013 SCVAL(smb_buf(req->outbuf),0,1);
6014 SSVAL(smb_buf(req->outbuf),1,28*count);
6018 DEBUG(3, ("%u entries returned in queue\n",
6019 (unsigned)count));
6021 out:
6022 if (b && is_valid_policy_hnd(&handle)) {
6023 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
6028 END_PROFILE(SMBsplretq);
6029 return;
6032 /****************************************************************************
6033 Reply to a printwrite.
6034 ****************************************************************************/
6036 void reply_printwrite(struct smb_request *req)
6038 connection_struct *conn = req->conn;
6039 int numtowrite;
6040 const char *data;
6041 files_struct *fsp;
6043 START_PROFILE(SMBsplwr);
6045 if (req->wct < 1) {
6046 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6047 END_PROFILE(SMBsplwr);
6048 return;
6051 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
6053 if (!check_fsp(conn, req, fsp)) {
6054 END_PROFILE(SMBsplwr);
6055 return;
6058 if (!fsp->print_file) {
6059 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6060 END_PROFILE(SMBsplwr);
6061 return;
6064 if (!CHECK_WRITE(fsp)) {
6065 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6066 END_PROFILE(SMBsplwr);
6067 return;
6070 numtowrite = SVAL(req->buf, 1);
6072 if (req->buflen < numtowrite + 3) {
6073 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6074 END_PROFILE(SMBsplwr);
6075 return;
6078 data = (const char *)req->buf + 3;
6080 if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
6081 reply_nterror(req, map_nt_error_from_unix(errno));
6082 END_PROFILE(SMBsplwr);
6083 return;
6086 DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
6088 END_PROFILE(SMBsplwr);
6089 return;
6092 /****************************************************************************
6093 Reply to a mkdir.
6094 ****************************************************************************/
6096 void reply_mkdir(struct smb_request *req)
6098 connection_struct *conn = req->conn;
6099 struct smb_filename *smb_dname = NULL;
6100 char *directory = NULL;
6101 NTSTATUS status;
6102 uint32_t ucf_flags;
6103 TALLOC_CTX *ctx = talloc_tos();
6105 START_PROFILE(SMBmkdir);
6107 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
6108 STR_TERMINATE, &status);
6109 if (!NT_STATUS_IS_OK(status)) {
6110 reply_nterror(req, status);
6111 goto out;
6114 ucf_flags = filename_create_ucf_flags(req, FILE_CREATE);
6115 status = filename_convert(ctx, conn,
6116 directory,
6117 ucf_flags,
6118 NULL,
6119 &smb_dname);
6120 if (!NT_STATUS_IS_OK(status)) {
6121 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6122 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6123 ERRSRV, ERRbadpath);
6124 goto out;
6126 reply_nterror(req, status);
6127 goto out;
6130 status = create_directory(conn, req, smb_dname);
6132 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
6134 if (!NT_STATUS_IS_OK(status)) {
6136 if (!use_nt_status()
6137 && NT_STATUS_EQUAL(status,
6138 NT_STATUS_OBJECT_NAME_COLLISION)) {
6140 * Yes, in the DOS error code case we get a
6141 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
6142 * samba4 torture test.
6144 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
6147 reply_nterror(req, status);
6148 goto out;
6151 reply_outbuf(req, 0, 0);
6153 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
6154 out:
6155 TALLOC_FREE(smb_dname);
6156 END_PROFILE(SMBmkdir);
6157 return;
6160 /****************************************************************************
6161 Reply to a rmdir.
6162 ****************************************************************************/
6164 void reply_rmdir(struct smb_request *req)
6166 connection_struct *conn = req->conn;
6167 struct smb_filename *smb_dname = NULL;
6168 char *directory = NULL;
6169 NTSTATUS status;
6170 TALLOC_CTX *ctx = talloc_tos();
6171 files_struct *fsp = NULL;
6172 int info = 0;
6173 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
6174 struct smbd_server_connection *sconn = req->sconn;
6176 START_PROFILE(SMBrmdir);
6178 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
6179 STR_TERMINATE, &status);
6180 if (!NT_STATUS_IS_OK(status)) {
6181 reply_nterror(req, status);
6182 goto out;
6185 status = filename_convert(ctx, conn,
6186 directory,
6187 ucf_flags,
6188 NULL,
6189 &smb_dname);
6190 if (!NT_STATUS_IS_OK(status)) {
6191 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6192 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6193 ERRSRV, ERRbadpath);
6194 goto out;
6196 reply_nterror(req, status);
6197 goto out;
6200 if (is_ntfs_stream_smb_fname(smb_dname)) {
6201 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
6202 goto out;
6205 status = SMB_VFS_CREATE_FILE(
6206 conn, /* conn */
6207 req, /* req */
6208 0, /* root_dir_fid */
6209 smb_dname, /* fname */
6210 DELETE_ACCESS, /* access_mask */
6211 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
6212 FILE_SHARE_DELETE),
6213 FILE_OPEN, /* create_disposition*/
6214 FILE_DIRECTORY_FILE, /* create_options */
6215 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
6216 0, /* oplock_request */
6217 NULL, /* lease */
6218 0, /* allocation_size */
6219 0, /* private_flags */
6220 NULL, /* sd */
6221 NULL, /* ea_list */
6222 &fsp, /* result */
6223 &info, /* pinfo */
6224 NULL, NULL); /* create context */
6226 if (!NT_STATUS_IS_OK(status)) {
6227 if (open_was_deferred(req->xconn, req->mid)) {
6228 /* We have re-scheduled this call. */
6229 goto out;
6231 reply_nterror(req, status);
6232 goto out;
6235 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
6236 if (!NT_STATUS_IS_OK(status)) {
6237 close_file(req, fsp, ERROR_CLOSE);
6238 reply_nterror(req, status);
6239 goto out;
6242 if (!set_delete_on_close(fsp, true,
6243 conn->session_info->security_token,
6244 conn->session_info->unix_token)) {
6245 close_file(req, fsp, ERROR_CLOSE);
6246 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
6247 goto out;
6250 status = close_file(req, fsp, NORMAL_CLOSE);
6251 if (!NT_STATUS_IS_OK(status)) {
6252 reply_nterror(req, status);
6253 } else {
6254 reply_outbuf(req, 0, 0);
6257 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
6259 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
6260 out:
6261 TALLOC_FREE(smb_dname);
6262 END_PROFILE(SMBrmdir);
6263 return;
6266 /*******************************************************************
6267 Resolve wildcards in a filename rename.
6268 ********************************************************************/
6270 static bool resolve_wildcards(TALLOC_CTX *ctx,
6271 const char *name1,
6272 const char *name2,
6273 char **pp_newname)
6275 char *name2_copy = NULL;
6276 char *root1 = NULL;
6277 char *root2 = NULL;
6278 char *ext1 = NULL;
6279 char *ext2 = NULL;
6280 char *p,*p2, *pname1, *pname2;
6282 name2_copy = talloc_strdup(ctx, name2);
6283 if (!name2_copy) {
6284 return False;
6287 pname1 = strrchr_m(name1,'/');
6288 pname2 = strrchr_m(name2_copy,'/');
6290 if (!pname1 || !pname2) {
6291 return False;
6294 /* Truncate the copy of name2 at the last '/' */
6295 *pname2 = '\0';
6297 /* Now go past the '/' */
6298 pname1++;
6299 pname2++;
6301 root1 = talloc_strdup(ctx, pname1);
6302 root2 = talloc_strdup(ctx, pname2);
6304 if (!root1 || !root2) {
6305 return False;
6308 p = strrchr_m(root1,'.');
6309 if (p) {
6310 *p = 0;
6311 ext1 = talloc_strdup(ctx, p+1);
6312 } else {
6313 ext1 = talloc_strdup(ctx, "");
6315 p = strrchr_m(root2,'.');
6316 if (p) {
6317 *p = 0;
6318 ext2 = talloc_strdup(ctx, p+1);
6319 } else {
6320 ext2 = talloc_strdup(ctx, "");
6323 if (!ext1 || !ext2) {
6324 return False;
6327 p = root1;
6328 p2 = root2;
6329 while (*p2) {
6330 if (*p2 == '?') {
6331 /* Hmmm. Should this be mb-aware ? */
6332 *p2 = *p;
6333 p2++;
6334 } else if (*p2 == '*') {
6335 *p2 = '\0';
6336 root2 = talloc_asprintf(ctx, "%s%s",
6337 root2,
6339 if (!root2) {
6340 return False;
6342 break;
6343 } else {
6344 p2++;
6346 if (*p) {
6347 p++;
6351 p = ext1;
6352 p2 = ext2;
6353 while (*p2) {
6354 if (*p2 == '?') {
6355 /* Hmmm. Should this be mb-aware ? */
6356 *p2 = *p;
6357 p2++;
6358 } else if (*p2 == '*') {
6359 *p2 = '\0';
6360 ext2 = talloc_asprintf(ctx, "%s%s",
6361 ext2,
6363 if (!ext2) {
6364 return False;
6366 break;
6367 } else {
6368 p2++;
6370 if (*p) {
6371 p++;
6375 if (*ext2) {
6376 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
6377 name2_copy,
6378 root2,
6379 ext2);
6380 } else {
6381 *pp_newname = talloc_asprintf(ctx, "%s/%s",
6382 name2_copy,
6383 root2);
6386 if (!*pp_newname) {
6387 return False;
6390 return True;
6393 /****************************************************************************
6394 Ensure open files have their names updated. Updated to notify other smbd's
6395 asynchronously.
6396 ****************************************************************************/
6398 static void rename_open_files(connection_struct *conn,
6399 struct share_mode_lock *lck,
6400 struct file_id id,
6401 uint32_t orig_name_hash,
6402 const struct smb_filename *smb_fname_dst)
6404 files_struct *fsp;
6405 bool did_rename = False;
6406 NTSTATUS status;
6407 uint32_t new_name_hash = 0;
6409 for(fsp = file_find_di_first(conn->sconn, id); fsp;
6410 fsp = file_find_di_next(fsp)) {
6411 /* fsp_name is a relative path under the fsp. To change this for other
6412 sharepaths we need to manipulate relative paths. */
6413 /* TODO - create the absolute path and manipulate the newname
6414 relative to the sharepath. */
6415 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
6416 continue;
6418 if (fsp->name_hash != orig_name_hash) {
6419 continue;
6421 DEBUG(10, ("rename_open_files: renaming file %s "
6422 "(file_id %s) from %s -> %s\n", fsp_fnum_dbg(fsp),
6423 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
6424 smb_fname_str_dbg(smb_fname_dst)));
6426 status = fsp_set_smb_fname(fsp, smb_fname_dst);
6427 if (NT_STATUS_IS_OK(status)) {
6428 did_rename = True;
6429 new_name_hash = fsp->name_hash;
6433 if (!did_rename) {
6434 DEBUG(10, ("rename_open_files: no open files on file_id %s "
6435 "for %s\n", file_id_string_tos(&id),
6436 smb_fname_str_dbg(smb_fname_dst)));
6439 /* Send messages to all smbd's (not ourself) that the name has changed. */
6440 rename_share_filename(conn->sconn->msg_ctx, lck, id, conn->connectpath,
6441 orig_name_hash, new_name_hash,
6442 smb_fname_dst);
6446 /****************************************************************************
6447 We need to check if the source path is a parent directory of the destination
6448 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
6449 refuse the rename with a sharing violation. Under UNIX the above call can
6450 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
6451 probably need to check that the client is a Windows one before disallowing
6452 this as a UNIX client (one with UNIX extensions) can know the source is a
6453 symlink and make this decision intelligently. Found by an excellent bug
6454 report from <AndyLiebman@aol.com>.
6455 ****************************************************************************/
6457 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
6458 const struct smb_filename *smb_fname_dst)
6460 const char *psrc = smb_fname_src->base_name;
6461 const char *pdst = smb_fname_dst->base_name;
6462 size_t slen;
6464 if (psrc[0] == '.' && psrc[1] == '/') {
6465 psrc += 2;
6467 if (pdst[0] == '.' && pdst[1] == '/') {
6468 pdst += 2;
6470 if ((slen = strlen(psrc)) > strlen(pdst)) {
6471 return False;
6473 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
6477 * Do the notify calls from a rename
6480 static void notify_rename(connection_struct *conn, bool is_dir,
6481 const struct smb_filename *smb_fname_src,
6482 const struct smb_filename *smb_fname_dst)
6484 char *parent_dir_src = NULL;
6485 char *parent_dir_dst = NULL;
6486 uint32_t mask;
6488 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
6489 : FILE_NOTIFY_CHANGE_FILE_NAME;
6491 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
6492 &parent_dir_src, NULL) ||
6493 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
6494 &parent_dir_dst, NULL)) {
6495 goto out;
6498 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
6499 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
6500 smb_fname_src->base_name);
6501 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
6502 smb_fname_dst->base_name);
6504 else {
6505 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
6506 smb_fname_src->base_name);
6507 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
6508 smb_fname_dst->base_name);
6511 /* this is a strange one. w2k3 gives an additional event for
6512 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
6513 files, but not directories */
6514 if (!is_dir) {
6515 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6516 FILE_NOTIFY_CHANGE_ATTRIBUTES
6517 |FILE_NOTIFY_CHANGE_CREATION,
6518 smb_fname_dst->base_name);
6520 out:
6521 TALLOC_FREE(parent_dir_src);
6522 TALLOC_FREE(parent_dir_dst);
6525 /****************************************************************************
6526 Returns an error if the parent directory for a filename is open in an
6527 incompatible way.
6528 ****************************************************************************/
6530 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
6531 const struct smb_filename *smb_fname_dst_in)
6533 char *parent_dir = NULL;
6534 struct smb_filename smb_fname_parent;
6535 struct file_id id;
6536 files_struct *fsp = NULL;
6537 int ret;
6539 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
6540 &parent_dir, NULL)) {
6541 return NT_STATUS_NO_MEMORY;
6543 ZERO_STRUCT(smb_fname_parent);
6544 smb_fname_parent.base_name = parent_dir;
6546 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
6547 if (ret == -1) {
6548 return map_nt_error_from_unix(errno);
6552 * We're only checking on this smbd here, mostly good
6553 * enough.. and will pass tests.
6556 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
6557 for (fsp = file_find_di_first(conn->sconn, id); fsp;
6558 fsp = file_find_di_next(fsp)) {
6559 if (fsp->access_mask & DELETE_ACCESS) {
6560 return NT_STATUS_SHARING_VIOLATION;
6563 return NT_STATUS_OK;
6566 /****************************************************************************
6567 Rename an open file - given an fsp.
6568 ****************************************************************************/
6570 NTSTATUS rename_internals_fsp(connection_struct *conn,
6571 files_struct *fsp,
6572 const struct smb_filename *smb_fname_dst_in,
6573 uint32_t attrs,
6574 bool replace_if_exists)
6576 TALLOC_CTX *ctx = talloc_tos();
6577 struct smb_filename *smb_fname_dst = NULL;
6578 NTSTATUS status = NT_STATUS_OK;
6579 struct share_mode_lock *lck = NULL;
6580 uint32_t access_mask = SEC_DIR_ADD_FILE;
6581 bool dst_exists, old_is_stream, new_is_stream;
6583 status = check_name(conn, smb_fname_dst_in);
6584 if (!NT_STATUS_IS_OK(status)) {
6585 return status;
6588 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
6589 if (!NT_STATUS_IS_OK(status)) {
6590 return status;
6593 /* Make a copy of the dst smb_fname structs */
6595 smb_fname_dst = cp_smb_filename(ctx, smb_fname_dst_in);
6596 if (smb_fname_dst == NULL) {
6597 status = NT_STATUS_NO_MEMORY;
6598 goto out;
6602 * Check for special case with case preserving and not
6603 * case sensitive. If the new last component differs from the original
6604 * last component only by case, then we should allow
6605 * the rename (user is trying to change the case of the
6606 * filename).
6608 if (!conn->case_sensitive && conn->case_preserve &&
6609 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6610 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
6611 char *fname_dst_parent = NULL;
6612 const char *fname_dst_lcomp = NULL;
6613 char *orig_lcomp_path = NULL;
6614 char *orig_lcomp_stream = NULL;
6615 bool ok = true;
6618 * Split off the last component of the processed
6619 * destination name. We will compare this to
6620 * the split components of smb_fname_dst->original_lcomp.
6622 if (!parent_dirname(ctx,
6623 smb_fname_dst->base_name,
6624 &fname_dst_parent,
6625 &fname_dst_lcomp)) {
6626 status = NT_STATUS_NO_MEMORY;
6627 goto out;
6631 * The original_lcomp component contains
6632 * the last_component of the path + stream
6633 * name (if a stream exists).
6635 * Split off the stream name so we
6636 * can check them separately.
6639 if (fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) {
6640 /* POSIX - no stream component. */
6641 orig_lcomp_path = talloc_strdup(ctx,
6642 smb_fname_dst->original_lcomp);
6643 if (orig_lcomp_path == NULL) {
6644 ok = false;
6646 } else {
6647 ok = split_stream_filename(ctx,
6648 smb_fname_dst->original_lcomp,
6649 &orig_lcomp_path,
6650 &orig_lcomp_stream);
6653 if (!ok) {
6654 TALLOC_FREE(fname_dst_parent);
6655 status = NT_STATUS_NO_MEMORY;
6656 goto out;
6659 /* If the base names only differ by case, use original. */
6660 if(!strcsequal(fname_dst_lcomp, orig_lcomp_path)) {
6661 char *tmp;
6663 * Replace the modified last component with the
6664 * original.
6666 if (!ISDOT(fname_dst_parent)) {
6667 tmp = talloc_asprintf(smb_fname_dst,
6668 "%s/%s",
6669 fname_dst_parent,
6670 orig_lcomp_path);
6671 } else {
6672 tmp = talloc_strdup(smb_fname_dst,
6673 orig_lcomp_path);
6675 if (tmp == NULL) {
6676 status = NT_STATUS_NO_MEMORY;
6677 TALLOC_FREE(fname_dst_parent);
6678 TALLOC_FREE(orig_lcomp_path);
6679 TALLOC_FREE(orig_lcomp_stream);
6680 goto out;
6682 TALLOC_FREE(smb_fname_dst->base_name);
6683 smb_fname_dst->base_name = tmp;
6686 /* If the stream_names only differ by case, use original. */
6687 if(!strcsequal(smb_fname_dst->stream_name,
6688 orig_lcomp_stream)) {
6689 /* Use the original stream. */
6690 char *tmp = talloc_strdup(smb_fname_dst,
6691 orig_lcomp_stream);
6692 if (tmp == NULL) {
6693 status = NT_STATUS_NO_MEMORY;
6694 TALLOC_FREE(fname_dst_parent);
6695 TALLOC_FREE(orig_lcomp_path);
6696 TALLOC_FREE(orig_lcomp_stream);
6697 goto out;
6699 TALLOC_FREE(smb_fname_dst->stream_name);
6700 smb_fname_dst->stream_name = tmp;
6702 TALLOC_FREE(fname_dst_parent);
6703 TALLOC_FREE(orig_lcomp_path);
6704 TALLOC_FREE(orig_lcomp_stream);
6708 * If the src and dest names are identical - including case,
6709 * don't do the rename, just return success.
6712 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6713 strcsequal(fsp->fsp_name->stream_name,
6714 smb_fname_dst->stream_name)) {
6715 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6716 "- returning success\n",
6717 smb_fname_str_dbg(smb_fname_dst)));
6718 status = NT_STATUS_OK;
6719 goto out;
6722 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6723 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6725 /* Return the correct error code if both names aren't streams. */
6726 if (!old_is_stream && new_is_stream) {
6727 status = NT_STATUS_OBJECT_NAME_INVALID;
6728 goto out;
6731 if (old_is_stream && !new_is_stream) {
6732 status = NT_STATUS_INVALID_PARAMETER;
6733 goto out;
6736 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6738 if(!replace_if_exists && dst_exists) {
6739 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6740 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6741 smb_fname_str_dbg(smb_fname_dst)));
6742 status = NT_STATUS_OBJECT_NAME_COLLISION;
6743 goto out;
6746 if (dst_exists) {
6747 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6748 &smb_fname_dst->st);
6749 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6750 fileid);
6751 /* The file can be open when renaming a stream */
6752 if (dst_fsp && !new_is_stream) {
6753 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6754 status = NT_STATUS_ACCESS_DENIED;
6755 goto out;
6759 /* Ensure we have a valid stat struct for the source. */
6760 status = vfs_stat_fsp(fsp);
6761 if (!NT_STATUS_IS_OK(status)) {
6762 goto out;
6765 status = can_rename(conn, fsp, attrs);
6767 if (!NT_STATUS_IS_OK(status)) {
6768 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6769 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6770 smb_fname_str_dbg(smb_fname_dst)));
6771 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6772 status = NT_STATUS_ACCESS_DENIED;
6773 goto out;
6776 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6777 status = NT_STATUS_ACCESS_DENIED;
6778 goto out;
6781 /* Do we have rights to move into the destination ? */
6782 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
6783 /* We're moving a directory. */
6784 access_mask = SEC_DIR_ADD_SUBDIR;
6786 status = check_parent_access(conn,
6787 smb_fname_dst,
6788 access_mask);
6789 if (!NT_STATUS_IS_OK(status)) {
6790 DBG_INFO("check_parent_access on "
6791 "dst %s returned %s\n",
6792 smb_fname_str_dbg(smb_fname_dst),
6793 nt_errstr(status));
6794 goto out;
6797 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
6800 * We have the file open ourselves, so not being able to get the
6801 * corresponding share mode lock is a fatal error.
6804 SMB_ASSERT(lck != NULL);
6806 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6807 uint32_t create_options = fsp->fh->private_options;
6809 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6810 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6811 smb_fname_str_dbg(smb_fname_dst)));
6813 if (!fsp->is_directory &&
6814 !(fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) &&
6815 (lp_map_archive(SNUM(conn)) ||
6816 lp_store_dos_attributes(SNUM(conn)))) {
6817 /* We must set the archive bit on the newly
6818 renamed file. */
6819 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6820 uint32_t old_dosmode = dos_mode(conn,
6821 smb_fname_dst);
6822 file_set_dosmode(conn,
6823 smb_fname_dst,
6824 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6825 NULL,
6826 true);
6830 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6831 smb_fname_dst);
6833 rename_open_files(conn, lck, fsp->file_id, fsp->name_hash,
6834 smb_fname_dst);
6837 * A rename acts as a new file create w.r.t. allowing an initial delete
6838 * on close, probably because in Windows there is a new handle to the
6839 * new file. If initial delete on close was requested but not
6840 * originally set, we need to set it here. This is probably not 100% correct,
6841 * but will work for the CIFSFS client which in non-posix mode
6842 * depends on these semantics. JRA.
6845 if (create_options & FILE_DELETE_ON_CLOSE) {
6846 status = can_set_delete_on_close(fsp, 0);
6848 if (NT_STATUS_IS_OK(status)) {
6849 /* Note that here we set the *inital* delete on close flag,
6850 * not the regular one. The magic gets handled in close. */
6851 fsp->initial_delete_on_close = True;
6854 TALLOC_FREE(lck);
6855 status = NT_STATUS_OK;
6856 goto out;
6859 TALLOC_FREE(lck);
6861 if (errno == ENOTDIR || errno == EISDIR) {
6862 status = NT_STATUS_OBJECT_NAME_COLLISION;
6863 } else {
6864 status = map_nt_error_from_unix(errno);
6867 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6868 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6869 smb_fname_str_dbg(smb_fname_dst)));
6871 out:
6872 TALLOC_FREE(smb_fname_dst);
6874 return status;
6877 /****************************************************************************
6878 The guts of the rename command, split out so it may be called by the NT SMB
6879 code.
6880 ****************************************************************************/
6882 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6883 connection_struct *conn,
6884 struct smb_request *req,
6885 struct smb_filename *smb_fname_src,
6886 struct smb_filename *smb_fname_dst,
6887 uint32_t attrs,
6888 bool replace_if_exists,
6889 bool src_has_wild,
6890 bool dest_has_wild,
6891 uint32_t access_mask)
6893 char *fname_src_dir = NULL;
6894 struct smb_filename *smb_fname_src_dir = NULL;
6895 char *fname_src_mask = NULL;
6896 int count=0;
6897 NTSTATUS status = NT_STATUS_OK;
6898 struct smb_Dir *dir_hnd = NULL;
6899 const char *dname = NULL;
6900 char *talloced = NULL;
6901 long offset = 0;
6902 int create_options = 0;
6903 bool posix_pathnames = (req != NULL && req->posix_pathnames);
6904 int rc;
6907 * Split the old name into directory and last component
6908 * strings. Note that unix_convert may have stripped off a
6909 * leading ./ from both name and newname if the rename is
6910 * at the root of the share. We need to make sure either both
6911 * name and newname contain a / character or neither of them do
6912 * as this is checked in resolve_wildcards().
6915 /* Split up the directory from the filename/mask. */
6916 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6917 &fname_src_dir, &fname_src_mask);
6918 if (!NT_STATUS_IS_OK(status)) {
6919 status = NT_STATUS_NO_MEMORY;
6920 goto out;
6924 * We should only check the mangled cache
6925 * here if unix_convert failed. This means
6926 * that the path in 'mask' doesn't exist
6927 * on the file system and so we need to look
6928 * for a possible mangle. This patch from
6929 * Tine Smukavec <valentin.smukavec@hermes.si>.
6932 if (!VALID_STAT(smb_fname_src->st) &&
6933 mangle_is_mangled(fname_src_mask, conn->params)) {
6934 char *new_mask = NULL;
6935 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6936 conn->params);
6937 if (new_mask) {
6938 TALLOC_FREE(fname_src_mask);
6939 fname_src_mask = new_mask;
6943 if (!src_has_wild) {
6944 files_struct *fsp;
6947 * Only one file needs to be renamed. Append the mask back
6948 * onto the directory.
6950 TALLOC_FREE(smb_fname_src->base_name);
6951 if (ISDOT(fname_src_dir)) {
6952 /* Ensure we use canonical names on open. */
6953 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6954 "%s",
6955 fname_src_mask);
6956 } else {
6957 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6958 "%s/%s",
6959 fname_src_dir,
6960 fname_src_mask);
6962 if (!smb_fname_src->base_name) {
6963 status = NT_STATUS_NO_MEMORY;
6964 goto out;
6967 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6968 "case_preserve = %d, short case preserve = %d, "
6969 "directory = %s, newname = %s, "
6970 "last_component_dest = %s\n",
6971 conn->case_sensitive, conn->case_preserve,
6972 conn->short_case_preserve,
6973 smb_fname_str_dbg(smb_fname_src),
6974 smb_fname_str_dbg(smb_fname_dst),
6975 smb_fname_dst->original_lcomp));
6977 /* The dest name still may have wildcards. */
6978 if (dest_has_wild) {
6979 char *fname_dst_mod = NULL;
6980 if (!resolve_wildcards(smb_fname_dst,
6981 smb_fname_src->base_name,
6982 smb_fname_dst->base_name,
6983 &fname_dst_mod)) {
6984 DEBUG(6, ("rename_internals: resolve_wildcards "
6985 "%s %s failed\n",
6986 smb_fname_src->base_name,
6987 smb_fname_dst->base_name));
6988 status = NT_STATUS_NO_MEMORY;
6989 goto out;
6991 TALLOC_FREE(smb_fname_dst->base_name);
6992 smb_fname_dst->base_name = fname_dst_mod;
6995 ZERO_STRUCT(smb_fname_src->st);
6996 if (posix_pathnames) {
6997 rc = SMB_VFS_LSTAT(conn, smb_fname_src);
6998 } else {
6999 rc = SMB_VFS_STAT(conn, smb_fname_src);
7001 if (rc == -1) {
7002 status = map_nt_error_from_unix_common(errno);
7003 goto out;
7006 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
7007 create_options |= FILE_DIRECTORY_FILE;
7010 status = SMB_VFS_CREATE_FILE(
7011 conn, /* conn */
7012 req, /* req */
7013 0, /* root_dir_fid */
7014 smb_fname_src, /* fname */
7015 access_mask, /* access_mask */
7016 (FILE_SHARE_READ | /* share_access */
7017 FILE_SHARE_WRITE),
7018 FILE_OPEN, /* create_disposition*/
7019 create_options, /* create_options */
7020 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
7021 0, /* oplock_request */
7022 NULL, /* lease */
7023 0, /* allocation_size */
7024 0, /* private_flags */
7025 NULL, /* sd */
7026 NULL, /* ea_list */
7027 &fsp, /* result */
7028 NULL, /* pinfo */
7029 NULL, NULL); /* create context */
7031 if (!NT_STATUS_IS_OK(status)) {
7032 DEBUG(3, ("Could not open rename source %s: %s\n",
7033 smb_fname_str_dbg(smb_fname_src),
7034 nt_errstr(status)));
7035 goto out;
7038 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
7039 attrs, replace_if_exists);
7041 close_file(req, fsp, NORMAL_CLOSE);
7043 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
7044 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
7045 smb_fname_str_dbg(smb_fname_dst)));
7047 goto out;
7051 * Wildcards - process each file that matches.
7053 if (strequal(fname_src_mask, "????????.???")) {
7054 TALLOC_FREE(fname_src_mask);
7055 fname_src_mask = talloc_strdup(ctx, "*");
7056 if (!fname_src_mask) {
7057 status = NT_STATUS_NO_MEMORY;
7058 goto out;
7062 smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
7063 fname_src_dir,
7064 NULL,
7065 NULL,
7066 smb_fname_src->flags);
7067 if (smb_fname_src_dir == NULL) {
7068 status = NT_STATUS_NO_MEMORY;
7069 goto out;
7072 status = check_name(conn, smb_fname_src_dir);
7073 if (!NT_STATUS_IS_OK(status)) {
7074 goto out;
7077 dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_src_dir, fname_src_mask,
7078 attrs);
7079 if (dir_hnd == NULL) {
7080 status = map_nt_error_from_unix(errno);
7081 goto out;
7084 status = NT_STATUS_NO_SUCH_FILE;
7086 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
7087 * - gentest fix. JRA
7090 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
7091 &talloced))) {
7092 files_struct *fsp = NULL;
7093 char *destname = NULL;
7094 bool sysdir_entry = False;
7096 /* Quick check for "." and ".." */
7097 if (ISDOT(dname) || ISDOTDOT(dname)) {
7098 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
7099 sysdir_entry = True;
7100 } else {
7101 TALLOC_FREE(talloced);
7102 continue;
7106 if (!is_visible_file(conn, fname_src_dir, dname,
7107 &smb_fname_src->st, false)) {
7108 TALLOC_FREE(talloced);
7109 continue;
7112 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
7113 TALLOC_FREE(talloced);
7114 continue;
7117 if (sysdir_entry) {
7118 status = NT_STATUS_OBJECT_NAME_INVALID;
7119 break;
7122 TALLOC_FREE(smb_fname_src->base_name);
7123 if (ISDOT(fname_src_dir)) {
7124 /* Ensure we use canonical names on open. */
7125 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7126 "%s",
7127 dname);
7128 } else {
7129 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7130 "%s/%s",
7131 fname_src_dir,
7132 dname);
7134 if (!smb_fname_src->base_name) {
7135 status = NT_STATUS_NO_MEMORY;
7136 goto out;
7139 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7140 smb_fname_dst->base_name,
7141 &destname)) {
7142 DEBUG(6, ("resolve_wildcards %s %s failed\n",
7143 smb_fname_src->base_name, destname));
7144 TALLOC_FREE(talloced);
7145 continue;
7147 if (!destname) {
7148 status = NT_STATUS_NO_MEMORY;
7149 goto out;
7152 TALLOC_FREE(smb_fname_dst->base_name);
7153 smb_fname_dst->base_name = destname;
7155 ZERO_STRUCT(smb_fname_src->st);
7156 if (posix_pathnames) {
7157 SMB_VFS_LSTAT(conn, smb_fname_src);
7158 } else {
7159 SMB_VFS_STAT(conn, smb_fname_src);
7162 create_options = 0;
7164 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
7165 create_options |= FILE_DIRECTORY_FILE;
7168 status = SMB_VFS_CREATE_FILE(
7169 conn, /* conn */
7170 req, /* req */
7171 0, /* root_dir_fid */
7172 smb_fname_src, /* fname */
7173 access_mask, /* access_mask */
7174 (FILE_SHARE_READ | /* share_access */
7175 FILE_SHARE_WRITE),
7176 FILE_OPEN, /* create_disposition*/
7177 create_options, /* create_options */
7178 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
7179 0, /* oplock_request */
7180 NULL, /* lease */
7181 0, /* allocation_size */
7182 0, /* private_flags */
7183 NULL, /* sd */
7184 NULL, /* ea_list */
7185 &fsp, /* result */
7186 NULL, /* pinfo */
7187 NULL, NULL); /* create context */
7189 if (!NT_STATUS_IS_OK(status)) {
7190 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
7191 "returned %s rename %s -> %s\n",
7192 nt_errstr(status),
7193 smb_fname_str_dbg(smb_fname_src),
7194 smb_fname_str_dbg(smb_fname_dst)));
7195 break;
7198 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
7199 dname);
7200 if (!smb_fname_dst->original_lcomp) {
7201 status = NT_STATUS_NO_MEMORY;
7202 goto out;
7205 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
7206 attrs, replace_if_exists);
7208 close_file(req, fsp, NORMAL_CLOSE);
7210 if (!NT_STATUS_IS_OK(status)) {
7211 DEBUG(3, ("rename_internals_fsp returned %s for "
7212 "rename %s -> %s\n", nt_errstr(status),
7213 smb_fname_str_dbg(smb_fname_src),
7214 smb_fname_str_dbg(smb_fname_dst)));
7215 break;
7218 count++;
7220 DEBUG(3,("rename_internals: doing rename on %s -> "
7221 "%s\n", smb_fname_str_dbg(smb_fname_src),
7222 smb_fname_str_dbg(smb_fname_src)));
7223 TALLOC_FREE(talloced);
7225 TALLOC_FREE(dir_hnd);
7227 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
7228 status = map_nt_error_from_unix(errno);
7231 out:
7232 TALLOC_FREE(talloced);
7233 TALLOC_FREE(smb_fname_src_dir);
7234 TALLOC_FREE(fname_src_dir);
7235 TALLOC_FREE(fname_src_mask);
7236 return status;
7239 /****************************************************************************
7240 Reply to a mv.
7241 ****************************************************************************/
7243 void reply_mv(struct smb_request *req)
7245 connection_struct *conn = req->conn;
7246 char *name = NULL;
7247 char *newname = NULL;
7248 const char *p;
7249 uint32_t attrs;
7250 NTSTATUS status;
7251 bool src_has_wcard = False;
7252 bool dest_has_wcard = False;
7253 TALLOC_CTX *ctx = talloc_tos();
7254 struct smb_filename *smb_fname_src = NULL;
7255 struct smb_filename *smb_fname_dst = NULL;
7256 uint32_t src_ucf_flags = ucf_flags_from_smb_request(req) |
7257 (req->posix_pathnames ?
7258 UCF_UNIX_NAME_LOOKUP :
7259 UCF_COND_ALLOW_WCARD_LCOMP);
7260 uint32_t dst_ucf_flags = ucf_flags_from_smb_request(req) |
7261 UCF_SAVE_LCOMP |
7262 (req->posix_pathnames ?
7264 UCF_COND_ALLOW_WCARD_LCOMP);
7265 bool stream_rename = false;
7267 START_PROFILE(SMBmv);
7269 if (req->wct < 1) {
7270 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7271 goto out;
7274 attrs = SVAL(req->vwv+0, 0);
7276 p = (const char *)req->buf + 1;
7277 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
7278 &status, &src_has_wcard);
7279 if (!NT_STATUS_IS_OK(status)) {
7280 reply_nterror(req, status);
7281 goto out;
7283 p++;
7284 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
7285 &status, &dest_has_wcard);
7286 if (!NT_STATUS_IS_OK(status)) {
7287 reply_nterror(req, status);
7288 goto out;
7291 if (!req->posix_pathnames) {
7292 /* The newname must begin with a ':' if the
7293 name contains a ':'. */
7294 if (strchr_m(name, ':')) {
7295 if (newname[0] != ':') {
7296 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7297 goto out;
7299 stream_rename = true;
7303 status = filename_convert(ctx,
7304 conn,
7305 name,
7306 src_ucf_flags,
7307 &src_has_wcard,
7308 &smb_fname_src);
7310 if (!NT_STATUS_IS_OK(status)) {
7311 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7312 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7313 ERRSRV, ERRbadpath);
7314 goto out;
7316 reply_nterror(req, status);
7317 goto out;
7320 status = filename_convert(ctx,
7321 conn,
7322 newname,
7323 dst_ucf_flags,
7324 &dest_has_wcard,
7325 &smb_fname_dst);
7327 if (!NT_STATUS_IS_OK(status)) {
7328 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7329 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7330 ERRSRV, ERRbadpath);
7331 goto out;
7333 reply_nterror(req, status);
7334 goto out;
7337 if (stream_rename) {
7338 /* smb_fname_dst->base_name must be the same as
7339 smb_fname_src->base_name. */
7340 TALLOC_FREE(smb_fname_dst->base_name);
7341 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
7342 smb_fname_src->base_name);
7343 if (!smb_fname_dst->base_name) {
7344 reply_nterror(req, NT_STATUS_NO_MEMORY);
7345 goto out;
7349 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
7350 smb_fname_str_dbg(smb_fname_dst)));
7352 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
7353 attrs, False, src_has_wcard, dest_has_wcard,
7354 DELETE_ACCESS);
7355 if (!NT_STATUS_IS_OK(status)) {
7356 if (open_was_deferred(req->xconn, req->mid)) {
7357 /* We have re-scheduled this call. */
7358 goto out;
7360 reply_nterror(req, status);
7361 goto out;
7364 reply_outbuf(req, 0, 0);
7365 out:
7366 TALLOC_FREE(smb_fname_src);
7367 TALLOC_FREE(smb_fname_dst);
7368 END_PROFILE(SMBmv);
7369 return;
7372 /*******************************************************************
7373 Copy a file as part of a reply_copy.
7374 ******************************************************************/
7377 * TODO: check error codes on all callers
7380 NTSTATUS copy_file(TALLOC_CTX *ctx,
7381 connection_struct *conn,
7382 struct smb_filename *smb_fname_src,
7383 struct smb_filename *smb_fname_dst,
7384 int ofun,
7385 int count,
7386 bool target_is_directory)
7388 struct smb_filename *smb_fname_dst_tmp = NULL;
7389 off_t ret=-1;
7390 files_struct *fsp1,*fsp2;
7391 uint32_t dosattrs;
7392 uint32_t new_create_disposition;
7393 NTSTATUS status;
7396 smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
7397 if (smb_fname_dst_tmp == NULL) {
7398 return NT_STATUS_NO_MEMORY;
7402 * If the target is a directory, extract the last component from the
7403 * src filename and append it to the dst filename
7405 if (target_is_directory) {
7406 const char *p;
7408 /* dest/target can't be a stream if it's a directory. */
7409 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
7411 p = strrchr_m(smb_fname_src->base_name,'/');
7412 if (p) {
7413 p++;
7414 } else {
7415 p = smb_fname_src->base_name;
7417 smb_fname_dst_tmp->base_name =
7418 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
7420 if (!smb_fname_dst_tmp->base_name) {
7421 status = NT_STATUS_NO_MEMORY;
7422 goto out;
7426 status = vfs_file_exist(conn, smb_fname_src);
7427 if (!NT_STATUS_IS_OK(status)) {
7428 goto out;
7431 if (!target_is_directory && count) {
7432 new_create_disposition = FILE_OPEN;
7433 } else {
7434 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
7435 0, ofun,
7436 NULL, NULL,
7437 &new_create_disposition,
7438 NULL,
7439 NULL)) {
7440 status = NT_STATUS_INVALID_PARAMETER;
7441 goto out;
7445 /* Open the src file for reading. */
7446 status = SMB_VFS_CREATE_FILE(
7447 conn, /* conn */
7448 NULL, /* req */
7449 0, /* root_dir_fid */
7450 smb_fname_src, /* fname */
7451 FILE_GENERIC_READ, /* access_mask */
7452 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7453 FILE_OPEN, /* create_disposition*/
7454 0, /* create_options */
7455 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
7456 INTERNAL_OPEN_ONLY, /* oplock_request */
7457 NULL, /* lease */
7458 0, /* allocation_size */
7459 0, /* private_flags */
7460 NULL, /* sd */
7461 NULL, /* ea_list */
7462 &fsp1, /* result */
7463 NULL, /* psbuf */
7464 NULL, NULL); /* create context */
7466 if (!NT_STATUS_IS_OK(status)) {
7467 goto out;
7470 dosattrs = dos_mode(conn, smb_fname_src);
7472 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
7473 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
7476 /* Open the dst file for writing. */
7477 status = SMB_VFS_CREATE_FILE(
7478 conn, /* conn */
7479 NULL, /* req */
7480 0, /* root_dir_fid */
7481 smb_fname_dst, /* fname */
7482 FILE_GENERIC_WRITE, /* access_mask */
7483 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7484 new_create_disposition, /* create_disposition*/
7485 0, /* create_options */
7486 dosattrs, /* file_attributes */
7487 INTERNAL_OPEN_ONLY, /* oplock_request */
7488 NULL, /* lease */
7489 0, /* allocation_size */
7490 0, /* private_flags */
7491 NULL, /* sd */
7492 NULL, /* ea_list */
7493 &fsp2, /* result */
7494 NULL, /* psbuf */
7495 NULL, NULL); /* create context */
7497 if (!NT_STATUS_IS_OK(status)) {
7498 close_file(NULL, fsp1, ERROR_CLOSE);
7499 goto out;
7502 if (ofun & OPENX_FILE_EXISTS_OPEN) {
7503 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
7504 if (ret == -1) {
7505 DEBUG(0, ("error - vfs lseek returned error %s\n",
7506 strerror(errno)));
7507 status = map_nt_error_from_unix(errno);
7508 close_file(NULL, fsp1, ERROR_CLOSE);
7509 close_file(NULL, fsp2, ERROR_CLOSE);
7510 goto out;
7514 /* Do the actual copy. */
7515 if (smb_fname_src->st.st_ex_size) {
7516 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
7517 } else {
7518 ret = 0;
7521 close_file(NULL, fsp1, NORMAL_CLOSE);
7523 /* Ensure the modtime is set correctly on the destination file. */
7524 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
7527 * As we are opening fsp1 read-only we only expect
7528 * an error on close on fsp2 if we are out of space.
7529 * Thus we don't look at the error return from the
7530 * close of fsp1.
7532 status = close_file(NULL, fsp2, NORMAL_CLOSE);
7534 if (!NT_STATUS_IS_OK(status)) {
7535 goto out;
7538 if (ret != (off_t)smb_fname_src->st.st_ex_size) {
7539 status = NT_STATUS_DISK_FULL;
7540 goto out;
7543 status = NT_STATUS_OK;
7545 out:
7546 TALLOC_FREE(smb_fname_dst_tmp);
7547 return status;
7550 /****************************************************************************
7551 Reply to a file copy.
7552 ****************************************************************************/
7554 void reply_copy(struct smb_request *req)
7556 connection_struct *conn = req->conn;
7557 struct smb_filename *smb_fname_src = NULL;
7558 struct smb_filename *smb_fname_src_dir = NULL;
7559 struct smb_filename *smb_fname_dst = NULL;
7560 char *fname_src = NULL;
7561 char *fname_dst = NULL;
7562 char *fname_src_mask = NULL;
7563 char *fname_src_dir = NULL;
7564 const char *p;
7565 int count=0;
7566 int error = ERRnoaccess;
7567 int tid2;
7568 int ofun;
7569 int flags;
7570 bool target_is_directory=False;
7571 bool source_has_wild = False;
7572 bool dest_has_wild = False;
7573 NTSTATUS status;
7574 uint32_t ucf_flags_src = UCF_COND_ALLOW_WCARD_LCOMP |
7575 ucf_flags_from_smb_request(req);
7576 uint32_t ucf_flags_dst = UCF_COND_ALLOW_WCARD_LCOMP |
7577 ucf_flags_from_smb_request(req);
7578 TALLOC_CTX *ctx = talloc_tos();
7580 START_PROFILE(SMBcopy);
7582 if (req->wct < 3) {
7583 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7584 goto out;
7587 tid2 = SVAL(req->vwv+0, 0);
7588 ofun = SVAL(req->vwv+1, 0);
7589 flags = SVAL(req->vwv+2, 0);
7591 p = (const char *)req->buf;
7592 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
7593 &status, &source_has_wild);
7594 if (!NT_STATUS_IS_OK(status)) {
7595 reply_nterror(req, status);
7596 goto out;
7598 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
7599 &status, &dest_has_wild);
7600 if (!NT_STATUS_IS_OK(status)) {
7601 reply_nterror(req, status);
7602 goto out;
7605 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
7607 if (tid2 != conn->cnum) {
7608 /* can't currently handle inter share copies XXXX */
7609 DEBUG(3,("Rejecting inter-share copy\n"));
7610 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
7611 goto out;
7614 status = filename_convert(ctx, conn,
7615 fname_src,
7616 ucf_flags_src,
7617 &source_has_wild,
7618 &smb_fname_src);
7619 if (!NT_STATUS_IS_OK(status)) {
7620 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7621 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7622 ERRSRV, ERRbadpath);
7623 goto out;
7625 reply_nterror(req, status);
7626 goto out;
7629 status = filename_convert(ctx, conn,
7630 fname_dst,
7631 ucf_flags_dst,
7632 &dest_has_wild,
7633 &smb_fname_dst);
7634 if (!NT_STATUS_IS_OK(status)) {
7635 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7636 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7637 ERRSRV, ERRbadpath);
7638 goto out;
7640 reply_nterror(req, status);
7641 goto out;
7644 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
7646 if ((flags&1) && target_is_directory) {
7647 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
7648 goto out;
7651 if ((flags&2) && !target_is_directory) {
7652 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
7653 goto out;
7656 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
7657 /* wants a tree copy! XXXX */
7658 DEBUG(3,("Rejecting tree copy\n"));
7659 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7660 goto out;
7663 /* Split up the directory from the filename/mask. */
7664 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7665 &fname_src_dir, &fname_src_mask);
7666 if (!NT_STATUS_IS_OK(status)) {
7667 reply_nterror(req, NT_STATUS_NO_MEMORY);
7668 goto out;
7672 * We should only check the mangled cache
7673 * here if unix_convert failed. This means
7674 * that the path in 'mask' doesn't exist
7675 * on the file system and so we need to look
7676 * for a possible mangle. This patch from
7677 * Tine Smukavec <valentin.smukavec@hermes.si>.
7679 if (!VALID_STAT(smb_fname_src->st) &&
7680 mangle_is_mangled(fname_src_mask, conn->params)) {
7681 char *new_mask = NULL;
7682 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
7683 &new_mask, conn->params);
7685 /* Use demangled name if one was successfully found. */
7686 if (new_mask) {
7687 TALLOC_FREE(fname_src_mask);
7688 fname_src_mask = new_mask;
7692 if (!source_has_wild) {
7695 * Only one file needs to be copied. Append the mask back onto
7696 * the directory.
7698 TALLOC_FREE(smb_fname_src->base_name);
7699 if (ISDOT(fname_src_dir)) {
7700 /* Ensure we use canonical names on open. */
7701 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7702 "%s",
7703 fname_src_mask);
7704 } else {
7705 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7706 "%s/%s",
7707 fname_src_dir,
7708 fname_src_mask);
7710 if (!smb_fname_src->base_name) {
7711 reply_nterror(req, NT_STATUS_NO_MEMORY);
7712 goto out;
7715 if (dest_has_wild) {
7716 char *fname_dst_mod = NULL;
7717 if (!resolve_wildcards(smb_fname_dst,
7718 smb_fname_src->base_name,
7719 smb_fname_dst->base_name,
7720 &fname_dst_mod)) {
7721 reply_nterror(req, NT_STATUS_NO_MEMORY);
7722 goto out;
7724 TALLOC_FREE(smb_fname_dst->base_name);
7725 smb_fname_dst->base_name = fname_dst_mod;
7728 status = check_name(conn, smb_fname_src);
7729 if (!NT_STATUS_IS_OK(status)) {
7730 reply_nterror(req, status);
7731 goto out;
7734 status = check_name(conn, smb_fname_dst);
7735 if (!NT_STATUS_IS_OK(status)) {
7736 reply_nterror(req, status);
7737 goto out;
7740 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7741 ofun, count, target_is_directory);
7743 if(!NT_STATUS_IS_OK(status)) {
7744 reply_nterror(req, status);
7745 goto out;
7746 } else {
7747 count++;
7749 } else {
7750 struct smb_Dir *dir_hnd = NULL;
7751 const char *dname = NULL;
7752 char *talloced = NULL;
7753 long offset = 0;
7756 * There is a wildcard that requires us to actually read the
7757 * src dir and copy each file matching the mask to the dst.
7758 * Right now streams won't be copied, but this could
7759 * presumably be added with a nested loop for reach dir entry.
7761 SMB_ASSERT(!smb_fname_src->stream_name);
7762 SMB_ASSERT(!smb_fname_dst->stream_name);
7764 smb_fname_src->stream_name = NULL;
7765 smb_fname_dst->stream_name = NULL;
7767 if (strequal(fname_src_mask,"????????.???")) {
7768 TALLOC_FREE(fname_src_mask);
7769 fname_src_mask = talloc_strdup(ctx, "*");
7770 if (!fname_src_mask) {
7771 reply_nterror(req, NT_STATUS_NO_MEMORY);
7772 goto out;
7776 smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
7777 fname_src_dir,
7778 NULL,
7779 NULL,
7780 smb_fname_src->flags);
7781 if (smb_fname_src_dir == NULL) {
7782 reply_nterror(req, NT_STATUS_NO_MEMORY);
7783 goto out;
7786 status = check_name(conn, smb_fname_src_dir);
7787 if (!NT_STATUS_IS_OK(status)) {
7788 reply_nterror(req, status);
7789 goto out;
7792 dir_hnd = OpenDir(ctx,
7793 conn,
7794 smb_fname_src_dir,
7795 fname_src_mask,
7797 if (dir_hnd == NULL) {
7798 status = map_nt_error_from_unix(errno);
7799 reply_nterror(req, status);
7800 goto out;
7803 error = ERRbadfile;
7805 /* Iterate over the src dir copying each entry to the dst. */
7806 while ((dname = ReadDirName(dir_hnd, &offset,
7807 &smb_fname_src->st, &talloced))) {
7808 char *destname = NULL;
7810 if (ISDOT(dname) || ISDOTDOT(dname)) {
7811 TALLOC_FREE(talloced);
7812 continue;
7815 if (!is_visible_file(conn, fname_src_dir, dname,
7816 &smb_fname_src->st, false)) {
7817 TALLOC_FREE(talloced);
7818 continue;
7821 if(!mask_match(dname, fname_src_mask,
7822 conn->case_sensitive)) {
7823 TALLOC_FREE(talloced);
7824 continue;
7827 error = ERRnoaccess;
7829 /* Get the src smb_fname struct setup. */
7830 TALLOC_FREE(smb_fname_src->base_name);
7831 if (ISDOT(fname_src_dir)) {
7832 /* Ensure we use canonical names on open. */
7833 smb_fname_src->base_name =
7834 talloc_asprintf(smb_fname_src, "%s",
7835 dname);
7836 } else {
7837 smb_fname_src->base_name =
7838 talloc_asprintf(smb_fname_src, "%s/%s",
7839 fname_src_dir, dname);
7842 if (!smb_fname_src->base_name) {
7843 TALLOC_FREE(dir_hnd);
7844 TALLOC_FREE(talloced);
7845 reply_nterror(req, NT_STATUS_NO_MEMORY);
7846 goto out;
7849 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7850 smb_fname_dst->base_name,
7851 &destname)) {
7852 TALLOC_FREE(talloced);
7853 continue;
7855 if (!destname) {
7856 TALLOC_FREE(dir_hnd);
7857 TALLOC_FREE(talloced);
7858 reply_nterror(req, NT_STATUS_NO_MEMORY);
7859 goto out;
7862 TALLOC_FREE(smb_fname_dst->base_name);
7863 smb_fname_dst->base_name = destname;
7865 status = check_name(conn, smb_fname_src);
7866 if (!NT_STATUS_IS_OK(status)) {
7867 TALLOC_FREE(dir_hnd);
7868 TALLOC_FREE(talloced);
7869 reply_nterror(req, status);
7870 goto out;
7873 status = check_name(conn, smb_fname_dst);
7874 if (!NT_STATUS_IS_OK(status)) {
7875 TALLOC_FREE(dir_hnd);
7876 TALLOC_FREE(talloced);
7877 reply_nterror(req, status);
7878 goto out;
7881 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7882 smb_fname_src->base_name,
7883 smb_fname_dst->base_name));
7885 status = copy_file(ctx, conn, smb_fname_src,
7886 smb_fname_dst, ofun, count,
7887 target_is_directory);
7888 if (NT_STATUS_IS_OK(status)) {
7889 count++;
7892 TALLOC_FREE(talloced);
7894 TALLOC_FREE(dir_hnd);
7897 if (count == 0) {
7898 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7899 goto out;
7902 reply_outbuf(req, 1, 0);
7903 SSVAL(req->outbuf,smb_vwv0,count);
7904 out:
7905 TALLOC_FREE(smb_fname_src);
7906 TALLOC_FREE(smb_fname_src_dir);
7907 TALLOC_FREE(smb_fname_dst);
7908 TALLOC_FREE(fname_src);
7909 TALLOC_FREE(fname_dst);
7910 TALLOC_FREE(fname_src_mask);
7911 TALLOC_FREE(fname_src_dir);
7913 END_PROFILE(SMBcopy);
7914 return;
7917 #undef DBGC_CLASS
7918 #define DBGC_CLASS DBGC_LOCKING
7920 /****************************************************************************
7921 Get a lock pid, dealing with large count requests.
7922 ****************************************************************************/
7924 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7925 bool large_file_format)
7927 if(!large_file_format)
7928 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7929 else
7930 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7933 /****************************************************************************
7934 Get a lock count, dealing with large count requests.
7935 ****************************************************************************/
7937 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7938 bool large_file_format)
7940 uint64_t count = 0;
7942 if(!large_file_format) {
7943 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7944 } else {
7946 * No BVAL, this is reversed!
7948 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7949 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7952 return count;
7955 /****************************************************************************
7956 Get a lock offset, dealing with large offset requests.
7957 ****************************************************************************/
7959 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7960 bool large_file_format)
7962 uint64_t offset = 0;
7964 if(!large_file_format) {
7965 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7966 } else {
7968 * No BVAL, this is reversed!
7970 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7971 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7974 return offset;
7977 NTSTATUS smbd_do_locking(struct smb_request *req,
7978 files_struct *fsp,
7979 uint8_t type,
7980 int32_t timeout,
7981 uint16_t num_locks,
7982 struct smbd_lock_element *locks,
7983 bool *async)
7985 connection_struct *conn = req->conn;
7986 int i;
7987 NTSTATUS status = NT_STATUS_OK;
7989 *async = false;
7991 /* Setup the timeout in seconds. */
7993 if (!lp_blocking_locks(SNUM(conn))) {
7994 timeout = 0;
7997 for(i = 0; i < (int)num_locks; i++) {
7998 struct smbd_lock_element *e = &locks[i];
8000 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
8001 "%llu, file %s timeout = %d\n",
8002 (double)e->offset,
8003 (double)e->count,
8004 (unsigned long long)e->smblctx,
8005 fsp_str_dbg(fsp),
8006 (int)timeout));
8008 if (type & LOCKING_ANDX_CANCEL_LOCK) {
8009 struct blocking_lock_record *blr = NULL;
8011 if (num_locks > 1) {
8013 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
8014 * if the lock vector contains one entry. When given multiple cancel
8015 * requests in a single PDU we expect the server to return an
8016 * error. Windows servers seem to accept the request but only
8017 * cancel the first lock.
8018 * JRA - Do what Windows does (tm) :-).
8021 #if 0
8022 /* MS-CIFS (2.2.4.32.1) behavior. */
8023 return NT_STATUS_DOS(ERRDOS,
8024 ERRcancelviolation);
8025 #else
8026 /* Windows behavior. */
8027 if (i != 0) {
8028 DEBUG(10,("smbd_do_locking: ignoring subsequent "
8029 "cancel request\n"));
8030 continue;
8032 #endif
8035 if (lp_blocking_locks(SNUM(conn))) {
8037 /* Schedule a message to ourselves to
8038 remove the blocking lock record and
8039 return the right error. */
8041 blr = blocking_lock_cancel_smb1(fsp,
8042 e->smblctx,
8043 e->offset,
8044 e->count,
8045 WINDOWS_LOCK,
8046 type,
8047 NT_STATUS_FILE_LOCK_CONFLICT);
8048 if (blr == NULL) {
8049 return NT_STATUS_DOS(
8050 ERRDOS,
8051 ERRcancelviolation);
8054 /* Remove a matching pending lock. */
8055 status = do_lock_cancel(fsp,
8056 e->smblctx,
8057 e->count,
8058 e->offset,
8059 WINDOWS_LOCK);
8060 } else {
8061 bool blocking_lock = timeout ? true : false;
8062 bool defer_lock = false;
8063 struct byte_range_lock *br_lck;
8064 uint64_t block_smblctx;
8066 br_lck = do_lock(req->sconn->msg_ctx,
8067 fsp,
8068 e->smblctx,
8069 e->count,
8070 e->offset,
8071 e->brltype,
8072 WINDOWS_LOCK,
8073 blocking_lock,
8074 &status,
8075 &block_smblctx);
8077 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
8078 /* Windows internal resolution for blocking locks seems
8079 to be about 200ms... Don't wait for less than that. JRA. */
8080 if (timeout != -1 && timeout < lp_lock_spin_time()) {
8081 timeout = lp_lock_spin_time();
8083 defer_lock = true;
8086 /* If a lock sent with timeout of zero would fail, and
8087 * this lock has been requested multiple times,
8088 * according to brl_lock_failed() we convert this
8089 * request to a blocking lock with a timeout of between
8090 * 150 - 300 milliseconds.
8092 * If lp_lock_spin_time() has been set to 0, we skip
8093 * this blocking retry and fail immediately.
8095 * Replacement for do_lock_spin(). JRA. */
8097 if (!req->sconn->using_smb2 &&
8098 br_lck && lp_blocking_locks(SNUM(conn)) &&
8099 lp_lock_spin_time() && !blocking_lock &&
8100 NT_STATUS_EQUAL((status),
8101 NT_STATUS_FILE_LOCK_CONFLICT))
8103 defer_lock = true;
8104 timeout = lp_lock_spin_time();
8107 if (br_lck && defer_lock) {
8109 * A blocking lock was requested. Package up
8110 * this smb into a queued request and push it
8111 * onto the blocking lock queue.
8113 if(push_blocking_lock_request(br_lck,
8114 req,
8115 fsp,
8116 timeout,
8118 e->smblctx,
8119 e->brltype,
8120 WINDOWS_LOCK,
8121 e->offset,
8122 e->count,
8123 block_smblctx)) {
8124 TALLOC_FREE(br_lck);
8125 *async = true;
8126 return NT_STATUS_OK;
8130 TALLOC_FREE(br_lck);
8133 if (!NT_STATUS_IS_OK(status)) {
8134 break;
8138 /* If any of the above locks failed, then we must unlock
8139 all of the previous locks (X/Open spec). */
8141 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
8143 if (type & LOCKING_ANDX_CANCEL_LOCK) {
8144 i = -1; /* we want to skip the for loop */
8148 * Ensure we don't do a remove on the lock that just failed,
8149 * as under POSIX rules, if we have a lock already there, we
8150 * will delete it (and we shouldn't) .....
8152 for(i--; i >= 0; i--) {
8153 struct smbd_lock_element *e = &locks[i];
8155 do_unlock(req->sconn->msg_ctx,
8156 fsp,
8157 e->smblctx,
8158 e->count,
8159 e->offset,
8160 WINDOWS_LOCK);
8162 return status;
8165 DEBUG(3, ("smbd_do_locking: %s type=%d num_locks=%d\n",
8166 fsp_fnum_dbg(fsp), (unsigned int)type, num_locks));
8168 return NT_STATUS_OK;
8171 NTSTATUS smbd_do_unlocking(struct smb_request *req,
8172 files_struct *fsp,
8173 uint16_t num_ulocks,
8174 struct smbd_lock_element *ulocks)
8176 int i;
8178 for(i = 0; i < (int)num_ulocks; i++) {
8179 struct smbd_lock_element *e = &ulocks[i];
8180 NTSTATUS status;
8182 DEBUG(10,("%s: unlock start=%.0f, len=%.0f for "
8183 "pid %u, file %s\n", __func__,
8184 (double)e->offset,
8185 (double)e->count,
8186 (unsigned int)e->smblctx,
8187 fsp_str_dbg(fsp)));
8189 if (e->brltype != UNLOCK_LOCK) {
8190 /* this can only happen with SMB2 */
8191 return NT_STATUS_INVALID_PARAMETER;
8194 status = do_unlock(req->sconn->msg_ctx,
8195 fsp,
8196 e->smblctx,
8197 e->count,
8198 e->offset,
8199 WINDOWS_LOCK);
8201 DEBUG(10, ("%s: unlock returned %s\n", __func__,
8202 nt_errstr(status)));
8204 if (!NT_STATUS_IS_OK(status)) {
8205 return status;
8209 DEBUG(3, ("%s: %s num_ulocks=%d\n", __func__, fsp_fnum_dbg(fsp),
8210 num_ulocks));
8212 return NT_STATUS_OK;
8215 /****************************************************************************
8216 Reply to a lockingX request.
8217 ****************************************************************************/
8219 void reply_lockingX(struct smb_request *req)
8221 connection_struct *conn = req->conn;
8222 files_struct *fsp;
8223 unsigned char locktype;
8224 unsigned char oplocklevel;
8225 uint16_t num_ulocks;
8226 uint16_t num_locks;
8227 int32_t lock_timeout;
8228 int i;
8229 const uint8_t *data;
8230 bool large_file_format;
8231 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
8232 struct smbd_lock_element *ulocks;
8233 struct smbd_lock_element *locks;
8234 bool async = false;
8236 START_PROFILE(SMBlockingX);
8238 if (req->wct < 8) {
8239 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8240 END_PROFILE(SMBlockingX);
8241 return;
8244 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
8245 locktype = CVAL(req->vwv+3, 0);
8246 oplocklevel = CVAL(req->vwv+3, 1);
8247 num_ulocks = SVAL(req->vwv+6, 0);
8248 num_locks = SVAL(req->vwv+7, 0);
8249 lock_timeout = IVAL(req->vwv+4, 0);
8250 large_file_format = ((locktype & LOCKING_ANDX_LARGE_FILES) != 0);
8252 if (!check_fsp(conn, req, fsp)) {
8253 END_PROFILE(SMBlockingX);
8254 return;
8257 data = req->buf;
8259 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
8260 /* we don't support these - and CANCEL_LOCK makes w2k
8261 and XP reboot so I don't really want to be
8262 compatible! (tridge) */
8263 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
8264 END_PROFILE(SMBlockingX);
8265 return;
8268 /* Check if this is an oplock break on a file
8269 we have granted an oplock on.
8271 if (locktype & LOCKING_ANDX_OPLOCK_RELEASE) {
8272 /* Client can insist on breaking to none. */
8273 bool break_to_none = (oplocklevel == 0);
8274 bool result;
8276 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
8277 "for %s\n", (unsigned int)oplocklevel,
8278 fsp_fnum_dbg(fsp)));
8281 * Make sure we have granted an exclusive or batch oplock on
8282 * this file.
8285 if (fsp->oplock_type == 0) {
8287 /* The Samba4 nbench simulator doesn't understand
8288 the difference between break to level2 and break
8289 to none from level2 - it sends oplock break
8290 replies in both cases. Don't keep logging an error
8291 message here - just ignore it. JRA. */
8293 DEBUG(5,("reply_lockingX: Error : oplock break from "
8294 "client for %s (oplock=%d) and no "
8295 "oplock granted on this file (%s).\n",
8296 fsp_fnum_dbg(fsp), fsp->oplock_type,
8297 fsp_str_dbg(fsp)));
8299 /* if this is a pure oplock break request then don't
8300 * send a reply */
8301 if (num_locks == 0 && num_ulocks == 0) {
8302 END_PROFILE(SMBlockingX);
8303 return;
8304 } else {
8305 END_PROFILE(SMBlockingX);
8306 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
8307 return;
8311 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
8312 (break_to_none)) {
8313 result = remove_oplock(fsp);
8314 } else {
8315 result = downgrade_oplock(fsp);
8318 if (!result) {
8319 DEBUG(0, ("reply_lockingX: error in removing "
8320 "oplock on file %s\n", fsp_str_dbg(fsp)));
8321 /* Hmmm. Is this panic justified? */
8322 smb_panic("internal tdb error");
8325 /* if this is a pure oplock break request then don't send a
8326 * reply */
8327 if (num_locks == 0 && num_ulocks == 0) {
8328 /* Sanity check - ensure a pure oplock break is not a
8329 chained request. */
8330 if (CVAL(req->vwv+0, 0) != 0xff) {
8331 DEBUG(0,("reply_lockingX: Error : pure oplock "
8332 "break is a chained %d request !\n",
8333 (unsigned int)CVAL(req->vwv+0, 0)));
8335 END_PROFILE(SMBlockingX);
8336 return;
8340 if (req->buflen <
8341 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
8342 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8343 END_PROFILE(SMBlockingX);
8344 return;
8347 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
8348 if (ulocks == NULL) {
8349 reply_nterror(req, NT_STATUS_NO_MEMORY);
8350 END_PROFILE(SMBlockingX);
8351 return;
8354 locks = talloc_array(req, struct smbd_lock_element, num_locks);
8355 if (locks == NULL) {
8356 reply_nterror(req, NT_STATUS_NO_MEMORY);
8357 END_PROFILE(SMBlockingX);
8358 return;
8361 /* Data now points at the beginning of the list
8362 of smb_unlkrng structs */
8363 for(i = 0; i < (int)num_ulocks; i++) {
8364 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
8365 ulocks[i].count = get_lock_count(data, i, large_file_format);
8366 ulocks[i].offset = get_lock_offset(data, i, large_file_format);
8367 ulocks[i].brltype = UNLOCK_LOCK;
8370 /* Now do any requested locks */
8371 data += ((large_file_format ? 20 : 10)*num_ulocks);
8373 /* Data now points at the beginning of the list
8374 of smb_lkrng structs */
8376 for(i = 0; i < (int)num_locks; i++) {
8377 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
8378 locks[i].count = get_lock_count(data, i, large_file_format);
8379 locks[i].offset = get_lock_offset(data, i, large_file_format);
8381 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
8382 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8383 locks[i].brltype = PENDING_READ_LOCK;
8384 } else {
8385 locks[i].brltype = READ_LOCK;
8387 } else {
8388 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
8389 locks[i].brltype = PENDING_WRITE_LOCK;
8390 } else {
8391 locks[i].brltype = WRITE_LOCK;
8396 status = smbd_do_unlocking(req, fsp, num_ulocks, ulocks);
8397 if (!NT_STATUS_IS_OK(status)) {
8398 END_PROFILE(SMBlockingX);
8399 reply_nterror(req, status);
8400 return;
8403 status = smbd_do_locking(req, fsp,
8404 locktype, lock_timeout,
8405 num_locks, locks,
8406 &async);
8407 if (!NT_STATUS_IS_OK(status)) {
8408 END_PROFILE(SMBlockingX);
8409 reply_nterror(req, status);
8410 return;
8412 if (async) {
8413 END_PROFILE(SMBlockingX);
8414 return;
8417 reply_outbuf(req, 2, 0);
8418 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
8419 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
8421 DEBUG(3, ("lockingX %s type=%d num_locks=%d num_ulocks=%d\n",
8422 fsp_fnum_dbg(fsp), (unsigned int)locktype, num_locks, num_ulocks));
8424 END_PROFILE(SMBlockingX);
8427 #undef DBGC_CLASS
8428 #define DBGC_CLASS DBGC_ALL
8430 /****************************************************************************
8431 Reply to a SMBreadbmpx (read block multiplex) request.
8432 Always reply with an error, if someone has a platform really needs this,
8433 please contact vl@samba.org
8434 ****************************************************************************/
8436 void reply_readbmpx(struct smb_request *req)
8438 START_PROFILE(SMBreadBmpx);
8439 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8440 END_PROFILE(SMBreadBmpx);
8441 return;
8444 /****************************************************************************
8445 Reply to a SMBreadbs (read block multiplex secondary) request.
8446 Always reply with an error, if someone has a platform really needs this,
8447 please contact vl@samba.org
8448 ****************************************************************************/
8450 void reply_readbs(struct smb_request *req)
8452 START_PROFILE(SMBreadBs);
8453 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8454 END_PROFILE(SMBreadBs);
8455 return;
8458 /****************************************************************************
8459 Reply to a SMBsetattrE.
8460 ****************************************************************************/
8462 void reply_setattrE(struct smb_request *req)
8464 connection_struct *conn = req->conn;
8465 struct smb_file_time ft;
8466 files_struct *fsp;
8467 NTSTATUS status;
8469 START_PROFILE(SMBsetattrE);
8470 ZERO_STRUCT(ft);
8472 if (req->wct < 7) {
8473 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8474 goto out;
8477 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8479 if(!fsp || (fsp->conn != conn)) {
8480 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8481 goto out;
8485 * Convert the DOS times into unix times.
8488 ft.atime = convert_time_t_to_timespec(
8489 srv_make_unix_date2(req->vwv+3));
8490 ft.mtime = convert_time_t_to_timespec(
8491 srv_make_unix_date2(req->vwv+5));
8492 ft.create_time = convert_time_t_to_timespec(
8493 srv_make_unix_date2(req->vwv+1));
8495 reply_outbuf(req, 0, 0);
8498 * Patch from Ray Frush <frush@engr.colostate.edu>
8499 * Sometimes times are sent as zero - ignore them.
8502 /* Ensure we have a valid stat struct for the source. */
8503 status = vfs_stat_fsp(fsp);
8504 if (!NT_STATUS_IS_OK(status)) {
8505 reply_nterror(req, status);
8506 goto out;
8509 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
8510 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8511 goto out;
8514 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
8515 if (!NT_STATUS_IS_OK(status)) {
8516 reply_nterror(req, status);
8517 goto out;
8520 DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
8521 " createtime=%u\n",
8522 fsp_fnum_dbg(fsp),
8523 (unsigned int)ft.atime.tv_sec,
8524 (unsigned int)ft.mtime.tv_sec,
8525 (unsigned int)ft.create_time.tv_sec
8527 out:
8528 END_PROFILE(SMBsetattrE);
8529 return;
8533 /* Back from the dead for OS/2..... JRA. */
8535 /****************************************************************************
8536 Reply to a SMBwritebmpx (write block multiplex primary) request.
8537 Always reply with an error, if someone has a platform really needs this,
8538 please contact vl@samba.org
8539 ****************************************************************************/
8541 void reply_writebmpx(struct smb_request *req)
8543 START_PROFILE(SMBwriteBmpx);
8544 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8545 END_PROFILE(SMBwriteBmpx);
8546 return;
8549 /****************************************************************************
8550 Reply to a SMBwritebs (write block multiplex secondary) request.
8551 Always reply with an error, if someone has a platform really needs this,
8552 please contact vl@samba.org
8553 ****************************************************************************/
8555 void reply_writebs(struct smb_request *req)
8557 START_PROFILE(SMBwriteBs);
8558 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8559 END_PROFILE(SMBwriteBs);
8560 return;
8563 /****************************************************************************
8564 Reply to a SMBgetattrE.
8565 ****************************************************************************/
8567 void reply_getattrE(struct smb_request *req)
8569 connection_struct *conn = req->conn;
8570 int mode;
8571 files_struct *fsp;
8572 struct timespec create_ts;
8574 START_PROFILE(SMBgetattrE);
8576 if (req->wct < 1) {
8577 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8578 END_PROFILE(SMBgetattrE);
8579 return;
8582 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8584 if(!fsp || (fsp->conn != conn)) {
8585 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8586 END_PROFILE(SMBgetattrE);
8587 return;
8590 /* Do an fstat on this file */
8591 if(fsp_stat(fsp)) {
8592 reply_nterror(req, map_nt_error_from_unix(errno));
8593 END_PROFILE(SMBgetattrE);
8594 return;
8597 mode = dos_mode(conn, fsp->fsp_name);
8600 * Convert the times into dos times. Set create
8601 * date to be last modify date as UNIX doesn't save
8602 * this.
8605 reply_outbuf(req, 11, 0);
8607 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
8608 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
8609 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
8610 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
8611 /* Should we check pending modtime here ? JRA */
8612 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
8613 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
8615 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
8616 SIVAL(req->outbuf, smb_vwv6, 0);
8617 SIVAL(req->outbuf, smb_vwv8, 0);
8618 } else {
8619 uint32_t allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8620 SIVAL(req->outbuf, smb_vwv6, (uint32_t)fsp->fsp_name->st.st_ex_size);
8621 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8623 SSVAL(req->outbuf,smb_vwv10, mode);
8625 DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp)));
8627 END_PROFILE(SMBgetattrE);
8628 return;