s3:smbd: setup the application session key with the first tcon on a session
[Samba.git] / source3 / smbd / reply.c
blob94c18b0c658a6260e806d3f5cffc07a95f0f4fb5
1 /*
2 Unix SMB/CIFS implementation.
3 Main SMB reply routines
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Andrew Bartlett 2001
6 Copyright (C) Jeremy Allison 1992-2007.
7 Copyright (C) Volker Lendecke 2007
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 This file handles most of the reply_ calls that the server
24 makes to handle specific protocols
27 #include "includes.h"
28 #include "system/filesys.h"
29 #include "printing.h"
30 #include "smbd/smbd.h"
31 #include "smbd/globals.h"
32 #include "fake_file.h"
33 #include "rpc_client/rpc_client.h"
34 #include "../librpc/gen_ndr/ndr_spoolss_c.h"
35 #include "../librpc/gen_ndr/open_files.h"
36 #include "rpc_client/cli_spoolss.h"
37 #include "rpc_client/init_spoolss.h"
38 #include "rpc_server/rpc_ncacn_np.h"
39 #include "libcli/security/security.h"
40 #include "libsmb/nmblib.h"
41 #include "auth.h"
42 #include "smbprofile.h"
43 #include "../lib/tsocket/tsocket.h"
44 #include "lib/tevent_wait.h"
46 /****************************************************************************
47 Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
48 path or anything including wildcards.
49 We're assuming here that '/' is not the second byte in any multibyte char
50 set (a safe assumption). '\\' *may* be the second byte in a multibyte char
51 set.
52 ****************************************************************************/
54 /* Custom version for processing POSIX paths. */
55 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
57 static NTSTATUS check_path_syntax_internal(char *path,
58 bool posix_path,
59 bool *p_last_component_contains_wcard)
61 char *d = path;
62 const char *s = path;
63 NTSTATUS ret = NT_STATUS_OK;
64 bool start_of_name_component = True;
65 bool stream_started = false;
67 *p_last_component_contains_wcard = False;
69 while (*s) {
70 if (stream_started) {
71 switch (*s) {
72 case '/':
73 case '\\':
74 return NT_STATUS_OBJECT_NAME_INVALID;
75 case ':':
76 if (s[1] == '\0') {
77 return NT_STATUS_OBJECT_NAME_INVALID;
79 if (strchr_m(&s[1], ':')) {
80 return NT_STATUS_OBJECT_NAME_INVALID;
82 break;
86 if ((*s == ':') && !posix_path && !stream_started) {
87 if (*p_last_component_contains_wcard) {
88 return NT_STATUS_OBJECT_NAME_INVALID;
90 /* Stream names allow more characters than file names.
91 We're overloading posix_path here to allow a wider
92 range of characters. If stream_started is true this
93 is still a Windows path even if posix_path is true.
94 JRA.
96 stream_started = true;
97 start_of_name_component = false;
98 posix_path = true;
100 if (s[1] == '\0') {
101 return NT_STATUS_OBJECT_NAME_INVALID;
105 if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
107 * Safe to assume is not the second part of a mb char
108 * as this is handled below.
110 /* Eat multiple '/' or '\\' */
111 while (IS_PATH_SEP(*s,posix_path)) {
112 s++;
114 if ((d != path) && (*s != '\0')) {
115 /* We only care about non-leading or trailing '/' or '\\' */
116 *d++ = '/';
119 start_of_name_component = True;
120 /* New component. */
121 *p_last_component_contains_wcard = False;
122 continue;
125 if (start_of_name_component) {
126 if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
127 /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
130 * No mb char starts with '.' so we're safe checking the directory separator here.
133 /* If we just added a '/' - delete it */
134 if ((d > path) && (*(d-1) == '/')) {
135 *(d-1) = '\0';
136 d--;
139 /* Are we at the start ? Can't go back further if so. */
140 if (d <= path) {
141 ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
142 break;
144 /* Go back one level... */
145 /* We know this is safe as '/' cannot be part of a mb sequence. */
146 /* NOTE - if this assumption is invalid we are not in good shape... */
147 /* Decrement d first as d points to the *next* char to write into. */
148 for (d--; d > path; d--) {
149 if (*d == '/')
150 break;
152 s += 2; /* Else go past the .. */
153 /* We're still at the start of a name component, just the previous one. */
154 continue;
156 } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
157 if (posix_path) {
158 /* Eat the '.' */
159 s++;
160 continue;
166 if (!(*s & 0x80)) {
167 if (!posix_path) {
168 if (*s <= 0x1f || *s == '|') {
169 return NT_STATUS_OBJECT_NAME_INVALID;
171 switch (*s) {
172 case '*':
173 case '?':
174 case '<':
175 case '>':
176 case '"':
177 *p_last_component_contains_wcard = True;
178 break;
179 default:
180 break;
183 *d++ = *s++;
184 } else {
185 size_t siz;
186 /* Get the size of the next MB character. */
187 next_codepoint(s,&siz);
188 switch(siz) {
189 case 5:
190 *d++ = *s++;
191 /*fall through*/
192 case 4:
193 *d++ = *s++;
194 /*fall through*/
195 case 3:
196 *d++ = *s++;
197 /*fall through*/
198 case 2:
199 *d++ = *s++;
200 /*fall through*/
201 case 1:
202 *d++ = *s++;
203 break;
204 default:
205 DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
206 *d = '\0';
207 return NT_STATUS_INVALID_PARAMETER;
210 start_of_name_component = False;
213 *d = '\0';
215 return ret;
218 /****************************************************************************
219 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
220 No wildcards allowed.
221 ****************************************************************************/
223 NTSTATUS check_path_syntax(char *path)
225 bool ignore;
226 return check_path_syntax_internal(path, False, &ignore);
229 /****************************************************************************
230 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
231 Wildcards allowed - p_contains_wcard returns true if the last component contained
232 a wildcard.
233 ****************************************************************************/
235 NTSTATUS check_path_syntax_wcard(char *path, bool *p_contains_wcard)
237 return check_path_syntax_internal(path, False, p_contains_wcard);
240 /****************************************************************************
241 Check the path for a POSIX client.
242 We're assuming here that '/' is not the second byte in any multibyte char
243 set (a safe assumption).
244 ****************************************************************************/
246 NTSTATUS check_path_syntax_posix(char *path)
248 bool ignore;
249 return check_path_syntax_internal(path, True, &ignore);
252 /****************************************************************************
253 Pull a string and check the path allowing a wilcard - provide for error return.
254 ****************************************************************************/
256 size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
257 const char *base_ptr,
258 uint16 smb_flags2,
259 char **pp_dest,
260 const char *src,
261 size_t src_len,
262 int flags,
263 NTSTATUS *err,
264 bool *contains_wcard)
266 size_t ret;
268 *pp_dest = NULL;
270 ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
271 src_len, flags);
273 if (!*pp_dest) {
274 *err = NT_STATUS_INVALID_PARAMETER;
275 return ret;
278 *contains_wcard = False;
280 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
282 * For a DFS path the function parse_dfs_path()
283 * will do the path processing, just make a copy.
285 *err = NT_STATUS_OK;
286 return ret;
289 if (lp_posix_pathnames()) {
290 *err = check_path_syntax_posix(*pp_dest);
291 } else {
292 *err = check_path_syntax_wcard(*pp_dest, contains_wcard);
295 return ret;
298 /****************************************************************************
299 Pull a string and check the path - provide for error return.
300 ****************************************************************************/
302 size_t srvstr_get_path(TALLOC_CTX *ctx,
303 const char *base_ptr,
304 uint16 smb_flags2,
305 char **pp_dest,
306 const char *src,
307 size_t src_len,
308 int flags,
309 NTSTATUS *err)
311 bool ignore;
312 return srvstr_get_path_wcard(ctx, base_ptr, smb_flags2, pp_dest, src,
313 src_len, flags, err, &ignore);
316 size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req,
317 char **pp_dest, const char *src, int flags,
318 NTSTATUS *err, bool *contains_wcard)
320 return srvstr_get_path_wcard(mem_ctx, (const char *)req->inbuf, req->flags2,
321 pp_dest, src, smbreq_bufrem(req, src),
322 flags, err, contains_wcard);
325 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
326 char **pp_dest, const char *src, int flags,
327 NTSTATUS *err)
329 bool ignore;
330 return srvstr_get_path_req_wcard(mem_ctx, req, pp_dest, src,
331 flags, err, &ignore);
334 /****************************************************************************
335 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
336 ****************************************************************************/
338 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
339 files_struct *fsp)
341 if ((fsp == NULL) || (conn == NULL)) {
342 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
343 return False;
345 if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
346 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
347 return False;
349 return True;
352 /****************************************************************************
353 Check if we have a correct fsp pointing to a file.
354 ****************************************************************************/
356 bool check_fsp(connection_struct *conn, struct smb_request *req,
357 files_struct *fsp)
359 if (!check_fsp_open(conn, req, fsp)) {
360 return False;
362 if (fsp->is_directory) {
363 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
364 return False;
366 if (fsp->fh->fd == -1) {
367 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
368 return False;
370 fsp->num_smb_operations++;
371 return True;
374 /****************************************************************************
375 Check if we have a correct fsp pointing to a quota fake file. Replacement for
376 the CHECK_NTQUOTA_HANDLE_OK macro.
377 ****************************************************************************/
379 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
380 files_struct *fsp)
382 if (!check_fsp_open(conn, req, fsp)) {
383 return false;
386 if (fsp->is_directory) {
387 return false;
390 if (fsp->fake_file_handle == NULL) {
391 return false;
394 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
395 return false;
398 if (fsp->fake_file_handle->private_data == NULL) {
399 return false;
402 return true;
405 static bool netbios_session_retarget(struct smbd_server_connection *sconn,
406 const char *name, int name_type)
408 char *trim_name;
409 char *trim_name_type;
410 const char *retarget_parm;
411 char *retarget;
412 char *p;
413 int retarget_type = 0x20;
414 int retarget_port = NBT_SMB_PORT;
415 struct sockaddr_storage retarget_addr;
416 struct sockaddr_in *in_addr;
417 bool ret = false;
418 uint8_t outbuf[10];
420 if (get_socket_port(sconn->sock) != NBT_SMB_PORT) {
421 return false;
424 trim_name = talloc_strdup(talloc_tos(), name);
425 if (trim_name == NULL) {
426 goto fail;
428 trim_char(trim_name, ' ', ' ');
430 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
431 name_type);
432 if (trim_name_type == NULL) {
433 goto fail;
436 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
437 trim_name_type, NULL);
438 if (retarget_parm == NULL) {
439 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
440 trim_name, NULL);
442 if (retarget_parm == NULL) {
443 goto fail;
446 retarget = talloc_strdup(trim_name, retarget_parm);
447 if (retarget == NULL) {
448 goto fail;
451 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
453 p = strchr(retarget, ':');
454 if (p != NULL) {
455 *p++ = '\0';
456 retarget_port = atoi(p);
459 p = strchr_m(retarget, '#');
460 if (p != NULL) {
461 *p++ = '\0';
462 if (sscanf(p, "%x", &retarget_type) != 1) {
463 goto fail;
467 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
468 if (!ret) {
469 DEBUG(10, ("could not resolve %s\n", retarget));
470 goto fail;
473 if (retarget_addr.ss_family != AF_INET) {
474 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
475 goto fail;
478 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
480 _smb_setlen(outbuf, 6);
481 SCVAL(outbuf, 0, 0x84);
482 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
483 *(uint16_t *)(outbuf+8) = htons(retarget_port);
485 if (!srv_send_smb(sconn, (char *)outbuf, false, 0, false,
486 NULL)) {
487 exit_server_cleanly("netbios_session_retarget: srv_send_smb "
488 "failed.");
491 ret = true;
492 fail:
493 TALLOC_FREE(trim_name);
494 return ret;
497 static void reply_called_name_not_present(char *outbuf)
499 smb_setlen(outbuf, 1);
500 SCVAL(outbuf, 0, 0x83);
501 SCVAL(outbuf, 4, 0x82);
504 /****************************************************************************
505 Reply to a (netbios-level) special message.
506 ****************************************************************************/
508 void reply_special(struct smbd_server_connection *sconn, char *inbuf, size_t inbuf_size)
510 int msg_type = CVAL(inbuf,0);
511 int msg_flags = CVAL(inbuf,1);
513 * We only really use 4 bytes of the outbuf, but for the smb_setlen
514 * calculation & friends (srv_send_smb uses that) we need the full smb
515 * header.
517 char outbuf[smb_size];
519 memset(outbuf, '\0', sizeof(outbuf));
521 smb_setlen(outbuf,0);
523 switch (msg_type) {
524 case NBSSrequest: /* session request */
526 /* inbuf_size is guarenteed to be at least 4. */
527 fstring name1,name2;
528 int name_type1, name_type2;
529 int name_len1, name_len2;
531 *name1 = *name2 = 0;
533 if (sconn->nbt.got_session) {
534 exit_server_cleanly("multiple session request not permitted");
537 SCVAL(outbuf,0,NBSSpositive);
538 SCVAL(outbuf,3,0);
540 /* inbuf_size is guaranteed to be at least 4. */
541 name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
542 if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
543 DEBUG(0,("Invalid name length in session request\n"));
544 reply_called_name_not_present(outbuf);
545 break;
547 name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
548 if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
549 DEBUG(0,("Invalid name length in session request\n"));
550 reply_called_name_not_present(outbuf);
551 break;
554 name_type1 = name_extract((unsigned char *)inbuf,
555 inbuf_size,(unsigned int)4,name1);
556 name_type2 = name_extract((unsigned char *)inbuf,
557 inbuf_size,(unsigned int)(4 + name_len1),name2);
559 if (name_type1 == -1 || name_type2 == -1) {
560 DEBUG(0,("Invalid name type in session request\n"));
561 reply_called_name_not_present(outbuf);
562 break;
565 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
566 name1, name_type1, name2, name_type2));
568 if (netbios_session_retarget(sconn, name1, name_type1)) {
569 exit_server_cleanly("retargeted client");
573 * Windows NT/2k uses "*SMBSERVER" and XP uses
574 * "*SMBSERV" arrggg!!!
576 if (strequal(name1, "*SMBSERVER ")
577 || strequal(name1, "*SMBSERV ")) {
578 char *raddr;
580 raddr = tsocket_address_inet_addr_string(sconn->remote_address,
581 talloc_tos());
582 if (raddr == NULL) {
583 exit_server_cleanly("could not allocate raddr");
586 fstrcpy(name1, raddr);
589 set_local_machine_name(name1, True);
590 set_remote_machine_name(name2, True);
592 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
593 get_local_machine_name(), get_remote_machine_name(),
594 name_type2));
596 if (name_type2 == 'R') {
597 /* We are being asked for a pathworks session ---
598 no thanks! */
599 reply_called_name_not_present(outbuf);
600 break;
603 reload_services(sconn, conn_snum_used, true);
604 reopen_logs();
606 sconn->nbt.got_session = true;
607 break;
610 case 0x89: /* session keepalive request
611 (some old clients produce this?) */
612 SCVAL(outbuf,0,NBSSkeepalive);
613 SCVAL(outbuf,3,0);
614 break;
616 case NBSSpositive: /* positive session response */
617 case NBSSnegative: /* negative session response */
618 case NBSSretarget: /* retarget session response */
619 DEBUG(0,("Unexpected session response\n"));
620 break;
622 case NBSSkeepalive: /* session keepalive */
623 default:
624 return;
627 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
628 msg_type, msg_flags));
630 srv_send_smb(sconn, outbuf, false, 0, false, NULL);
632 if (CVAL(outbuf, 0) != 0x82) {
633 exit_server_cleanly("invalid netbios session");
635 return;
638 /****************************************************************************
639 Reply to a tcon.
640 conn POINTER CAN BE NULL HERE !
641 ****************************************************************************/
643 void reply_tcon(struct smb_request *req)
645 connection_struct *conn = req->conn;
646 const char *service;
647 char *service_buf = NULL;
648 char *password = NULL;
649 char *dev = NULL;
650 int pwlen=0;
651 NTSTATUS nt_status;
652 const char *p;
653 TALLOC_CTX *ctx = talloc_tos();
654 struct smbd_server_connection *sconn = req->sconn;
656 START_PROFILE(SMBtcon);
658 if (req->buflen < 4) {
659 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
660 END_PROFILE(SMBtcon);
661 return;
664 p = (const char *)req->buf + 1;
665 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
666 p += 1;
667 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
668 p += pwlen+1;
669 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
670 p += 1;
672 if (service_buf == NULL || password == NULL || dev == NULL) {
673 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
674 END_PROFILE(SMBtcon);
675 return;
677 p = strrchr_m(service_buf,'\\');
678 if (p) {
679 service = p+1;
680 } else {
681 service = service_buf;
684 conn = make_connection(sconn,service,dev,
685 req->vuid,&nt_status);
686 req->conn = conn;
688 if (!conn) {
689 reply_nterror(req, nt_status);
690 END_PROFILE(SMBtcon);
691 return;
694 reply_outbuf(req, 2, 0);
695 SSVAL(req->outbuf,smb_vwv0,sconn->smb1.negprot.max_recv);
696 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
697 SSVAL(req->outbuf,smb_tid,conn->cnum);
699 DEBUG(3,("tcon service=%s cnum=%d\n",
700 service, conn->cnum));
702 END_PROFILE(SMBtcon);
703 return;
706 /****************************************************************************
707 Reply to a tcon and X.
708 conn POINTER CAN BE NULL HERE !
709 ****************************************************************************/
711 void reply_tcon_and_X(struct smb_request *req)
713 connection_struct *conn = req->conn;
714 const char *service = NULL;
715 TALLOC_CTX *ctx = talloc_tos();
716 /* what the cleint thinks the device is */
717 char *client_devicetype = NULL;
718 /* what the server tells the client the share represents */
719 const char *server_devicetype;
720 NTSTATUS nt_status;
721 int passlen;
722 char *path = NULL;
723 const char *p, *q;
724 uint16_t tcon_flags;
725 struct smbXsrv_session *session = NULL;
726 NTTIME now = timeval_to_nttime(&req->request_time);
727 bool session_key_updated = false;
728 struct smbd_server_connection *sconn = req->sconn;
730 START_PROFILE(SMBtconX);
732 if (req->wct < 4) {
733 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
734 END_PROFILE(SMBtconX);
735 return;
738 passlen = SVAL(req->vwv+3, 0);
739 tcon_flags = SVAL(req->vwv+2, 0);
741 /* we might have to close an old one */
742 if ((tcon_flags & TCONX_FLAG_DISCONNECT_TID) && conn) {
743 struct smbXsrv_tcon *tcon;
744 NTSTATUS status;
746 tcon = conn->tcon;
747 req->conn = NULL;
748 conn = NULL;
751 * TODO: cancel all outstanding requests on the tcon
753 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
754 if (!NT_STATUS_IS_OK(status)) {
755 DEBUG(0, ("reply_tcon_and_X: "
756 "smbXsrv_tcon_disconnect() failed: %s\n",
757 nt_errstr(status)));
759 * If we hit this case, there is something completely
760 * wrong, so we better disconnect the transport connection.
762 END_PROFILE(SMBtconX);
763 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
764 return;
767 TALLOC_FREE(tcon);
770 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
771 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
772 END_PROFILE(SMBtconX);
773 return;
776 if (sconn->smb1.negprot.encrypted_passwords) {
777 p = (const char *)req->buf + passlen;
778 } else {
779 p = (const char *)req->buf + passlen + 1;
782 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
784 if (path == NULL) {
785 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
786 END_PROFILE(SMBtconX);
787 return;
791 * the service name can be either: \\server\share
792 * or share directly like on the DELL PowerVault 705
794 if (*path=='\\') {
795 q = strchr_m(path+2,'\\');
796 if (!q) {
797 reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
798 END_PROFILE(SMBtconX);
799 return;
801 service = q+1;
802 } else {
803 service = path;
806 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
807 &client_devicetype, p,
808 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
810 if (client_devicetype == NULL) {
811 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
812 END_PROFILE(SMBtconX);
813 return;
816 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
818 nt_status = smb1srv_session_lookup(req->sconn->conn,
819 req->vuid, now, &session);
820 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_USER_SESSION_DELETED)) {
821 reply_force_doserror(req, ERRSRV, ERRbaduid);
822 END_PROFILE(SMBtconX);
823 return;
825 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
826 reply_nterror(req, nt_status);
827 END_PROFILE(SMBtconX);
828 return;
830 if (!NT_STATUS_IS_OK(nt_status)) {
831 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
832 END_PROFILE(SMBtconX);
833 return;
836 if (session->global->auth_session_info == NULL) {
837 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
838 END_PROFILE(SMBtconX);
839 return;
843 * If there is no application key defined yet
844 * we create one.
846 * This means we setup the application key on the
847 * first tcon that happens via the given session.
849 * Once the application key is defined, it does not
850 * change any more.
852 if (session->global->application_key.length == 0 &&
853 session->global->signing_key.length > 0)
855 struct smbXsrv_session *x = session;
856 struct auth_session_info *session_info =
857 session->global->auth_session_info;
858 uint8_t session_key[16];
860 ZERO_STRUCT(session_key);
861 memcpy(session_key, x->global->signing_key.data,
862 MIN(x->global->signing_key.length, sizeof(session_key)));
865 * The application key is truncated/padded to 16 bytes
867 x->global->application_key = data_blob_talloc(x->global,
868 session_key,
869 sizeof(session_key));
870 ZERO_STRUCT(session_key);
871 if (x->global->application_key.data == NULL) {
872 reply_nterror(req, NT_STATUS_NO_MEMORY);
873 END_PROFILE(SMBtconX);
874 return;
878 * Place the application key into the session_info
880 data_blob_clear_free(&session_info->session_key);
881 session_info->session_key = data_blob_dup_talloc(session_info,
882 x->global->application_key);
883 if (session_info->session_key.data == NULL) {
884 data_blob_clear_free(&x->global->application_key);
885 reply_nterror(req, NT_STATUS_NO_MEMORY);
886 END_PROFILE(SMBtconX);
887 return;
889 session_key_updated = true;
892 conn = make_connection(sconn, service, client_devicetype,
893 req->vuid, &nt_status);
894 req->conn =conn;
896 if (!conn) {
897 if (session_key_updated) {
898 struct smbXsrv_session *x = session;
899 struct auth_session_info *session_info =
900 session->global->auth_session_info;
901 data_blob_clear_free(&x->global->application_key);
902 data_blob_clear_free(&session_info->session_key);
904 reply_nterror(req, nt_status);
905 END_PROFILE(SMBtconX);
906 return;
909 if ( IS_IPC(conn) )
910 server_devicetype = "IPC";
911 else if ( IS_PRINT(conn) )
912 server_devicetype = "LPT1:";
913 else
914 server_devicetype = "A:";
916 if (get_Protocol() < PROTOCOL_NT1) {
917 reply_outbuf(req, 2, 0);
918 if (message_push_string(&req->outbuf, server_devicetype,
919 STR_TERMINATE|STR_ASCII) == -1) {
920 reply_nterror(req, NT_STATUS_NO_MEMORY);
921 END_PROFILE(SMBtconX);
922 return;
924 } else {
925 /* NT sets the fstype of IPC$ to the null string */
926 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(ctx, SNUM(conn));
927 uint16_t optional_support = 0;
929 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
930 /* Return permissions. */
931 uint32 perm1 = 0;
932 uint32 perm2 = 0;
934 reply_outbuf(req, 7, 0);
936 if (IS_IPC(conn)) {
937 perm1 = FILE_ALL_ACCESS;
938 perm2 = FILE_ALL_ACCESS;
939 } else {
940 perm1 = conn->share_access;
943 SIVAL(req->outbuf, smb_vwv3, perm1);
944 SIVAL(req->outbuf, smb_vwv5, perm2);
945 } else {
946 reply_outbuf(req, 3, 0);
949 if ((message_push_string(&req->outbuf, server_devicetype,
950 STR_TERMINATE|STR_ASCII) == -1)
951 || (message_push_string(&req->outbuf, fstype,
952 STR_TERMINATE) == -1)) {
953 reply_nterror(req, NT_STATUS_NO_MEMORY);
954 END_PROFILE(SMBtconX);
955 return;
958 /* what does setting this bit do? It is set by NT4 and
959 may affect the ability to autorun mounted cdroms */
960 optional_support |= SMB_SUPPORT_SEARCH_BITS;
961 optional_support |=
962 (lp_csc_policy(SNUM(conn)) << SMB_CSC_POLICY_SHIFT);
964 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
965 DEBUG(2,("Serving %s as a Dfs root\n",
966 lp_servicename(ctx, SNUM(conn)) ));
967 optional_support |= SMB_SHARE_IN_DFS;
970 SSVAL(req->outbuf, smb_vwv2, optional_support);
973 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
974 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
976 DEBUG(3,("tconX service=%s \n",
977 service));
979 /* set the incoming and outgoing tid to the just created one */
980 SSVAL(discard_const_p(uint8_t, req->inbuf),smb_tid,conn->cnum);
981 SSVAL(req->outbuf,smb_tid,conn->cnum);
983 END_PROFILE(SMBtconX);
985 req->tid = conn->cnum;
988 /****************************************************************************
989 Reply to an unknown type.
990 ****************************************************************************/
992 void reply_unknown_new(struct smb_request *req, uint8 type)
994 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
995 smb_fn_name(type), type, type));
996 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
997 return;
1000 /****************************************************************************
1001 Reply to an ioctl.
1002 conn POINTER CAN BE NULL HERE !
1003 ****************************************************************************/
1005 void reply_ioctl(struct smb_request *req)
1007 connection_struct *conn = req->conn;
1008 uint16 device;
1009 uint16 function;
1010 uint32 ioctl_code;
1011 int replysize;
1012 char *p;
1014 START_PROFILE(SMBioctl);
1016 if (req->wct < 3) {
1017 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1018 END_PROFILE(SMBioctl);
1019 return;
1022 device = SVAL(req->vwv+1, 0);
1023 function = SVAL(req->vwv+2, 0);
1024 ioctl_code = (device << 16) + function;
1026 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
1028 switch (ioctl_code) {
1029 case IOCTL_QUERY_JOB_INFO:
1030 replysize = 32;
1031 break;
1032 default:
1033 reply_force_doserror(req, ERRSRV, ERRnosupport);
1034 END_PROFILE(SMBioctl);
1035 return;
1038 reply_outbuf(req, 8, replysize+1);
1039 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
1040 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
1041 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
1042 p = smb_buf(req->outbuf);
1043 memset(p, '\0', replysize+1); /* valgrind-safe. */
1044 p += 1; /* Allow for alignment */
1046 switch (ioctl_code) {
1047 case IOCTL_QUERY_JOB_INFO:
1049 files_struct *fsp = file_fsp(
1050 req, SVAL(req->vwv+0, 0));
1051 if (!fsp) {
1052 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
1053 END_PROFILE(SMBioctl);
1054 return;
1056 /* Job number */
1057 SSVAL(p, 0, print_spool_rap_jobid(fsp->print_file));
1059 srvstr_push((char *)req->outbuf, req->flags2, p+2,
1060 lp_netbios_name(), 15,
1061 STR_TERMINATE|STR_ASCII);
1062 if (conn) {
1063 srvstr_push((char *)req->outbuf, req->flags2,
1064 p+18,
1065 lp_servicename(talloc_tos(),
1066 SNUM(conn)),
1067 13, STR_TERMINATE|STR_ASCII);
1068 } else {
1069 memset(p+18, 0, 13);
1071 break;
1075 END_PROFILE(SMBioctl);
1076 return;
1079 /****************************************************************************
1080 Strange checkpath NTSTATUS mapping.
1081 ****************************************************************************/
1083 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
1085 /* Strange DOS error code semantics only for checkpath... */
1086 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
1087 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
1088 /* We need to map to ERRbadpath */
1089 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1092 return status;
1095 /****************************************************************************
1096 Reply to a checkpath.
1097 ****************************************************************************/
1099 void reply_checkpath(struct smb_request *req)
1101 connection_struct *conn = req->conn;
1102 struct smb_filename *smb_fname = NULL;
1103 char *name = NULL;
1104 NTSTATUS status;
1105 TALLOC_CTX *ctx = talloc_tos();
1107 START_PROFILE(SMBcheckpath);
1109 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
1110 STR_TERMINATE, &status);
1112 if (!NT_STATUS_IS_OK(status)) {
1113 status = map_checkpath_error(req->flags2, status);
1114 reply_nterror(req, status);
1115 END_PROFILE(SMBcheckpath);
1116 return;
1119 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
1121 status = filename_convert(ctx,
1122 conn,
1123 req->flags2 & FLAGS2_DFS_PATHNAMES,
1124 name,
1126 NULL,
1127 &smb_fname);
1129 if (!NT_STATUS_IS_OK(status)) {
1130 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1131 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1132 ERRSRV, ERRbadpath);
1133 END_PROFILE(SMBcheckpath);
1134 return;
1136 goto path_err;
1139 if (!VALID_STAT(smb_fname->st) &&
1140 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1141 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1142 smb_fname_str_dbg(smb_fname), strerror(errno)));
1143 status = map_nt_error_from_unix(errno);
1144 goto path_err;
1147 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1148 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1149 ERRDOS, ERRbadpath);
1150 goto out;
1153 reply_outbuf(req, 0, 0);
1155 path_err:
1156 /* We special case this - as when a Windows machine
1157 is parsing a path is steps through the components
1158 one at a time - if a component fails it expects
1159 ERRbadpath, not ERRbadfile.
1161 status = map_checkpath_error(req->flags2, status);
1162 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1164 * Windows returns different error codes if
1165 * the parent directory is valid but not the
1166 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1167 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1168 * if the path is invalid.
1170 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1171 ERRDOS, ERRbadpath);
1172 goto out;
1175 reply_nterror(req, status);
1177 out:
1178 TALLOC_FREE(smb_fname);
1179 END_PROFILE(SMBcheckpath);
1180 return;
1183 /****************************************************************************
1184 Reply to a getatr.
1185 ****************************************************************************/
1187 void reply_getatr(struct smb_request *req)
1189 connection_struct *conn = req->conn;
1190 struct smb_filename *smb_fname = NULL;
1191 char *fname = NULL;
1192 int mode=0;
1193 off_t size=0;
1194 time_t mtime=0;
1195 const char *p;
1196 NTSTATUS status;
1197 TALLOC_CTX *ctx = talloc_tos();
1198 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1200 START_PROFILE(SMBgetatr);
1202 p = (const char *)req->buf + 1;
1203 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1204 if (!NT_STATUS_IS_OK(status)) {
1205 reply_nterror(req, status);
1206 goto out;
1209 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1210 under WfWg - weird! */
1211 if (*fname == '\0') {
1212 mode = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
1213 if (!CAN_WRITE(conn)) {
1214 mode |= FILE_ATTRIBUTE_READONLY;
1216 size = 0;
1217 mtime = 0;
1218 } else {
1219 status = filename_convert(ctx,
1220 conn,
1221 req->flags2 & FLAGS2_DFS_PATHNAMES,
1222 fname,
1224 NULL,
1225 &smb_fname);
1226 if (!NT_STATUS_IS_OK(status)) {
1227 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1228 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1229 ERRSRV, ERRbadpath);
1230 goto out;
1232 reply_nterror(req, status);
1233 goto out;
1235 if (!VALID_STAT(smb_fname->st) &&
1236 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1237 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1238 smb_fname_str_dbg(smb_fname),
1239 strerror(errno)));
1240 reply_nterror(req, map_nt_error_from_unix(errno));
1241 goto out;
1244 mode = dos_mode(conn, smb_fname);
1245 size = smb_fname->st.st_ex_size;
1247 if (ask_sharemode) {
1248 struct timespec write_time_ts;
1249 struct file_id fileid;
1251 ZERO_STRUCT(write_time_ts);
1252 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1253 get_file_infos(fileid, 0, NULL, &write_time_ts);
1254 if (!null_timespec(write_time_ts)) {
1255 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1259 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1260 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1261 size = 0;
1265 reply_outbuf(req, 10, 0);
1267 SSVAL(req->outbuf,smb_vwv0,mode);
1268 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1269 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1270 } else {
1271 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1273 SIVAL(req->outbuf,smb_vwv3,(uint32)size);
1275 if (get_Protocol() >= PROTOCOL_NT1) {
1276 SSVAL(req->outbuf, smb_flg2,
1277 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1280 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1281 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1283 out:
1284 TALLOC_FREE(smb_fname);
1285 TALLOC_FREE(fname);
1286 END_PROFILE(SMBgetatr);
1287 return;
1290 /****************************************************************************
1291 Reply to a setatr.
1292 ****************************************************************************/
1294 void reply_setatr(struct smb_request *req)
1296 struct smb_file_time ft;
1297 connection_struct *conn = req->conn;
1298 struct smb_filename *smb_fname = NULL;
1299 char *fname = NULL;
1300 int mode;
1301 time_t mtime;
1302 const char *p;
1303 NTSTATUS status;
1304 TALLOC_CTX *ctx = talloc_tos();
1306 START_PROFILE(SMBsetatr);
1308 ZERO_STRUCT(ft);
1310 if (req->wct < 2) {
1311 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1312 goto out;
1315 p = (const char *)req->buf + 1;
1316 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1317 if (!NT_STATUS_IS_OK(status)) {
1318 reply_nterror(req, status);
1319 goto out;
1322 status = filename_convert(ctx,
1323 conn,
1324 req->flags2 & FLAGS2_DFS_PATHNAMES,
1325 fname,
1327 NULL,
1328 &smb_fname);
1329 if (!NT_STATUS_IS_OK(status)) {
1330 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1331 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1332 ERRSRV, ERRbadpath);
1333 goto out;
1335 reply_nterror(req, status);
1336 goto out;
1339 if (smb_fname->base_name[0] == '.' &&
1340 smb_fname->base_name[1] == '\0') {
1342 * Not sure here is the right place to catch this
1343 * condition. Might be moved to somewhere else later -- vl
1345 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1346 goto out;
1349 mode = SVAL(req->vwv+0, 0);
1350 mtime = srv_make_unix_date3(req->vwv+1);
1352 if (mode != FILE_ATTRIBUTE_NORMAL) {
1353 if (VALID_STAT_OF_DIR(smb_fname->st))
1354 mode |= FILE_ATTRIBUTE_DIRECTORY;
1355 else
1356 mode &= ~FILE_ATTRIBUTE_DIRECTORY;
1358 status = check_access(conn, NULL, smb_fname,
1359 FILE_WRITE_ATTRIBUTES);
1360 if (!NT_STATUS_IS_OK(status)) {
1361 reply_nterror(req, status);
1362 goto out;
1365 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1366 false) != 0) {
1367 reply_nterror(req, map_nt_error_from_unix(errno));
1368 goto out;
1372 ft.mtime = convert_time_t_to_timespec(mtime);
1373 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1374 if (!NT_STATUS_IS_OK(status)) {
1375 reply_nterror(req, status);
1376 goto out;
1379 reply_outbuf(req, 0, 0);
1381 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1382 mode));
1383 out:
1384 TALLOC_FREE(smb_fname);
1385 END_PROFILE(SMBsetatr);
1386 return;
1389 /****************************************************************************
1390 Reply to a dskattr.
1391 ****************************************************************************/
1393 void reply_dskattr(struct smb_request *req)
1395 connection_struct *conn = req->conn;
1396 uint64_t dfree,dsize,bsize;
1397 START_PROFILE(SMBdskattr);
1399 if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (uint64_t)-1) {
1400 reply_nterror(req, map_nt_error_from_unix(errno));
1401 END_PROFILE(SMBdskattr);
1402 return;
1405 reply_outbuf(req, 5, 0);
1407 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1408 double total_space, free_space;
1409 /* we need to scale this to a number that DOS6 can handle. We
1410 use floating point so we can handle large drives on systems
1411 that don't have 64 bit integers
1413 we end up displaying a maximum of 2G to DOS systems
1415 total_space = dsize * (double)bsize;
1416 free_space = dfree * (double)bsize;
1418 dsize = (uint64_t)((total_space+63*512) / (64*512));
1419 dfree = (uint64_t)((free_space+63*512) / (64*512));
1421 if (dsize > 0xFFFF) dsize = 0xFFFF;
1422 if (dfree > 0xFFFF) dfree = 0xFFFF;
1424 SSVAL(req->outbuf,smb_vwv0,dsize);
1425 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1426 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1427 SSVAL(req->outbuf,smb_vwv3,dfree);
1428 } else {
1429 SSVAL(req->outbuf,smb_vwv0,dsize);
1430 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1431 SSVAL(req->outbuf,smb_vwv2,512);
1432 SSVAL(req->outbuf,smb_vwv3,dfree);
1435 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1437 END_PROFILE(SMBdskattr);
1438 return;
1442 * Utility function to split the filename from the directory.
1444 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1445 char **fname_dir_out,
1446 char **fname_mask_out)
1448 const char *p = NULL;
1449 char *fname_dir = NULL;
1450 char *fname_mask = NULL;
1452 p = strrchr_m(fname_in, '/');
1453 if (!p) {
1454 fname_dir = talloc_strdup(ctx, ".");
1455 fname_mask = talloc_strdup(ctx, fname_in);
1456 } else {
1457 fname_dir = talloc_strndup(ctx, fname_in,
1458 PTR_DIFF(p, fname_in));
1459 fname_mask = talloc_strdup(ctx, p+1);
1462 if (!fname_dir || !fname_mask) {
1463 TALLOC_FREE(fname_dir);
1464 TALLOC_FREE(fname_mask);
1465 return NT_STATUS_NO_MEMORY;
1468 *fname_dir_out = fname_dir;
1469 *fname_mask_out = fname_mask;
1470 return NT_STATUS_OK;
1473 /****************************************************************************
1474 Reply to a search.
1475 Can be called from SMBsearch, SMBffirst or SMBfunique.
1476 ****************************************************************************/
1478 void reply_search(struct smb_request *req)
1480 connection_struct *conn = req->conn;
1481 char *path = NULL;
1482 const char *mask = NULL;
1483 char *directory = NULL;
1484 struct smb_filename *smb_fname = NULL;
1485 char *fname = NULL;
1486 off_t size;
1487 uint32 mode;
1488 struct timespec date;
1489 uint32 dirtype;
1490 unsigned int numentries = 0;
1491 unsigned int maxentries = 0;
1492 bool finished = False;
1493 const char *p;
1494 int status_len;
1495 char status[21];
1496 int dptr_num= -1;
1497 bool check_descend = False;
1498 bool expect_close = False;
1499 NTSTATUS nt_status;
1500 bool mask_contains_wcard = False;
1501 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1502 TALLOC_CTX *ctx = talloc_tos();
1503 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1504 struct dptr_struct *dirptr = NULL;
1505 struct smbd_server_connection *sconn = req->sconn;
1507 START_PROFILE(SMBsearch);
1509 if (req->wct < 2) {
1510 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1511 goto out;
1514 if (lp_posix_pathnames()) {
1515 reply_unknown_new(req, req->cmd);
1516 goto out;
1519 /* If we were called as SMBffirst then we must expect close. */
1520 if(req->cmd == SMBffirst) {
1521 expect_close = True;
1524 reply_outbuf(req, 1, 3);
1525 maxentries = SVAL(req->vwv+0, 0);
1526 dirtype = SVAL(req->vwv+1, 0);
1527 p = (const char *)req->buf + 1;
1528 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1529 &nt_status, &mask_contains_wcard);
1530 if (!NT_STATUS_IS_OK(nt_status)) {
1531 reply_nterror(req, nt_status);
1532 goto out;
1535 p++;
1536 status_len = SVAL(p, 0);
1537 p += 2;
1539 /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
1541 if (status_len == 0) {
1542 nt_status = filename_convert(ctx, conn,
1543 req->flags2 & FLAGS2_DFS_PATHNAMES,
1544 path,
1545 UCF_ALWAYS_ALLOW_WCARD_LCOMP,
1546 &mask_contains_wcard,
1547 &smb_fname);
1548 if (!NT_STATUS_IS_OK(nt_status)) {
1549 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1550 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1551 ERRSRV, ERRbadpath);
1552 goto out;
1554 reply_nterror(req, nt_status);
1555 goto out;
1558 directory = smb_fname->base_name;
1560 p = strrchr_m(directory,'/');
1561 if ((p != NULL) && (*directory != '/')) {
1562 mask = p + 1;
1563 directory = talloc_strndup(ctx, directory,
1564 PTR_DIFF(p, directory));
1565 } else {
1566 mask = directory;
1567 directory = talloc_strdup(ctx,".");
1570 if (!directory) {
1571 reply_nterror(req, NT_STATUS_NO_MEMORY);
1572 goto out;
1575 memset((char *)status,'\0',21);
1576 SCVAL(status,0,(dirtype & 0x1F));
1578 nt_status = dptr_create(conn,
1579 NULL, /* req */
1580 NULL, /* fsp */
1581 directory,
1582 True,
1583 expect_close,
1584 req->smbpid,
1585 mask,
1586 mask_contains_wcard,
1587 dirtype,
1588 &dirptr);
1589 if (!NT_STATUS_IS_OK(nt_status)) {
1590 reply_nterror(req, nt_status);
1591 goto out;
1593 dptr_num = dptr_dnum(dirptr);
1594 } else {
1595 int status_dirtype;
1596 const char *dirpath;
1598 memcpy(status,p,21);
1599 status_dirtype = CVAL(status,0) & 0x1F;
1600 if (status_dirtype != (dirtype & 0x1F)) {
1601 dirtype = status_dirtype;
1604 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1605 if (!dirptr) {
1606 goto SearchEmpty;
1608 dirpath = dptr_path(sconn, dptr_num);
1609 directory = talloc_strdup(ctx, dirpath);
1610 if (!directory) {
1611 reply_nterror(req, NT_STATUS_NO_MEMORY);
1612 goto out;
1615 mask = dptr_wcard(sconn, dptr_num);
1616 if (!mask) {
1617 goto SearchEmpty;
1620 * For a 'continue' search we have no string. So
1621 * check from the initial saved string.
1623 mask_contains_wcard = ms_has_wild(mask);
1624 dirtype = dptr_attr(sconn, dptr_num);
1627 DEBUG(4,("dptr_num is %d\n",dptr_num));
1629 /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
1630 dptr_init_search_op(dirptr);
1632 if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
1633 char buf[DIR_STRUCT_SIZE];
1634 memcpy(buf,status,21);
1635 if (!make_dir_struct(ctx,buf,"???????????",volume_label(ctx, SNUM(conn)),
1636 0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
1637 reply_nterror(req, NT_STATUS_NO_MEMORY);
1638 goto out;
1640 dptr_fill(sconn, buf+12,dptr_num);
1641 if (dptr_zero(buf+12) && (status_len==0)) {
1642 numentries = 1;
1643 } else {
1644 numentries = 0;
1646 if (message_push_blob(&req->outbuf,
1647 data_blob_const(buf, sizeof(buf)))
1648 == -1) {
1649 reply_nterror(req, NT_STATUS_NO_MEMORY);
1650 goto out;
1652 } else {
1653 unsigned int i;
1654 maxentries = MIN(
1655 maxentries,
1656 ((BUFFER_SIZE -
1657 ((uint8 *)smb_buf(req->outbuf) + 3 - req->outbuf))
1658 /DIR_STRUCT_SIZE));
1660 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1661 directory,lp_dontdescend(ctx, SNUM(conn))));
1662 if (in_list(directory, lp_dontdescend(ctx, SNUM(conn)),True)) {
1663 check_descend = True;
1666 for (i=numentries;(i<maxentries) && !finished;i++) {
1667 finished = !get_dir_entry(ctx,
1668 dirptr,
1669 mask,
1670 dirtype,
1671 &fname,
1672 &size,
1673 &mode,
1674 &date,
1675 check_descend,
1676 ask_sharemode);
1677 if (!finished) {
1678 char buf[DIR_STRUCT_SIZE];
1679 memcpy(buf,status,21);
1680 if (!make_dir_struct(ctx,
1681 buf,
1682 mask,
1683 fname,
1684 size,
1685 mode,
1686 convert_timespec_to_time_t(date),
1687 !allow_long_path_components)) {
1688 reply_nterror(req, NT_STATUS_NO_MEMORY);
1689 goto out;
1691 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1692 break;
1694 if (message_push_blob(&req->outbuf,
1695 data_blob_const(buf, sizeof(buf)))
1696 == -1) {
1697 reply_nterror(req, NT_STATUS_NO_MEMORY);
1698 goto out;
1700 numentries++;
1705 SearchEmpty:
1707 /* If we were called as SMBffirst with smb_search_id == NULL
1708 and no entries were found then return error and close dirptr
1709 (X/Open spec) */
1711 if (numentries == 0) {
1712 dptr_close(sconn, &dptr_num);
1713 } else if(expect_close && status_len == 0) {
1714 /* Close the dptr - we know it's gone */
1715 dptr_close(sconn, &dptr_num);
1718 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1719 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1720 dptr_close(sconn, &dptr_num);
1723 if ((numentries == 0) && !mask_contains_wcard) {
1724 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1725 goto out;
1728 SSVAL(req->outbuf,smb_vwv0,numentries);
1729 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1730 SCVAL(smb_buf(req->outbuf),0,5);
1731 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1733 /* The replies here are never long name. */
1734 SSVAL(req->outbuf, smb_flg2,
1735 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1736 if (!allow_long_path_components) {
1737 SSVAL(req->outbuf, smb_flg2,
1738 SVAL(req->outbuf, smb_flg2)
1739 & (~FLAGS2_LONG_PATH_COMPONENTS));
1742 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
1743 SSVAL(req->outbuf, smb_flg2,
1744 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
1746 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
1747 smb_fn_name(req->cmd),
1748 mask,
1749 directory,
1750 dirtype,
1751 numentries,
1752 maxentries ));
1753 out:
1754 TALLOC_FREE(directory);
1755 TALLOC_FREE(smb_fname);
1756 END_PROFILE(SMBsearch);
1757 return;
1760 /****************************************************************************
1761 Reply to a fclose (stop directory search).
1762 ****************************************************************************/
1764 void reply_fclose(struct smb_request *req)
1766 int status_len;
1767 char status[21];
1768 int dptr_num= -2;
1769 const char *p;
1770 char *path = NULL;
1771 NTSTATUS err;
1772 bool path_contains_wcard = False;
1773 TALLOC_CTX *ctx = talloc_tos();
1774 struct smbd_server_connection *sconn = req->sconn;
1776 START_PROFILE(SMBfclose);
1778 if (lp_posix_pathnames()) {
1779 reply_unknown_new(req, req->cmd);
1780 END_PROFILE(SMBfclose);
1781 return;
1784 p = (const char *)req->buf + 1;
1785 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1786 &err, &path_contains_wcard);
1787 if (!NT_STATUS_IS_OK(err)) {
1788 reply_nterror(req, err);
1789 END_PROFILE(SMBfclose);
1790 return;
1792 p++;
1793 status_len = SVAL(p,0);
1794 p += 2;
1796 if (status_len == 0) {
1797 reply_force_doserror(req, ERRSRV, ERRsrverror);
1798 END_PROFILE(SMBfclose);
1799 return;
1802 memcpy(status,p,21);
1804 if(dptr_fetch(sconn, status+12,&dptr_num)) {
1805 /* Close the dptr - we know it's gone */
1806 dptr_close(sconn, &dptr_num);
1809 reply_outbuf(req, 1, 0);
1810 SSVAL(req->outbuf,smb_vwv0,0);
1812 DEBUG(3,("search close\n"));
1814 END_PROFILE(SMBfclose);
1815 return;
1818 /****************************************************************************
1819 Reply to an open.
1820 ****************************************************************************/
1822 void reply_open(struct smb_request *req)
1824 connection_struct *conn = req->conn;
1825 struct smb_filename *smb_fname = NULL;
1826 char *fname = NULL;
1827 uint32 fattr=0;
1828 off_t size = 0;
1829 time_t mtime=0;
1830 int info;
1831 files_struct *fsp;
1832 int oplock_request;
1833 int deny_mode;
1834 uint32 dos_attr;
1835 uint32 access_mask;
1836 uint32 share_mode;
1837 uint32 create_disposition;
1838 uint32 create_options = 0;
1839 uint32_t private_flags = 0;
1840 NTSTATUS status;
1841 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1842 TALLOC_CTX *ctx = talloc_tos();
1844 START_PROFILE(SMBopen);
1846 if (req->wct < 2) {
1847 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1848 goto out;
1851 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1852 deny_mode = SVAL(req->vwv+0, 0);
1853 dos_attr = SVAL(req->vwv+1, 0);
1855 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
1856 STR_TERMINATE, &status);
1857 if (!NT_STATUS_IS_OK(status)) {
1858 reply_nterror(req, status);
1859 goto out;
1862 status = filename_convert(ctx,
1863 conn,
1864 req->flags2 & FLAGS2_DFS_PATHNAMES,
1865 fname,
1867 NULL,
1868 &smb_fname);
1869 if (!NT_STATUS_IS_OK(status)) {
1870 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1871 reply_botherror(req,
1872 NT_STATUS_PATH_NOT_COVERED,
1873 ERRSRV, ERRbadpath);
1874 goto out;
1876 reply_nterror(req, status);
1877 goto out;
1880 if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode,
1881 OPENX_FILE_EXISTS_OPEN, &access_mask,
1882 &share_mode, &create_disposition,
1883 &create_options, &private_flags)) {
1884 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1885 goto out;
1888 status = SMB_VFS_CREATE_FILE(
1889 conn, /* conn */
1890 req, /* req */
1891 0, /* root_dir_fid */
1892 smb_fname, /* fname */
1893 access_mask, /* access_mask */
1894 share_mode, /* share_access */
1895 create_disposition, /* create_disposition*/
1896 create_options, /* create_options */
1897 dos_attr, /* file_attributes */
1898 oplock_request, /* oplock_request */
1899 0, /* allocation_size */
1900 private_flags,
1901 NULL, /* sd */
1902 NULL, /* ea_list */
1903 &fsp, /* result */
1904 &info); /* pinfo */
1906 if (!NT_STATUS_IS_OK(status)) {
1907 if (open_was_deferred(req->sconn, req->mid)) {
1908 /* We have re-scheduled this call. */
1909 goto out;
1911 reply_openerror(req, status);
1912 goto out;
1915 size = smb_fname->st.st_ex_size;
1916 fattr = dos_mode(conn, smb_fname);
1918 /* Deal with other possible opens having a modified
1919 write time. JRA. */
1920 if (ask_sharemode) {
1921 struct timespec write_time_ts;
1923 ZERO_STRUCT(write_time_ts);
1924 get_file_infos(fsp->file_id, 0, NULL, &write_time_ts);
1925 if (!null_timespec(write_time_ts)) {
1926 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1930 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1932 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
1933 DEBUG(3,("attempt to open a directory %s\n",
1934 fsp_str_dbg(fsp)));
1935 close_file(req, fsp, ERROR_CLOSE);
1936 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
1937 ERRDOS, ERRnoaccess);
1938 goto out;
1941 reply_outbuf(req, 7, 0);
1942 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
1943 SSVAL(req->outbuf,smb_vwv1,fattr);
1944 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1945 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
1946 } else {
1947 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
1949 SIVAL(req->outbuf,smb_vwv4,(uint32)size);
1950 SSVAL(req->outbuf,smb_vwv6,deny_mode);
1952 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1953 SCVAL(req->outbuf,smb_flg,
1954 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1957 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1958 SCVAL(req->outbuf,smb_flg,
1959 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1961 out:
1962 TALLOC_FREE(smb_fname);
1963 END_PROFILE(SMBopen);
1964 return;
1967 /****************************************************************************
1968 Reply to an open and X.
1969 ****************************************************************************/
1971 void reply_open_and_X(struct smb_request *req)
1973 connection_struct *conn = req->conn;
1974 struct smb_filename *smb_fname = NULL;
1975 char *fname = NULL;
1976 uint16 open_flags;
1977 int deny_mode;
1978 uint32 smb_attr;
1979 /* Breakout the oplock request bits so we can set the
1980 reply bits separately. */
1981 int ex_oplock_request;
1982 int core_oplock_request;
1983 int oplock_request;
1984 #if 0
1985 int smb_sattr = SVAL(req->vwv+4, 0);
1986 uint32 smb_time = make_unix_date3(req->vwv+6);
1987 #endif
1988 int smb_ofun;
1989 uint32 fattr=0;
1990 int mtime=0;
1991 int smb_action = 0;
1992 files_struct *fsp;
1993 NTSTATUS status;
1994 uint64_t allocation_size;
1995 ssize_t retval = -1;
1996 uint32 access_mask;
1997 uint32 share_mode;
1998 uint32 create_disposition;
1999 uint32 create_options = 0;
2000 uint32_t private_flags = 0;
2001 TALLOC_CTX *ctx = talloc_tos();
2003 START_PROFILE(SMBopenX);
2005 if (req->wct < 15) {
2006 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2007 goto out;
2010 open_flags = SVAL(req->vwv+2, 0);
2011 deny_mode = SVAL(req->vwv+3, 0);
2012 smb_attr = SVAL(req->vwv+5, 0);
2013 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
2014 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2015 oplock_request = ex_oplock_request | core_oplock_request;
2016 smb_ofun = SVAL(req->vwv+8, 0);
2017 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
2019 /* If it's an IPC, pass off the pipe handler. */
2020 if (IS_IPC(conn)) {
2021 if (lp_nt_pipe_support()) {
2022 reply_open_pipe_and_X(conn, req);
2023 } else {
2024 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
2026 goto out;
2029 /* XXXX we need to handle passed times, sattr and flags */
2030 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
2031 STR_TERMINATE, &status);
2032 if (!NT_STATUS_IS_OK(status)) {
2033 reply_nterror(req, status);
2034 goto out;
2037 status = filename_convert(ctx,
2038 conn,
2039 req->flags2 & FLAGS2_DFS_PATHNAMES,
2040 fname,
2042 NULL,
2043 &smb_fname);
2044 if (!NT_STATUS_IS_OK(status)) {
2045 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2046 reply_botherror(req,
2047 NT_STATUS_PATH_NOT_COVERED,
2048 ERRSRV, ERRbadpath);
2049 goto out;
2051 reply_nterror(req, status);
2052 goto out;
2055 if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode,
2056 smb_ofun,
2057 &access_mask, &share_mode,
2058 &create_disposition,
2059 &create_options,
2060 &private_flags)) {
2061 reply_force_doserror(req, ERRDOS, ERRbadaccess);
2062 goto out;
2065 status = SMB_VFS_CREATE_FILE(
2066 conn, /* conn */
2067 req, /* req */
2068 0, /* root_dir_fid */
2069 smb_fname, /* fname */
2070 access_mask, /* access_mask */
2071 share_mode, /* share_access */
2072 create_disposition, /* create_disposition*/
2073 create_options, /* create_options */
2074 smb_attr, /* file_attributes */
2075 oplock_request, /* oplock_request */
2076 0, /* allocation_size */
2077 private_flags,
2078 NULL, /* sd */
2079 NULL, /* ea_list */
2080 &fsp, /* result */
2081 &smb_action); /* pinfo */
2083 if (!NT_STATUS_IS_OK(status)) {
2084 if (open_was_deferred(req->sconn, req->mid)) {
2085 /* We have re-scheduled this call. */
2086 goto out;
2088 reply_openerror(req, status);
2089 goto out;
2092 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
2093 if the file is truncated or created. */
2094 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
2095 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
2096 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
2097 close_file(req, fsp, ERROR_CLOSE);
2098 reply_nterror(req, NT_STATUS_DISK_FULL);
2099 goto out;
2101 retval = vfs_set_filelen(fsp, (off_t)allocation_size);
2102 if (retval < 0) {
2103 close_file(req, fsp, ERROR_CLOSE);
2104 reply_nterror(req, NT_STATUS_DISK_FULL);
2105 goto out;
2107 status = vfs_stat_fsp(fsp);
2108 if (!NT_STATUS_IS_OK(status)) {
2109 close_file(req, fsp, ERROR_CLOSE);
2110 reply_nterror(req, status);
2111 goto out;
2115 fattr = dos_mode(conn, fsp->fsp_name);
2116 mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
2117 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2118 close_file(req, fsp, ERROR_CLOSE);
2119 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
2120 goto out;
2123 /* If the caller set the extended oplock request bit
2124 and we granted one (by whatever means) - set the
2125 correct bit for extended oplock reply.
2128 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2129 smb_action |= EXTENDED_OPLOCK_GRANTED;
2132 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2133 smb_action |= EXTENDED_OPLOCK_GRANTED;
2136 /* If the caller set the core oplock request bit
2137 and we granted one (by whatever means) - set the
2138 correct bit for core oplock reply.
2141 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2142 reply_outbuf(req, 19, 0);
2143 } else {
2144 reply_outbuf(req, 15, 0);
2147 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2148 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2150 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
2151 SCVAL(req->outbuf, smb_flg,
2152 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2155 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2156 SCVAL(req->outbuf, smb_flg,
2157 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2160 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2161 SSVAL(req->outbuf,smb_vwv3,fattr);
2162 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2163 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2164 } else {
2165 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2167 SIVAL(req->outbuf,smb_vwv6,(uint32)fsp->fsp_name->st.st_ex_size);
2168 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2169 SSVAL(req->outbuf,smb_vwv11,smb_action);
2171 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2172 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2175 out:
2176 TALLOC_FREE(smb_fname);
2177 END_PROFILE(SMBopenX);
2178 return;
2181 /****************************************************************************
2182 Reply to a SMBulogoffX.
2183 ****************************************************************************/
2185 void reply_ulogoffX(struct smb_request *req)
2187 struct smbd_server_connection *sconn = req->sconn;
2188 struct user_struct *vuser;
2189 struct smbXsrv_session *session = NULL;
2190 NTSTATUS status;
2192 START_PROFILE(SMBulogoffX);
2194 vuser = get_valid_user_struct(sconn, req->vuid);
2196 if(vuser == NULL) {
2197 DEBUG(3,("ulogoff, vuser id %llu does not map to user.\n",
2198 (unsigned long long)req->vuid));
2200 req->vuid = UID_FIELD_INVALID;
2201 reply_force_doserror(req, ERRSRV, ERRbaduid);
2202 END_PROFILE(SMBulogoffX);
2203 return;
2206 session = vuser->session;
2207 vuser = NULL;
2210 * TODO: cancel all outstanding requests on the session
2212 status = smbXsrv_session_logoff(session);
2213 if (!NT_STATUS_IS_OK(status)) {
2214 DEBUG(0, ("reply_ulogoff: "
2215 "smbXsrv_session_logoff() failed: %s\n",
2216 nt_errstr(status)));
2218 * If we hit this case, there is something completely
2219 * wrong, so we better disconnect the transport connection.
2221 END_PROFILE(SMBulogoffX);
2222 exit_server(__location__ ": smbXsrv_session_logoff failed");
2223 return;
2226 TALLOC_FREE(session);
2228 reply_outbuf(req, 2, 0);
2229 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
2230 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
2232 DEBUG(3, ("ulogoffX vuid=%llu\n",
2233 (unsigned long long)req->vuid));
2235 END_PROFILE(SMBulogoffX);
2236 req->vuid = UID_FIELD_INVALID;
2239 /****************************************************************************
2240 Reply to a mknew or a create.
2241 ****************************************************************************/
2243 void reply_mknew(struct smb_request *req)
2245 connection_struct *conn = req->conn;
2246 struct smb_filename *smb_fname = NULL;
2247 char *fname = NULL;
2248 uint32 fattr = 0;
2249 struct smb_file_time ft;
2250 files_struct *fsp;
2251 int oplock_request = 0;
2252 NTSTATUS status;
2253 uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2254 uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2255 uint32 create_disposition;
2256 uint32 create_options = 0;
2257 TALLOC_CTX *ctx = talloc_tos();
2259 START_PROFILE(SMBcreate);
2260 ZERO_STRUCT(ft);
2262 if (req->wct < 3) {
2263 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2264 goto out;
2267 fattr = SVAL(req->vwv+0, 0);
2268 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2270 /* mtime. */
2271 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2273 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2274 STR_TERMINATE, &status);
2275 if (!NT_STATUS_IS_OK(status)) {
2276 reply_nterror(req, status);
2277 goto out;
2280 status = filename_convert(ctx,
2281 conn,
2282 req->flags2 & FLAGS2_DFS_PATHNAMES,
2283 fname,
2285 NULL,
2286 &smb_fname);
2287 if (!NT_STATUS_IS_OK(status)) {
2288 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2289 reply_botherror(req,
2290 NT_STATUS_PATH_NOT_COVERED,
2291 ERRSRV, ERRbadpath);
2292 goto out;
2294 reply_nterror(req, status);
2295 goto out;
2298 if (fattr & FILE_ATTRIBUTE_VOLUME) {
2299 DEBUG(0,("Attempt to create file (%s) with volid set - "
2300 "please report this\n",
2301 smb_fname_str_dbg(smb_fname)));
2304 if(req->cmd == SMBmknew) {
2305 /* We should fail if file exists. */
2306 create_disposition = FILE_CREATE;
2307 } else {
2308 /* Create if file doesn't exist, truncate if it does. */
2309 create_disposition = FILE_OVERWRITE_IF;
2312 status = SMB_VFS_CREATE_FILE(
2313 conn, /* conn */
2314 req, /* req */
2315 0, /* root_dir_fid */
2316 smb_fname, /* fname */
2317 access_mask, /* access_mask */
2318 share_mode, /* share_access */
2319 create_disposition, /* create_disposition*/
2320 create_options, /* create_options */
2321 fattr, /* file_attributes */
2322 oplock_request, /* oplock_request */
2323 0, /* allocation_size */
2324 0, /* private_flags */
2325 NULL, /* sd */
2326 NULL, /* ea_list */
2327 &fsp, /* result */
2328 NULL); /* pinfo */
2330 if (!NT_STATUS_IS_OK(status)) {
2331 if (open_was_deferred(req->sconn, req->mid)) {
2332 /* We have re-scheduled this call. */
2333 goto out;
2335 reply_openerror(req, status);
2336 goto out;
2339 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2340 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2341 if (!NT_STATUS_IS_OK(status)) {
2342 END_PROFILE(SMBcreate);
2343 goto out;
2346 reply_outbuf(req, 1, 0);
2347 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2349 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2350 SCVAL(req->outbuf,smb_flg,
2351 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2354 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2355 SCVAL(req->outbuf,smb_flg,
2356 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2359 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2360 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2361 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2362 (unsigned int)fattr));
2364 out:
2365 TALLOC_FREE(smb_fname);
2366 END_PROFILE(SMBcreate);
2367 return;
2370 /****************************************************************************
2371 Reply to a create temporary file.
2372 ****************************************************************************/
2374 void reply_ctemp(struct smb_request *req)
2376 connection_struct *conn = req->conn;
2377 struct smb_filename *smb_fname = NULL;
2378 char *fname = NULL;
2379 uint32 fattr;
2380 files_struct *fsp;
2381 int oplock_request;
2382 int tmpfd;
2383 char *s;
2384 NTSTATUS status;
2385 TALLOC_CTX *ctx = talloc_tos();
2387 START_PROFILE(SMBctemp);
2389 if (req->wct < 3) {
2390 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2391 goto out;
2394 fattr = SVAL(req->vwv+0, 0);
2395 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2397 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
2398 STR_TERMINATE, &status);
2399 if (!NT_STATUS_IS_OK(status)) {
2400 reply_nterror(req, status);
2401 goto out;
2403 if (*fname) {
2404 fname = talloc_asprintf(ctx,
2405 "%s/TMXXXXXX",
2406 fname);
2407 } else {
2408 fname = talloc_strdup(ctx, "TMXXXXXX");
2411 if (!fname) {
2412 reply_nterror(req, NT_STATUS_NO_MEMORY);
2413 goto out;
2416 status = filename_convert(ctx, conn,
2417 req->flags2 & FLAGS2_DFS_PATHNAMES,
2418 fname,
2420 NULL,
2421 &smb_fname);
2422 if (!NT_STATUS_IS_OK(status)) {
2423 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2424 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2425 ERRSRV, ERRbadpath);
2426 goto out;
2428 reply_nterror(req, status);
2429 goto out;
2432 tmpfd = mkstemp(smb_fname->base_name);
2433 if (tmpfd == -1) {
2434 reply_nterror(req, map_nt_error_from_unix(errno));
2435 goto out;
2438 SMB_VFS_STAT(conn, smb_fname);
2440 /* We should fail if file does not exist. */
2441 status = SMB_VFS_CREATE_FILE(
2442 conn, /* conn */
2443 req, /* req */
2444 0, /* root_dir_fid */
2445 smb_fname, /* fname */
2446 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2447 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2448 FILE_OPEN, /* create_disposition*/
2449 0, /* create_options */
2450 fattr, /* file_attributes */
2451 oplock_request, /* oplock_request */
2452 0, /* allocation_size */
2453 0, /* private_flags */
2454 NULL, /* sd */
2455 NULL, /* ea_list */
2456 &fsp, /* result */
2457 NULL); /* pinfo */
2459 /* close fd from mkstemp() */
2460 close(tmpfd);
2462 if (!NT_STATUS_IS_OK(status)) {
2463 if (open_was_deferred(req->sconn, req->mid)) {
2464 /* We have re-scheduled this call. */
2465 goto out;
2467 reply_openerror(req, status);
2468 goto out;
2471 reply_outbuf(req, 1, 0);
2472 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2474 /* the returned filename is relative to the directory */
2475 s = strrchr_m(fsp->fsp_name->base_name, '/');
2476 if (!s) {
2477 s = fsp->fsp_name->base_name;
2478 } else {
2479 s++;
2482 #if 0
2483 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2484 thing in the byte section. JRA */
2485 SSVALS(p, 0, -1); /* what is this? not in spec */
2486 #endif
2487 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2488 == -1) {
2489 reply_nterror(req, NT_STATUS_NO_MEMORY);
2490 goto out;
2493 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2494 SCVAL(req->outbuf, smb_flg,
2495 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2498 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2499 SCVAL(req->outbuf, smb_flg,
2500 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2503 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2504 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2505 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2506 out:
2507 TALLOC_FREE(smb_fname);
2508 END_PROFILE(SMBctemp);
2509 return;
2512 /*******************************************************************
2513 Check if a user is allowed to rename a file.
2514 ********************************************************************/
2516 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2517 uint16 dirtype)
2519 if (!CAN_WRITE(conn)) {
2520 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2523 if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
2524 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2525 /* Only bother to read the DOS attribute if we might deny the
2526 rename on the grounds of attribute missmatch. */
2527 uint32_t fmode = dos_mode(conn, fsp->fsp_name);
2528 if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
2529 return NT_STATUS_NO_SUCH_FILE;
2533 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2534 if (fsp->posix_open) {
2535 return NT_STATUS_OK;
2538 /* If no pathnames are open below this
2539 directory, allow the rename. */
2541 if (file_find_subpath(fsp)) {
2542 return NT_STATUS_ACCESS_DENIED;
2544 return NT_STATUS_OK;
2547 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2548 return NT_STATUS_OK;
2551 return NT_STATUS_ACCESS_DENIED;
2554 /*******************************************************************
2555 * unlink a file with all relevant access checks
2556 *******************************************************************/
2558 static NTSTATUS do_unlink(connection_struct *conn,
2559 struct smb_request *req,
2560 struct smb_filename *smb_fname,
2561 uint32 dirtype)
2563 uint32 fattr;
2564 files_struct *fsp;
2565 uint32 dirtype_orig = dirtype;
2566 NTSTATUS status;
2567 int ret;
2568 bool posix_paths = lp_posix_pathnames();
2570 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2571 smb_fname_str_dbg(smb_fname),
2572 dirtype));
2574 if (!CAN_WRITE(conn)) {
2575 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2578 if (posix_paths) {
2579 ret = SMB_VFS_LSTAT(conn, smb_fname);
2580 } else {
2581 ret = SMB_VFS_STAT(conn, smb_fname);
2583 if (ret != 0) {
2584 return map_nt_error_from_unix(errno);
2587 fattr = dos_mode(conn, smb_fname);
2589 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2590 dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
2593 dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
2594 if (!dirtype) {
2595 return NT_STATUS_NO_SUCH_FILE;
2598 if (!dir_check_ftype(conn, fattr, dirtype)) {
2599 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2600 return NT_STATUS_FILE_IS_A_DIRECTORY;
2602 return NT_STATUS_NO_SUCH_FILE;
2605 if (dirtype_orig & 0x8000) {
2606 /* These will never be set for POSIX. */
2607 return NT_STATUS_NO_SUCH_FILE;
2610 #if 0
2611 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2612 return NT_STATUS_FILE_IS_A_DIRECTORY;
2615 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2616 return NT_STATUS_NO_SUCH_FILE;
2619 if (dirtype & 0xFF00) {
2620 /* These will never be set for POSIX. */
2621 return NT_STATUS_NO_SUCH_FILE;
2624 dirtype &= 0xFF;
2625 if (!dirtype) {
2626 return NT_STATUS_NO_SUCH_FILE;
2629 /* Can't delete a directory. */
2630 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
2631 return NT_STATUS_FILE_IS_A_DIRECTORY;
2633 #endif
2635 #if 0 /* JRATEST */
2636 else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
2637 return NT_STATUS_OBJECT_NAME_INVALID;
2638 #endif /* JRATEST */
2640 /* On open checks the open itself will check the share mode, so
2641 don't do it here as we'll get it wrong. */
2643 status = SMB_VFS_CREATE_FILE
2644 (conn, /* conn */
2645 req, /* req */
2646 0, /* root_dir_fid */
2647 smb_fname, /* fname */
2648 DELETE_ACCESS, /* access_mask */
2649 FILE_SHARE_NONE, /* share_access */
2650 FILE_OPEN, /* create_disposition*/
2651 FILE_NON_DIRECTORY_FILE, /* create_options */
2652 /* file_attributes */
2653 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2654 FILE_ATTRIBUTE_NORMAL,
2655 0, /* oplock_request */
2656 0, /* allocation_size */
2657 0, /* private_flags */
2658 NULL, /* sd */
2659 NULL, /* ea_list */
2660 &fsp, /* result */
2661 NULL); /* pinfo */
2663 if (!NT_STATUS_IS_OK(status)) {
2664 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2665 nt_errstr(status)));
2666 return status;
2669 status = can_set_delete_on_close(fsp, fattr);
2670 if (!NT_STATUS_IS_OK(status)) {
2671 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2672 "(%s)\n",
2673 smb_fname_str_dbg(smb_fname),
2674 nt_errstr(status)));
2675 close_file(req, fsp, NORMAL_CLOSE);
2676 return status;
2679 /* The set is across all open files on this dev/inode pair. */
2680 if (!set_delete_on_close(fsp, True,
2681 conn->session_info->security_token,
2682 conn->session_info->unix_token)) {
2683 close_file(req, fsp, NORMAL_CLOSE);
2684 return NT_STATUS_ACCESS_DENIED;
2687 return close_file(req, fsp, NORMAL_CLOSE);
2690 /****************************************************************************
2691 The guts of the unlink command, split out so it may be called by the NT SMB
2692 code.
2693 ****************************************************************************/
2695 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2696 uint32 dirtype, struct smb_filename *smb_fname,
2697 bool has_wild)
2699 char *fname_dir = NULL;
2700 char *fname_mask = NULL;
2701 int count=0;
2702 NTSTATUS status = NT_STATUS_OK;
2703 TALLOC_CTX *ctx = talloc_tos();
2705 /* Split up the directory from the filename/mask. */
2706 status = split_fname_dir_mask(ctx, smb_fname->base_name,
2707 &fname_dir, &fname_mask);
2708 if (!NT_STATUS_IS_OK(status)) {
2709 goto out;
2713 * We should only check the mangled cache
2714 * here if unix_convert failed. This means
2715 * that the path in 'mask' doesn't exist
2716 * on the file system and so we need to look
2717 * for a possible mangle. This patch from
2718 * Tine Smukavec <valentin.smukavec@hermes.si>.
2721 if (!VALID_STAT(smb_fname->st) &&
2722 mangle_is_mangled(fname_mask, conn->params)) {
2723 char *new_mask = NULL;
2724 mangle_lookup_name_from_8_3(ctx, fname_mask,
2725 &new_mask, conn->params);
2726 if (new_mask) {
2727 TALLOC_FREE(fname_mask);
2728 fname_mask = new_mask;
2732 if (!has_wild) {
2735 * Only one file needs to be unlinked. Append the mask back
2736 * onto the directory.
2738 TALLOC_FREE(smb_fname->base_name);
2739 if (ISDOT(fname_dir)) {
2740 /* Ensure we use canonical names on open. */
2741 smb_fname->base_name = talloc_asprintf(smb_fname,
2742 "%s",
2743 fname_mask);
2744 } else {
2745 smb_fname->base_name = talloc_asprintf(smb_fname,
2746 "%s/%s",
2747 fname_dir,
2748 fname_mask);
2750 if (!smb_fname->base_name) {
2751 status = NT_STATUS_NO_MEMORY;
2752 goto out;
2754 if (dirtype == 0) {
2755 dirtype = FILE_ATTRIBUTE_NORMAL;
2758 status = check_name(conn, smb_fname->base_name);
2759 if (!NT_STATUS_IS_OK(status)) {
2760 goto out;
2763 status = do_unlink(conn, req, smb_fname, dirtype);
2764 if (!NT_STATUS_IS_OK(status)) {
2765 goto out;
2768 count++;
2769 } else {
2770 struct smb_Dir *dir_hnd = NULL;
2771 long offset = 0;
2772 const char *dname = NULL;
2773 char *talloced = NULL;
2775 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == FILE_ATTRIBUTE_DIRECTORY) {
2776 status = NT_STATUS_OBJECT_NAME_INVALID;
2777 goto out;
2780 if (strequal(fname_mask,"????????.???")) {
2781 TALLOC_FREE(fname_mask);
2782 fname_mask = talloc_strdup(ctx, "*");
2783 if (!fname_mask) {
2784 status = NT_STATUS_NO_MEMORY;
2785 goto out;
2789 status = check_name(conn, fname_dir);
2790 if (!NT_STATUS_IS_OK(status)) {
2791 goto out;
2794 dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask,
2795 dirtype);
2796 if (dir_hnd == NULL) {
2797 status = map_nt_error_from_unix(errno);
2798 goto out;
2801 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2802 the pattern matches against the long name, otherwise the short name
2803 We don't implement this yet XXXX
2806 status = NT_STATUS_NO_SUCH_FILE;
2808 while ((dname = ReadDirName(dir_hnd, &offset,
2809 &smb_fname->st, &talloced))) {
2810 TALLOC_CTX *frame = talloc_stackframe();
2812 if (!is_visible_file(conn, fname_dir, dname,
2813 &smb_fname->st, true)) {
2814 TALLOC_FREE(frame);
2815 TALLOC_FREE(talloced);
2816 continue;
2819 /* Quick check for "." and ".." */
2820 if (ISDOT(dname) || ISDOTDOT(dname)) {
2821 TALLOC_FREE(frame);
2822 TALLOC_FREE(talloced);
2823 continue;
2826 if(!mask_match(dname, fname_mask,
2827 conn->case_sensitive)) {
2828 TALLOC_FREE(frame);
2829 TALLOC_FREE(talloced);
2830 continue;
2833 TALLOC_FREE(smb_fname->base_name);
2834 if (ISDOT(fname_dir)) {
2835 /* Ensure we use canonical names on open. */
2836 smb_fname->base_name =
2837 talloc_asprintf(smb_fname, "%s",
2838 dname);
2839 } else {
2840 smb_fname->base_name =
2841 talloc_asprintf(smb_fname, "%s/%s",
2842 fname_dir, dname);
2845 if (!smb_fname->base_name) {
2846 TALLOC_FREE(dir_hnd);
2847 status = NT_STATUS_NO_MEMORY;
2848 TALLOC_FREE(frame);
2849 TALLOC_FREE(talloced);
2850 goto out;
2853 status = check_name(conn, smb_fname->base_name);
2854 if (!NT_STATUS_IS_OK(status)) {
2855 TALLOC_FREE(dir_hnd);
2856 TALLOC_FREE(frame);
2857 TALLOC_FREE(talloced);
2858 goto out;
2861 status = do_unlink(conn, req, smb_fname, dirtype);
2862 if (!NT_STATUS_IS_OK(status)) {
2863 TALLOC_FREE(frame);
2864 TALLOC_FREE(talloced);
2865 continue;
2868 count++;
2869 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
2870 smb_fname->base_name));
2872 TALLOC_FREE(frame);
2873 TALLOC_FREE(talloced);
2875 TALLOC_FREE(dir_hnd);
2878 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
2879 status = map_nt_error_from_unix(errno);
2882 out:
2883 TALLOC_FREE(fname_dir);
2884 TALLOC_FREE(fname_mask);
2885 return status;
2888 /****************************************************************************
2889 Reply to a unlink
2890 ****************************************************************************/
2892 void reply_unlink(struct smb_request *req)
2894 connection_struct *conn = req->conn;
2895 char *name = NULL;
2896 struct smb_filename *smb_fname = NULL;
2897 uint32 dirtype;
2898 NTSTATUS status;
2899 bool path_contains_wcard = False;
2900 TALLOC_CTX *ctx = talloc_tos();
2902 START_PROFILE(SMBunlink);
2904 if (req->wct < 1) {
2905 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2906 goto out;
2909 dirtype = SVAL(req->vwv+0, 0);
2911 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
2912 STR_TERMINATE, &status,
2913 &path_contains_wcard);
2914 if (!NT_STATUS_IS_OK(status)) {
2915 reply_nterror(req, status);
2916 goto out;
2919 status = filename_convert(ctx, conn,
2920 req->flags2 & FLAGS2_DFS_PATHNAMES,
2921 name,
2922 UCF_COND_ALLOW_WCARD_LCOMP,
2923 &path_contains_wcard,
2924 &smb_fname);
2925 if (!NT_STATUS_IS_OK(status)) {
2926 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2927 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2928 ERRSRV, ERRbadpath);
2929 goto out;
2931 reply_nterror(req, status);
2932 goto out;
2935 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
2937 status = unlink_internals(conn, req, dirtype, smb_fname,
2938 path_contains_wcard);
2939 if (!NT_STATUS_IS_OK(status)) {
2940 if (open_was_deferred(req->sconn, req->mid)) {
2941 /* We have re-scheduled this call. */
2942 goto out;
2944 reply_nterror(req, status);
2945 goto out;
2948 reply_outbuf(req, 0, 0);
2949 out:
2950 TALLOC_FREE(smb_fname);
2951 END_PROFILE(SMBunlink);
2952 return;
2955 /****************************************************************************
2956 Fail for readbraw.
2957 ****************************************************************************/
2959 static void fail_readraw(void)
2961 const char *errstr = talloc_asprintf(talloc_tos(),
2962 "FAIL ! reply_readbraw: socket write fail (%s)",
2963 strerror(errno));
2964 if (!errstr) {
2965 errstr = "";
2967 exit_server_cleanly(errstr);
2970 /****************************************************************************
2971 Fake (read/write) sendfile. Returns -1 on read or write fail.
2972 ****************************************************************************/
2974 ssize_t fake_sendfile(files_struct *fsp, off_t startpos, size_t nread)
2976 size_t bufsize;
2977 size_t tosend = nread;
2978 char *buf;
2980 if (nread == 0) {
2981 return 0;
2984 bufsize = MIN(nread, 65536);
2986 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
2987 return -1;
2990 while (tosend > 0) {
2991 ssize_t ret;
2992 size_t cur_read;
2994 if (tosend > bufsize) {
2995 cur_read = bufsize;
2996 } else {
2997 cur_read = tosend;
2999 ret = read_file(fsp,buf,startpos,cur_read);
3000 if (ret == -1) {
3001 SAFE_FREE(buf);
3002 return -1;
3005 /* If we had a short read, fill with zeros. */
3006 if (ret < cur_read) {
3007 memset(buf + ret, '\0', cur_read - ret);
3010 if (write_data(fsp->conn->sconn->sock, buf, cur_read)
3011 != cur_read) {
3012 char addr[INET6_ADDRSTRLEN];
3014 * Try and give an error message saying what
3015 * client failed.
3017 DEBUG(0, ("write_data failed for client %s. "
3018 "Error %s\n",
3019 get_peer_addr(fsp->conn->sconn->sock, addr,
3020 sizeof(addr)),
3021 strerror(errno)));
3022 SAFE_FREE(buf);
3023 return -1;
3025 tosend -= cur_read;
3026 startpos += cur_read;
3029 SAFE_FREE(buf);
3030 return (ssize_t)nread;
3033 /****************************************************************************
3034 Deal with the case of sendfile reading less bytes from the file than
3035 requested. Fill with zeros (all we can do).
3036 ****************************************************************************/
3038 void sendfile_short_send(files_struct *fsp,
3039 ssize_t nread,
3040 size_t headersize,
3041 size_t smb_maxcnt)
3043 #define SHORT_SEND_BUFSIZE 1024
3044 if (nread < headersize) {
3045 DEBUG(0,("sendfile_short_send: sendfile failed to send "
3046 "header for file %s (%s). Terminating\n",
3047 fsp_str_dbg(fsp), strerror(errno)));
3048 exit_server_cleanly("sendfile_short_send failed");
3051 nread -= headersize;
3053 if (nread < smb_maxcnt) {
3054 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
3055 if (!buf) {
3056 exit_server_cleanly("sendfile_short_send: "
3057 "malloc failed");
3060 DEBUG(0,("sendfile_short_send: filling truncated file %s "
3061 "with zeros !\n", fsp_str_dbg(fsp)));
3063 while (nread < smb_maxcnt) {
3065 * We asked for the real file size and told sendfile
3066 * to not go beyond the end of the file. But it can
3067 * happen that in between our fstat call and the
3068 * sendfile call the file was truncated. This is very
3069 * bad because we have already announced the larger
3070 * number of bytes to the client.
3072 * The best we can do now is to send 0-bytes, just as
3073 * a read from a hole in a sparse file would do.
3075 * This should happen rarely enough that I don't care
3076 * about efficiency here :-)
3078 size_t to_write;
3080 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
3081 if (write_data(fsp->conn->sconn->sock, buf, to_write)
3082 != to_write) {
3083 char addr[INET6_ADDRSTRLEN];
3085 * Try and give an error message saying what
3086 * client failed.
3088 DEBUG(0, ("write_data failed for client %s. "
3089 "Error %s\n",
3090 get_peer_addr(
3091 fsp->conn->sconn->sock, addr,
3092 sizeof(addr)),
3093 strerror(errno)));
3094 exit_server_cleanly("sendfile_short_send: "
3095 "write_data failed");
3097 nread += to_write;
3099 SAFE_FREE(buf);
3103 /****************************************************************************
3104 Return a readbraw error (4 bytes of zero).
3105 ****************************************************************************/
3107 static void reply_readbraw_error(struct smbd_server_connection *sconn)
3109 char header[4];
3111 SIVAL(header,0,0);
3113 smbd_lock_socket(sconn);
3114 if (write_data(sconn->sock,header,4) != 4) {
3115 char addr[INET6_ADDRSTRLEN];
3117 * Try and give an error message saying what
3118 * client failed.
3120 DEBUG(0, ("write_data failed for client %s. "
3121 "Error %s\n",
3122 get_peer_addr(sconn->sock, addr, sizeof(addr)),
3123 strerror(errno)));
3125 fail_readraw();
3127 smbd_unlock_socket(sconn);
3130 /****************************************************************************
3131 Use sendfile in readbraw.
3132 ****************************************************************************/
3134 static void send_file_readbraw(connection_struct *conn,
3135 struct smb_request *req,
3136 files_struct *fsp,
3137 off_t startpos,
3138 size_t nread,
3139 ssize_t mincount)
3141 struct smbd_server_connection *sconn = req->sconn;
3142 char *outbuf = NULL;
3143 ssize_t ret=0;
3146 * We can only use sendfile on a non-chained packet
3147 * but we can use on a non-oplocked file. tridge proved this
3148 * on a train in Germany :-). JRA.
3149 * reply_readbraw has already checked the length.
3152 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
3153 (fsp->wcp == NULL) &&
3154 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3155 ssize_t sendfile_read = -1;
3156 char header[4];
3157 DATA_BLOB header_blob;
3159 _smb_setlen(header,nread);
3160 header_blob = data_blob_const(header, 4);
3162 sendfile_read = SMB_VFS_SENDFILE(sconn->sock, fsp,
3163 &header_blob, startpos,
3164 nread);
3165 if (sendfile_read == -1) {
3166 /* Returning ENOSYS means no data at all was sent.
3167 * Do this as a normal read. */
3168 if (errno == ENOSYS) {
3169 goto normal_readbraw;
3173 * Special hack for broken Linux with no working sendfile. If we
3174 * return EINTR we sent the header but not the rest of the data.
3175 * Fake this up by doing read/write calls.
3177 if (errno == EINTR) {
3178 /* Ensure we don't do this again. */
3179 set_use_sendfile(SNUM(conn), False);
3180 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
3182 if (fake_sendfile(fsp, startpos, nread) == -1) {
3183 DEBUG(0,("send_file_readbraw: "
3184 "fake_sendfile failed for "
3185 "file %s (%s).\n",
3186 fsp_str_dbg(fsp),
3187 strerror(errno)));
3188 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
3190 return;
3193 DEBUG(0,("send_file_readbraw: sendfile failed for "
3194 "file %s (%s). Terminating\n",
3195 fsp_str_dbg(fsp), strerror(errno)));
3196 exit_server_cleanly("send_file_readbraw sendfile failed");
3197 } else if (sendfile_read == 0) {
3199 * Some sendfile implementations return 0 to indicate
3200 * that there was a short read, but nothing was
3201 * actually written to the socket. In this case,
3202 * fallback to the normal read path so the header gets
3203 * the correct byte count.
3205 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
3206 "bytes falling back to the normal read: "
3207 "%s\n", fsp_str_dbg(fsp)));
3208 goto normal_readbraw;
3211 /* Deal with possible short send. */
3212 if (sendfile_read != 4+nread) {
3213 sendfile_short_send(fsp, sendfile_read, 4, nread);
3215 return;
3218 normal_readbraw:
3220 outbuf = talloc_array(NULL, char, nread+4);
3221 if (!outbuf) {
3222 DEBUG(0,("send_file_readbraw: talloc_array failed for size %u.\n",
3223 (unsigned)(nread+4)));
3224 reply_readbraw_error(sconn);
3225 return;
3228 if (nread > 0) {
3229 ret = read_file(fsp,outbuf+4,startpos,nread);
3230 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3231 if (ret < mincount)
3232 ret = 0;
3233 #else
3234 if (ret < nread)
3235 ret = 0;
3236 #endif
3239 _smb_setlen(outbuf,ret);
3240 if (write_data(sconn->sock, outbuf, 4+ret) != 4+ret) {
3241 char addr[INET6_ADDRSTRLEN];
3243 * Try and give an error message saying what
3244 * client failed.
3246 DEBUG(0, ("write_data failed for client %s. "
3247 "Error %s\n",
3248 get_peer_addr(fsp->conn->sconn->sock, addr,
3249 sizeof(addr)),
3250 strerror(errno)));
3252 fail_readraw();
3255 TALLOC_FREE(outbuf);
3258 /****************************************************************************
3259 Reply to a readbraw (core+ protocol).
3260 ****************************************************************************/
3262 void reply_readbraw(struct smb_request *req)
3264 connection_struct *conn = req->conn;
3265 struct smbd_server_connection *sconn = req->sconn;
3266 ssize_t maxcount,mincount;
3267 size_t nread = 0;
3268 off_t startpos;
3269 files_struct *fsp;
3270 struct lock_struct lock;
3271 off_t size = 0;
3273 START_PROFILE(SMBreadbraw);
3275 if (srv_is_signing_active(sconn) ||
3276 is_encrypted_packet(sconn, req->inbuf)) {
3277 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3278 "raw reads/writes are disallowed.");
3281 if (req->wct < 8) {
3282 reply_readbraw_error(sconn);
3283 END_PROFILE(SMBreadbraw);
3284 return;
3287 if (sconn->smb1.echo_handler.trusted_fde) {
3288 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3289 "'async smb echo handler = yes'\n"));
3290 reply_readbraw_error(sconn);
3291 END_PROFILE(SMBreadbraw);
3292 return;
3296 * Special check if an oplock break has been issued
3297 * and the readraw request croses on the wire, we must
3298 * return a zero length response here.
3301 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3304 * We have to do a check_fsp by hand here, as
3305 * we must always return 4 zero bytes on error,
3306 * not a NTSTATUS.
3309 if (!fsp || !conn || conn != fsp->conn ||
3310 req->vuid != fsp->vuid ||
3311 fsp->is_directory || fsp->fh->fd == -1) {
3313 * fsp could be NULL here so use the value from the packet. JRA.
3315 DEBUG(3,("reply_readbraw: fnum %d not valid "
3316 "- cache prime?\n",
3317 (int)SVAL(req->vwv+0, 0)));
3318 reply_readbraw_error(sconn);
3319 END_PROFILE(SMBreadbraw);
3320 return;
3323 /* Do a "by hand" version of CHECK_READ. */
3324 if (!(fsp->can_read ||
3325 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3326 (fsp->access_mask & FILE_EXECUTE)))) {
3327 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3328 (int)SVAL(req->vwv+0, 0)));
3329 reply_readbraw_error(sconn);
3330 END_PROFILE(SMBreadbraw);
3331 return;
3334 flush_write_cache(fsp, READRAW_FLUSH);
3336 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3337 if(req->wct == 10) {
3339 * This is a large offset (64 bit) read.
3342 startpos |= (((off_t)IVAL(req->vwv+8, 0)) << 32);
3344 if(startpos < 0) {
3345 DEBUG(0,("reply_readbraw: negative 64 bit "
3346 "readraw offset (%.0f) !\n",
3347 (double)startpos ));
3348 reply_readbraw_error(sconn);
3349 END_PROFILE(SMBreadbraw);
3350 return;
3354 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3355 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3357 /* ensure we don't overrun the packet size */
3358 maxcount = MIN(65535,maxcount);
3360 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3361 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3362 &lock);
3364 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3365 reply_readbraw_error(sconn);
3366 END_PROFILE(SMBreadbraw);
3367 return;
3370 if (fsp_stat(fsp) == 0) {
3371 size = fsp->fsp_name->st.st_ex_size;
3374 if (startpos >= size) {
3375 nread = 0;
3376 } else {
3377 nread = MIN(maxcount,(size - startpos));
3380 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3381 if (nread < mincount)
3382 nread = 0;
3383 #endif
3385 DEBUG( 3, ( "reply_readbraw: %s start=%.0f max=%lu "
3386 "min=%lu nread=%lu\n",
3387 fsp_fnum_dbg(fsp), (double)startpos,
3388 (unsigned long)maxcount,
3389 (unsigned long)mincount,
3390 (unsigned long)nread ) );
3392 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3394 DEBUG(5,("reply_readbraw finished\n"));
3396 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3398 END_PROFILE(SMBreadbraw);
3399 return;
3402 #undef DBGC_CLASS
3403 #define DBGC_CLASS DBGC_LOCKING
3405 /****************************************************************************
3406 Reply to a lockread (core+ protocol).
3407 ****************************************************************************/
3409 void reply_lockread(struct smb_request *req)
3411 connection_struct *conn = req->conn;
3412 ssize_t nread = -1;
3413 char *data;
3414 off_t startpos;
3415 size_t numtoread;
3416 NTSTATUS status;
3417 files_struct *fsp;
3418 struct byte_range_lock *br_lck = NULL;
3419 char *p = NULL;
3420 struct smbd_server_connection *sconn = req->sconn;
3422 START_PROFILE(SMBlockread);
3424 if (req->wct < 5) {
3425 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3426 END_PROFILE(SMBlockread);
3427 return;
3430 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3432 if (!check_fsp(conn, req, fsp)) {
3433 END_PROFILE(SMBlockread);
3434 return;
3437 if (!CHECK_READ(fsp,req)) {
3438 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3439 END_PROFILE(SMBlockread);
3440 return;
3443 numtoread = SVAL(req->vwv+1, 0);
3444 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3446 numtoread = MIN(BUFFER_SIZE - (smb_size + 3*2 + 3), numtoread);
3448 reply_outbuf(req, 5, numtoread + 3);
3450 data = smb_buf(req->outbuf) + 3;
3453 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3454 * protocol request that predates the read/write lock concept.
3455 * Thus instead of asking for a read lock here we need to ask
3456 * for a write lock. JRA.
3457 * Note that the requested lock size is unaffected by max_recv.
3460 br_lck = do_lock(req->sconn->msg_ctx,
3461 fsp,
3462 (uint64_t)req->smbpid,
3463 (uint64_t)numtoread,
3464 (uint64_t)startpos,
3465 WRITE_LOCK,
3466 WINDOWS_LOCK,
3467 False, /* Non-blocking lock. */
3468 &status,
3469 NULL,
3470 NULL);
3471 TALLOC_FREE(br_lck);
3473 if (NT_STATUS_V(status)) {
3474 reply_nterror(req, status);
3475 END_PROFILE(SMBlockread);
3476 return;
3480 * However the requested READ size IS affected by max_recv. Insanity.... JRA.
3483 if (numtoread > sconn->smb1.negprot.max_recv) {
3484 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \
3485 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3486 (unsigned int)numtoread,
3487 (unsigned int)sconn->smb1.negprot.max_recv));
3488 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3490 nread = read_file(fsp,data,startpos,numtoread);
3492 if (nread < 0) {
3493 reply_nterror(req, map_nt_error_from_unix(errno));
3494 END_PROFILE(SMBlockread);
3495 return;
3498 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3500 SSVAL(req->outbuf,smb_vwv0,nread);
3501 SSVAL(req->outbuf,smb_vwv5,nread+3);
3502 p = smb_buf(req->outbuf);
3503 SCVAL(p,0,0); /* pad byte. */
3504 SSVAL(p,1,nread);
3506 DEBUG(3,("lockread %s num=%d nread=%d\n",
3507 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3509 END_PROFILE(SMBlockread);
3510 return;
3513 #undef DBGC_CLASS
3514 #define DBGC_CLASS DBGC_ALL
3516 /****************************************************************************
3517 Reply to a read.
3518 ****************************************************************************/
3520 void reply_read(struct smb_request *req)
3522 connection_struct *conn = req->conn;
3523 size_t numtoread;
3524 ssize_t nread = 0;
3525 char *data;
3526 off_t startpos;
3527 int outsize = 0;
3528 files_struct *fsp;
3529 struct lock_struct lock;
3530 struct smbd_server_connection *sconn = req->sconn;
3532 START_PROFILE(SMBread);
3534 if (req->wct < 3) {
3535 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3536 END_PROFILE(SMBread);
3537 return;
3540 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3542 if (!check_fsp(conn, req, fsp)) {
3543 END_PROFILE(SMBread);
3544 return;
3547 if (!CHECK_READ(fsp,req)) {
3548 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3549 END_PROFILE(SMBread);
3550 return;
3553 numtoread = SVAL(req->vwv+1, 0);
3554 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3556 numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
3559 * The requested read size cannot be greater than max_recv. JRA.
3561 if (numtoread > sconn->smb1.negprot.max_recv) {
3562 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \
3563 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3564 (unsigned int)numtoread,
3565 (unsigned int)sconn->smb1.negprot.max_recv));
3566 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3569 reply_outbuf(req, 5, numtoread+3);
3571 data = smb_buf(req->outbuf) + 3;
3573 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3574 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3575 &lock);
3577 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3578 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3579 END_PROFILE(SMBread);
3580 return;
3583 if (numtoread > 0)
3584 nread = read_file(fsp,data,startpos,numtoread);
3586 if (nread < 0) {
3587 reply_nterror(req, map_nt_error_from_unix(errno));
3588 goto strict_unlock;
3591 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3593 SSVAL(req->outbuf,smb_vwv0,nread);
3594 SSVAL(req->outbuf,smb_vwv5,nread+3);
3595 SCVAL(smb_buf(req->outbuf),0,1);
3596 SSVAL(smb_buf(req->outbuf),1,nread);
3598 DEBUG(3, ("read %s num=%d nread=%d\n",
3599 fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
3601 strict_unlock:
3602 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3604 END_PROFILE(SMBread);
3605 return;
3608 /****************************************************************************
3609 Setup readX header.
3610 ****************************************************************************/
3612 static int setup_readX_header(struct smb_request *req, char *outbuf,
3613 size_t smb_maxcnt)
3615 int outsize;
3617 outsize = srv_set_message(outbuf,12,smb_maxcnt,False);
3619 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3621 SCVAL(outbuf,smb_vwv0,0xFF);
3622 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3623 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3624 SSVAL(outbuf,smb_vwv6,
3625 (smb_wct - 4) /* offset from smb header to wct */
3626 + 1 /* the wct field */
3627 + 12 * sizeof(uint16_t) /* vwv */
3628 + 2); /* the buflen field */
3629 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3630 SSVAL(outbuf,smb_vwv11,smb_maxcnt);
3631 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3632 _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
3633 return outsize;
3636 /****************************************************************************
3637 Reply to a read and X - possibly using sendfile.
3638 ****************************************************************************/
3640 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3641 files_struct *fsp, off_t startpos,
3642 size_t smb_maxcnt)
3644 ssize_t nread = -1;
3645 struct lock_struct lock;
3646 int saved_errno = 0;
3648 if(fsp_stat(fsp) == -1) {
3649 reply_nterror(req, map_nt_error_from_unix(errno));
3650 return;
3653 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3654 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3655 &lock);
3657 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3658 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3659 return;
3662 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3663 (startpos > fsp->fsp_name->st.st_ex_size)
3664 || (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3666 * We already know that we would do a short read, so don't
3667 * try the sendfile() path.
3669 goto nosendfile_read;
3673 * We can only use sendfile on a non-chained packet
3674 * but we can use on a non-oplocked file. tridge proved this
3675 * on a train in Germany :-). JRA.
3678 if (!req_is_in_chain(req) &&
3679 !is_encrypted_packet(req->sconn, req->inbuf) &&
3680 (fsp->base_fsp == NULL) &&
3681 (fsp->wcp == NULL) &&
3682 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3683 uint8 headerbuf[smb_size + 12 * 2];
3684 DATA_BLOB header;
3687 * Set up the packet header before send. We
3688 * assume here the sendfile will work (get the
3689 * correct amount of data).
3692 header = data_blob_const(headerbuf, sizeof(headerbuf));
3694 construct_reply_common_req(req, (char *)headerbuf);
3695 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3697 nread = SMB_VFS_SENDFILE(req->sconn->sock, fsp, &header,
3698 startpos, smb_maxcnt);
3699 if (nread == -1) {
3700 /* Returning ENOSYS means no data at all was sent.
3701 Do this as a normal read. */
3702 if (errno == ENOSYS) {
3703 goto normal_read;
3707 * Special hack for broken Linux with no working sendfile. If we
3708 * return EINTR we sent the header but not the rest of the data.
3709 * Fake this up by doing read/write calls.
3712 if (errno == EINTR) {
3713 /* Ensure we don't do this again. */
3714 set_use_sendfile(SNUM(conn), False);
3715 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3716 nread = fake_sendfile(fsp, startpos,
3717 smb_maxcnt);
3718 if (nread == -1) {
3719 DEBUG(0,("send_file_readX: "
3720 "fake_sendfile failed for "
3721 "file %s (%s).\n",
3722 fsp_str_dbg(fsp),
3723 strerror(errno)));
3724 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3726 DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
3727 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3728 /* No outbuf here means successful sendfile. */
3729 goto strict_unlock;
3732 DEBUG(0,("send_file_readX: sendfile failed for file "
3733 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3734 strerror(errno)));
3735 exit_server_cleanly("send_file_readX sendfile failed");
3736 } else if (nread == 0) {
3738 * Some sendfile implementations return 0 to indicate
3739 * that there was a short read, but nothing was
3740 * actually written to the socket. In this case,
3741 * fallback to the normal read path so the header gets
3742 * the correct byte count.
3744 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
3745 "falling back to the normal read: %s\n",
3746 fsp_str_dbg(fsp)));
3747 goto normal_read;
3750 DEBUG(3, ("send_file_readX: sendfile %s max=%d nread=%d\n",
3751 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3753 /* Deal with possible short send. */
3754 if (nread != smb_maxcnt + sizeof(headerbuf)) {
3755 sendfile_short_send(fsp, nread, sizeof(headerbuf), smb_maxcnt);
3757 /* No outbuf here means successful sendfile. */
3758 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
3759 SMB_PERFCOUNT_END(&req->pcd);
3760 goto strict_unlock;
3763 normal_read:
3765 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3766 uint8 headerbuf[smb_size + 2*12];
3768 construct_reply_common_req(req, (char *)headerbuf);
3769 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3771 /* Send out the header. */
3772 if (write_data(req->sconn->sock, (char *)headerbuf,
3773 sizeof(headerbuf)) != sizeof(headerbuf)) {
3775 char addr[INET6_ADDRSTRLEN];
3777 * Try and give an error message saying what
3778 * client failed.
3780 DEBUG(0, ("write_data failed for client %s. "
3781 "Error %s\n",
3782 get_peer_addr(req->sconn->sock, addr,
3783 sizeof(addr)),
3784 strerror(errno)));
3786 DEBUG(0,("send_file_readX: write_data failed for file "
3787 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3788 strerror(errno)));
3789 exit_server_cleanly("send_file_readX sendfile failed");
3791 nread = fake_sendfile(fsp, startpos, smb_maxcnt);
3792 if (nread == -1) {
3793 DEBUG(0,("send_file_readX: fake_sendfile failed for "
3794 "file %s (%s).\n", fsp_str_dbg(fsp),
3795 strerror(errno)));
3796 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3798 goto strict_unlock;
3801 nosendfile_read:
3803 reply_outbuf(req, 12, smb_maxcnt);
3804 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
3805 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
3807 nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt);
3808 saved_errno = errno;
3810 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3812 if (nread < 0) {
3813 reply_nterror(req, map_nt_error_from_unix(saved_errno));
3814 return;
3817 setup_readX_header(req, (char *)req->outbuf, nread);
3819 DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
3820 fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
3821 return;
3823 strict_unlock:
3824 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3825 TALLOC_FREE(req->outbuf);
3826 return;
3829 /****************************************************************************
3830 Reply to a read and X.
3831 ****************************************************************************/
3833 void reply_read_and_X(struct smb_request *req)
3835 struct smbd_server_connection *sconn = req->sconn;
3836 connection_struct *conn = req->conn;
3837 files_struct *fsp;
3838 off_t startpos;
3839 size_t smb_maxcnt;
3840 bool big_readX = False;
3841 #if 0
3842 size_t smb_mincnt = SVAL(req->vwv+6, 0);
3843 #endif
3845 START_PROFILE(SMBreadX);
3847 if ((req->wct != 10) && (req->wct != 12)) {
3848 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3849 return;
3852 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
3853 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3854 smb_maxcnt = SVAL(req->vwv+5, 0);
3856 /* If it's an IPC, pass off the pipe handler. */
3857 if (IS_IPC(conn)) {
3858 reply_pipe_read_and_X(req);
3859 END_PROFILE(SMBreadX);
3860 return;
3863 if (!check_fsp(conn, req, fsp)) {
3864 END_PROFILE(SMBreadX);
3865 return;
3868 if (!CHECK_READ(fsp,req)) {
3869 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3870 END_PROFILE(SMBreadX);
3871 return;
3874 if ((sconn->smb1.unix_info.client_cap_low & CIFS_UNIX_LARGE_READ_CAP) ||
3875 (get_remote_arch() == RA_SAMBA)) {
3877 * This is Samba only behavior (up to Samba 3.6)!
3879 * Windows 2008 R2 ignores the upper_size,
3880 * so we do unless unix extentions are active
3881 * or "smbclient" is talking to us.
3883 size_t upper_size = SVAL(req->vwv+7, 0);
3884 smb_maxcnt |= (upper_size<<16);
3885 if (upper_size > 1) {
3886 /* Can't do this on a chained packet. */
3887 if ((CVAL(req->vwv+0, 0) != 0xFF)) {
3888 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3889 END_PROFILE(SMBreadX);
3890 return;
3892 /* We currently don't do this on signed or sealed data. */
3893 if (srv_is_signing_active(req->sconn) ||
3894 is_encrypted_packet(req->sconn, req->inbuf)) {
3895 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3896 END_PROFILE(SMBreadX);
3897 return;
3899 /* Is there room in the reply for this data ? */
3900 if (smb_maxcnt > (0xFFFFFF - (smb_size -4 + 12*2))) {
3901 reply_nterror(req,
3902 NT_STATUS_INVALID_PARAMETER);
3903 END_PROFILE(SMBreadX);
3904 return;
3906 big_readX = True;
3910 if (req->wct == 12) {
3912 * This is a large offset (64 bit) read.
3914 startpos |= (((off_t)IVAL(req->vwv+10, 0)) << 32);
3918 if (!big_readX) {
3919 NTSTATUS status = schedule_aio_read_and_X(conn,
3920 req,
3921 fsp,
3922 startpos,
3923 smb_maxcnt);
3924 if (NT_STATUS_IS_OK(status)) {
3925 /* Read scheduled - we're done. */
3926 goto out;
3928 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
3929 /* Real error - report to client. */
3930 END_PROFILE(SMBreadX);
3931 reply_nterror(req, status);
3932 return;
3934 /* NT_STATUS_RETRY - fall back to sync read. */
3937 smbd_lock_socket(req->sconn);
3938 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
3939 smbd_unlock_socket(req->sconn);
3941 out:
3942 END_PROFILE(SMBreadX);
3943 return;
3946 /****************************************************************************
3947 Error replies to writebraw must have smb_wct == 1. Fix this up.
3948 ****************************************************************************/
3950 void error_to_writebrawerr(struct smb_request *req)
3952 uint8 *old_outbuf = req->outbuf;
3954 reply_outbuf(req, 1, 0);
3956 memcpy(req->outbuf, old_outbuf, smb_size);
3957 TALLOC_FREE(old_outbuf);
3960 /****************************************************************************
3961 Read 4 bytes of a smb packet and return the smb length of the packet.
3962 Store the result in the buffer. This version of the function will
3963 never return a session keepalive (length of zero).
3964 Timeout is in milliseconds.
3965 ****************************************************************************/
3967 static NTSTATUS read_smb_length(int fd, char *inbuf, unsigned int timeout,
3968 size_t *len)
3970 uint8_t msgtype = NBSSkeepalive;
3972 while (msgtype == NBSSkeepalive) {
3973 NTSTATUS status;
3975 status = read_smb_length_return_keepalive(fd, inbuf, timeout,
3976 len);
3977 if (!NT_STATUS_IS_OK(status)) {
3978 char addr[INET6_ADDRSTRLEN];
3979 /* Try and give an error message
3980 * saying what client failed. */
3981 DEBUG(0, ("read_fd_with_timeout failed for "
3982 "client %s read error = %s.\n",
3983 get_peer_addr(fd,addr,sizeof(addr)),
3984 nt_errstr(status)));
3985 return status;
3988 msgtype = CVAL(inbuf, 0);
3991 DEBUG(10,("read_smb_length: got smb length of %lu\n",
3992 (unsigned long)len));
3994 return NT_STATUS_OK;
3997 /****************************************************************************
3998 Reply to a writebraw (core+ or LANMAN1.0 protocol).
3999 ****************************************************************************/
4001 void reply_writebraw(struct smb_request *req)
4003 connection_struct *conn = req->conn;
4004 char *buf = NULL;
4005 ssize_t nwritten=0;
4006 ssize_t total_written=0;
4007 size_t numtowrite=0;
4008 size_t tcount;
4009 off_t startpos;
4010 const char *data=NULL;
4011 bool write_through;
4012 files_struct *fsp;
4013 struct lock_struct lock;
4014 NTSTATUS status;
4016 START_PROFILE(SMBwritebraw);
4019 * If we ever reply with an error, it must have the SMB command
4020 * type of SMBwritec, not SMBwriteBraw, as this tells the client
4021 * we're finished.
4023 SCVAL(discard_const_p(uint8_t, req->inbuf),smb_com,SMBwritec);
4025 if (srv_is_signing_active(req->sconn)) {
4026 END_PROFILE(SMBwritebraw);
4027 exit_server_cleanly("reply_writebraw: SMB signing is active - "
4028 "raw reads/writes are disallowed.");
4031 if (req->wct < 12) {
4032 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4033 error_to_writebrawerr(req);
4034 END_PROFILE(SMBwritebraw);
4035 return;
4038 if (req->sconn->smb1.echo_handler.trusted_fde) {
4039 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
4040 "'async smb echo handler = yes'\n"));
4041 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
4042 error_to_writebrawerr(req);
4043 END_PROFILE(SMBwritebraw);
4044 return;
4047 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4048 if (!check_fsp(conn, req, fsp)) {
4049 error_to_writebrawerr(req);
4050 END_PROFILE(SMBwritebraw);
4051 return;
4054 if (!CHECK_WRITE(fsp)) {
4055 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4056 error_to_writebrawerr(req);
4057 END_PROFILE(SMBwritebraw);
4058 return;
4061 tcount = IVAL(req->vwv+1, 0);
4062 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4063 write_through = BITSETW(req->vwv+7,0);
4065 /* We have to deal with slightly different formats depending
4066 on whether we are using the core+ or lanman1.0 protocol */
4068 if(get_Protocol() <= PROTOCOL_COREPLUS) {
4069 numtowrite = SVAL(smb_buf_const(req->inbuf),-2);
4070 data = smb_buf_const(req->inbuf);
4071 } else {
4072 numtowrite = SVAL(req->vwv+10, 0);
4073 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
4076 /* Ensure we don't write bytes past the end of this packet. */
4077 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
4078 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4079 error_to_writebrawerr(req);
4080 END_PROFILE(SMBwritebraw);
4081 return;
4084 if (!fsp->print_file) {
4085 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4086 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
4087 &lock);
4089 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4090 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4091 error_to_writebrawerr(req);
4092 END_PROFILE(SMBwritebraw);
4093 return;
4097 if (numtowrite>0) {
4098 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4101 DEBUG(3, ("reply_writebraw: initial write %s start=%.0f num=%d "
4102 "wrote=%d sync=%d\n",
4103 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4104 (int)nwritten, (int)write_through));
4106 if (nwritten < (ssize_t)numtowrite) {
4107 reply_nterror(req, NT_STATUS_DISK_FULL);
4108 error_to_writebrawerr(req);
4109 goto strict_unlock;
4112 total_written = nwritten;
4114 /* Allocate a buffer of 64k + length. */
4115 buf = talloc_array(NULL, char, 65540);
4116 if (!buf) {
4117 reply_nterror(req, NT_STATUS_NO_MEMORY);
4118 error_to_writebrawerr(req);
4119 goto strict_unlock;
4122 /* Return a SMBwritebraw message to the redirector to tell
4123 * it to send more bytes */
4125 memcpy(buf, req->inbuf, smb_size);
4126 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
4127 SCVAL(buf,smb_com,SMBwritebraw);
4128 SSVALS(buf,smb_vwv0,0xFFFF);
4129 show_msg(buf);
4130 if (!srv_send_smb(req->sconn,
4131 buf,
4132 false, 0, /* no signing */
4133 IS_CONN_ENCRYPTED(conn),
4134 &req->pcd)) {
4135 exit_server_cleanly("reply_writebraw: srv_send_smb "
4136 "failed.");
4139 /* Now read the raw data into the buffer and write it */
4140 status = read_smb_length(req->sconn->sock, buf, SMB_SECONDARY_WAIT,
4141 &numtowrite);
4142 if (!NT_STATUS_IS_OK(status)) {
4143 exit_server_cleanly("secondary writebraw failed");
4146 /* Set up outbuf to return the correct size */
4147 reply_outbuf(req, 1, 0);
4149 if (numtowrite != 0) {
4151 if (numtowrite > 0xFFFF) {
4152 DEBUG(0,("reply_writebraw: Oversize secondary write "
4153 "raw requested (%u). Terminating\n",
4154 (unsigned int)numtowrite ));
4155 exit_server_cleanly("secondary writebraw failed");
4158 if (tcount > nwritten+numtowrite) {
4159 DEBUG(3,("reply_writebraw: Client overestimated the "
4160 "write %d %d %d\n",
4161 (int)tcount,(int)nwritten,(int)numtowrite));
4164 status = read_data(req->sconn->sock, buf+4, numtowrite);
4166 if (!NT_STATUS_IS_OK(status)) {
4167 char addr[INET6_ADDRSTRLEN];
4168 /* Try and give an error message
4169 * saying what client failed. */
4170 DEBUG(0, ("reply_writebraw: Oversize secondary write "
4171 "raw read failed (%s) for client %s. "
4172 "Terminating\n", nt_errstr(status),
4173 get_peer_addr(req->sconn->sock, addr,
4174 sizeof(addr))));
4175 exit_server_cleanly("secondary writebraw failed");
4178 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
4179 if (nwritten == -1) {
4180 TALLOC_FREE(buf);
4181 reply_nterror(req, map_nt_error_from_unix(errno));
4182 error_to_writebrawerr(req);
4183 goto strict_unlock;
4186 if (nwritten < (ssize_t)numtowrite) {
4187 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4188 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4191 if (nwritten > 0) {
4192 total_written += nwritten;
4196 TALLOC_FREE(buf);
4197 SSVAL(req->outbuf,smb_vwv0,total_written);
4199 status = sync_file(conn, fsp, write_through);
4200 if (!NT_STATUS_IS_OK(status)) {
4201 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
4202 fsp_str_dbg(fsp), nt_errstr(status)));
4203 reply_nterror(req, status);
4204 error_to_writebrawerr(req);
4205 goto strict_unlock;
4208 DEBUG(3,("reply_writebraw: secondart write %s start=%.0f num=%d "
4209 "wrote=%d\n",
4210 fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
4211 (int)total_written));
4213 if (!fsp->print_file) {
4214 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4217 /* We won't return a status if write through is not selected - this
4218 * follows what WfWg does */
4219 END_PROFILE(SMBwritebraw);
4221 if (!write_through && total_written==tcount) {
4223 #if RABBIT_PELLET_FIX
4225 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
4226 * sending a NBSSkeepalive. Thanks to DaveCB at Sun for this.
4227 * JRA.
4229 if (!send_keepalive(req->sconn->sock)) {
4230 exit_server_cleanly("reply_writebraw: send of "
4231 "keepalive failed");
4233 #endif
4234 TALLOC_FREE(req->outbuf);
4236 return;
4238 strict_unlock:
4239 if (!fsp->print_file) {
4240 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4243 END_PROFILE(SMBwritebraw);
4244 return;
4247 #undef DBGC_CLASS
4248 #define DBGC_CLASS DBGC_LOCKING
4250 /****************************************************************************
4251 Reply to a writeunlock (core+).
4252 ****************************************************************************/
4254 void reply_writeunlock(struct smb_request *req)
4256 connection_struct *conn = req->conn;
4257 ssize_t nwritten = -1;
4258 size_t numtowrite;
4259 off_t startpos;
4260 const char *data;
4261 NTSTATUS status = NT_STATUS_OK;
4262 files_struct *fsp;
4263 struct lock_struct lock;
4264 int saved_errno = 0;
4266 START_PROFILE(SMBwriteunlock);
4268 if (req->wct < 5) {
4269 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4270 END_PROFILE(SMBwriteunlock);
4271 return;
4274 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4276 if (!check_fsp(conn, req, fsp)) {
4277 END_PROFILE(SMBwriteunlock);
4278 return;
4281 if (!CHECK_WRITE(fsp)) {
4282 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4283 END_PROFILE(SMBwriteunlock);
4284 return;
4287 numtowrite = SVAL(req->vwv+1, 0);
4288 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4289 data = (const char *)req->buf + 3;
4291 if (!fsp->print_file && numtowrite > 0) {
4292 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4293 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4294 &lock);
4296 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4297 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4298 END_PROFILE(SMBwriteunlock);
4299 return;
4303 /* The special X/Open SMB protocol handling of
4304 zero length writes is *NOT* done for
4305 this call */
4306 if(numtowrite == 0) {
4307 nwritten = 0;
4308 } else {
4309 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4310 saved_errno = errno;
4313 status = sync_file(conn, fsp, False /* write through */);
4314 if (!NT_STATUS_IS_OK(status)) {
4315 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4316 fsp_str_dbg(fsp), nt_errstr(status)));
4317 reply_nterror(req, status);
4318 goto strict_unlock;
4321 if(nwritten < 0) {
4322 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4323 goto strict_unlock;
4326 if((nwritten < numtowrite) && (numtowrite != 0)) {
4327 reply_nterror(req, NT_STATUS_DISK_FULL);
4328 goto strict_unlock;
4331 if (numtowrite && !fsp->print_file) {
4332 status = do_unlock(req->sconn->msg_ctx,
4333 fsp,
4334 (uint64_t)req->smbpid,
4335 (uint64_t)numtowrite,
4336 (uint64_t)startpos,
4337 WINDOWS_LOCK);
4339 if (NT_STATUS_V(status)) {
4340 reply_nterror(req, status);
4341 goto strict_unlock;
4345 reply_outbuf(req, 1, 0);
4347 SSVAL(req->outbuf,smb_vwv0,nwritten);
4349 DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
4350 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4352 strict_unlock:
4353 if (numtowrite && !fsp->print_file) {
4354 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4357 END_PROFILE(SMBwriteunlock);
4358 return;
4361 #undef DBGC_CLASS
4362 #define DBGC_CLASS DBGC_ALL
4364 /****************************************************************************
4365 Reply to a write.
4366 ****************************************************************************/
4368 void reply_write(struct smb_request *req)
4370 connection_struct *conn = req->conn;
4371 size_t numtowrite;
4372 ssize_t nwritten = -1;
4373 off_t startpos;
4374 const char *data;
4375 files_struct *fsp;
4376 struct lock_struct lock;
4377 NTSTATUS status;
4378 int saved_errno = 0;
4380 START_PROFILE(SMBwrite);
4382 if (req->wct < 5) {
4383 END_PROFILE(SMBwrite);
4384 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4385 return;
4388 /* If it's an IPC, pass off the pipe handler. */
4389 if (IS_IPC(conn)) {
4390 reply_pipe_write(req);
4391 END_PROFILE(SMBwrite);
4392 return;
4395 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4397 if (!check_fsp(conn, req, fsp)) {
4398 END_PROFILE(SMBwrite);
4399 return;
4402 if (!CHECK_WRITE(fsp)) {
4403 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4404 END_PROFILE(SMBwrite);
4405 return;
4408 numtowrite = SVAL(req->vwv+1, 0);
4409 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4410 data = (const char *)req->buf + 3;
4412 if (!fsp->print_file) {
4413 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4414 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4415 &lock);
4417 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4418 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4419 END_PROFILE(SMBwrite);
4420 return;
4425 * X/Open SMB protocol says that if smb_vwv1 is
4426 * zero then the file size should be extended or
4427 * truncated to the size given in smb_vwv[2-3].
4430 if(numtowrite == 0) {
4432 * This is actually an allocate call, and set EOF. JRA.
4434 nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
4435 if (nwritten < 0) {
4436 reply_nterror(req, NT_STATUS_DISK_FULL);
4437 goto strict_unlock;
4439 nwritten = vfs_set_filelen(fsp, (off_t)startpos);
4440 if (nwritten < 0) {
4441 reply_nterror(req, NT_STATUS_DISK_FULL);
4442 goto strict_unlock;
4444 trigger_write_time_update_immediate(fsp);
4445 } else {
4446 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4449 status = sync_file(conn, fsp, False);
4450 if (!NT_STATUS_IS_OK(status)) {
4451 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4452 fsp_str_dbg(fsp), nt_errstr(status)));
4453 reply_nterror(req, status);
4454 goto strict_unlock;
4457 if(nwritten < 0) {
4458 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4459 goto strict_unlock;
4462 if((nwritten == 0) && (numtowrite != 0)) {
4463 reply_nterror(req, NT_STATUS_DISK_FULL);
4464 goto strict_unlock;
4467 reply_outbuf(req, 1, 0);
4469 SSVAL(req->outbuf,smb_vwv0,nwritten);
4471 if (nwritten < (ssize_t)numtowrite) {
4472 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4473 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4476 DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4478 strict_unlock:
4479 if (!fsp->print_file) {
4480 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4483 END_PROFILE(SMBwrite);
4484 return;
4487 /****************************************************************************
4488 Ensure a buffer is a valid writeX for recvfile purposes.
4489 ****************************************************************************/
4491 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4492 (2*14) + /* word count (including bcc) */ \
4493 1 /* pad byte */)
4495 bool is_valid_writeX_buffer(struct smbd_server_connection *sconn,
4496 const uint8_t *inbuf)
4498 size_t numtowrite;
4499 connection_struct *conn = NULL;
4500 unsigned int doff = 0;
4501 size_t len = smb_len_large(inbuf);
4502 struct smbXsrv_tcon *tcon;
4503 NTSTATUS status;
4504 NTTIME now = 0;
4506 if (is_encrypted_packet(sconn, inbuf)) {
4507 /* Can't do this on encrypted
4508 * connections. */
4509 return false;
4512 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4513 return false;
4516 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4517 CVAL(inbuf,smb_wct) != 14) {
4518 DEBUG(10,("is_valid_writeX_buffer: chained or "
4519 "invalid word length.\n"));
4520 return false;
4523 status = smb1srv_tcon_lookup(sconn->conn, SVAL(inbuf, smb_tid),
4524 now, &tcon);
4525 if (!NT_STATUS_IS_OK(status)) {
4526 DEBUG(10,("is_valid_writeX_buffer: bad tid\n"));
4527 return false;
4529 conn = tcon->compat;
4531 if (IS_IPC(conn)) {
4532 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4533 return false;
4535 if (IS_PRINT(conn)) {
4536 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4537 return false;
4539 doff = SVAL(inbuf,smb_vwv11);
4541 numtowrite = SVAL(inbuf,smb_vwv10);
4543 if (len > doff && len - doff > 0xFFFF) {
4544 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4547 if (numtowrite == 0) {
4548 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4549 return false;
4552 /* Ensure the sizes match up. */
4553 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4554 /* no pad byte...old smbclient :-( */
4555 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4556 (unsigned int)doff,
4557 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4558 return false;
4561 if (len - doff != numtowrite) {
4562 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4563 "len = %u, doff = %u, numtowrite = %u\n",
4564 (unsigned int)len,
4565 (unsigned int)doff,
4566 (unsigned int)numtowrite ));
4567 return false;
4570 DEBUG(10,("is_valid_writeX_buffer: true "
4571 "len = %u, doff = %u, numtowrite = %u\n",
4572 (unsigned int)len,
4573 (unsigned int)doff,
4574 (unsigned int)numtowrite ));
4576 return true;
4579 /****************************************************************************
4580 Reply to a write and X.
4581 ****************************************************************************/
4583 void reply_write_and_X(struct smb_request *req)
4585 connection_struct *conn = req->conn;
4586 files_struct *fsp;
4587 struct lock_struct lock;
4588 off_t startpos;
4589 size_t numtowrite;
4590 bool write_through;
4591 ssize_t nwritten;
4592 unsigned int smb_doff;
4593 unsigned int smblen;
4594 const char *data;
4595 NTSTATUS status;
4596 int saved_errno = 0;
4598 START_PROFILE(SMBwriteX);
4600 if ((req->wct != 12) && (req->wct != 14)) {
4601 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4602 goto out;
4605 numtowrite = SVAL(req->vwv+10, 0);
4606 smb_doff = SVAL(req->vwv+11, 0);
4607 smblen = smb_len(req->inbuf);
4609 if (req->unread_bytes > 0xFFFF ||
4610 (smblen > smb_doff &&
4611 smblen - smb_doff > 0xFFFF)) {
4612 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
4615 if (req->unread_bytes) {
4616 /* Can't do a recvfile write on IPC$ */
4617 if (IS_IPC(conn)) {
4618 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4619 goto out;
4621 if (numtowrite != req->unread_bytes) {
4622 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4623 goto out;
4625 } else {
4626 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4627 smb_doff + numtowrite > smblen) {
4628 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4629 goto out;
4633 /* If it's an IPC, pass off the pipe handler. */
4634 if (IS_IPC(conn)) {
4635 if (req->unread_bytes) {
4636 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4637 goto out;
4639 reply_pipe_write_and_X(req);
4640 goto out;
4643 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4644 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4645 write_through = BITSETW(req->vwv+7,0);
4647 if (!check_fsp(conn, req, fsp)) {
4648 goto out;
4651 if (!CHECK_WRITE(fsp)) {
4652 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4653 goto out;
4656 data = smb_base(req->inbuf) + smb_doff;
4658 if(req->wct == 14) {
4660 * This is a large offset (64 bit) write.
4662 startpos |= (((off_t)IVAL(req->vwv+12, 0)) << 32);
4666 /* X/Open SMB protocol says that, unlike SMBwrite
4667 if the length is zero then NO truncation is
4668 done, just a write of zero. To truncate a file,
4669 use SMBwrite. */
4671 if(numtowrite == 0) {
4672 nwritten = 0;
4673 } else {
4674 if (req->unread_bytes == 0) {
4675 status = schedule_aio_write_and_X(conn,
4676 req,
4677 fsp,
4678 data,
4679 startpos,
4680 numtowrite);
4682 if (NT_STATUS_IS_OK(status)) {
4683 /* write scheduled - we're done. */
4684 goto out;
4686 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4687 /* Real error - report to client. */
4688 reply_nterror(req, status);
4689 goto out;
4691 /* NT_STATUS_RETRY - fall through to sync write. */
4694 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4695 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4696 &lock);
4698 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4699 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4700 goto out;
4703 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4704 saved_errno = errno;
4706 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4709 if(nwritten < 0) {
4710 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4711 goto out;
4714 if((nwritten == 0) && (numtowrite != 0)) {
4715 reply_nterror(req, NT_STATUS_DISK_FULL);
4716 goto out;
4719 reply_outbuf(req, 6, 0);
4720 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
4721 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
4722 SSVAL(req->outbuf,smb_vwv2,nwritten);
4723 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4725 DEBUG(3,("writeX %s num=%d wrote=%d\n",
4726 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
4728 status = sync_file(conn, fsp, write_through);
4729 if (!NT_STATUS_IS_OK(status)) {
4730 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4731 fsp_str_dbg(fsp), nt_errstr(status)));
4732 reply_nterror(req, status);
4733 goto out;
4736 END_PROFILE(SMBwriteX);
4737 return;
4739 out:
4740 if (req->unread_bytes) {
4741 /* writeX failed. drain socket. */
4742 if (drain_socket(req->sconn->sock, req->unread_bytes) !=
4743 req->unread_bytes) {
4744 smb_panic("failed to drain pending bytes");
4746 req->unread_bytes = 0;
4749 END_PROFILE(SMBwriteX);
4750 return;
4753 /****************************************************************************
4754 Reply to a lseek.
4755 ****************************************************************************/
4757 void reply_lseek(struct smb_request *req)
4759 connection_struct *conn = req->conn;
4760 off_t startpos;
4761 off_t res= -1;
4762 int mode,umode;
4763 files_struct *fsp;
4765 START_PROFILE(SMBlseek);
4767 if (req->wct < 4) {
4768 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4769 END_PROFILE(SMBlseek);
4770 return;
4773 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4775 if (!check_fsp(conn, req, fsp)) {
4776 return;
4779 flush_write_cache(fsp, SEEK_FLUSH);
4781 mode = SVAL(req->vwv+1, 0) & 3;
4782 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4783 startpos = (off_t)IVALS(req->vwv+2, 0);
4785 switch (mode) {
4786 case 0:
4787 umode = SEEK_SET;
4788 res = startpos;
4789 break;
4790 case 1:
4791 umode = SEEK_CUR;
4792 res = fsp->fh->pos + startpos;
4793 break;
4794 case 2:
4795 umode = SEEK_END;
4796 break;
4797 default:
4798 umode = SEEK_SET;
4799 res = startpos;
4800 break;
4803 if (umode == SEEK_END) {
4804 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
4805 if(errno == EINVAL) {
4806 off_t current_pos = startpos;
4808 if(fsp_stat(fsp) == -1) {
4809 reply_nterror(req,
4810 map_nt_error_from_unix(errno));
4811 END_PROFILE(SMBlseek);
4812 return;
4815 current_pos += fsp->fsp_name->st.st_ex_size;
4816 if(current_pos < 0)
4817 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
4821 if(res == -1) {
4822 reply_nterror(req, map_nt_error_from_unix(errno));
4823 END_PROFILE(SMBlseek);
4824 return;
4828 fsp->fh->pos = res;
4830 reply_outbuf(req, 2, 0);
4831 SIVAL(req->outbuf,smb_vwv0,res);
4833 DEBUG(3,("lseek %s ofs=%.0f newpos = %.0f mode=%d\n",
4834 fsp_fnum_dbg(fsp), (double)startpos, (double)res, mode));
4836 END_PROFILE(SMBlseek);
4837 return;
4840 /****************************************************************************
4841 Reply to a flush.
4842 ****************************************************************************/
4844 void reply_flush(struct smb_request *req)
4846 connection_struct *conn = req->conn;
4847 uint16 fnum;
4848 files_struct *fsp;
4850 START_PROFILE(SMBflush);
4852 if (req->wct < 1) {
4853 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4854 return;
4857 fnum = SVAL(req->vwv+0, 0);
4858 fsp = file_fsp(req, fnum);
4860 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
4861 return;
4864 if (!fsp) {
4865 file_sync_all(conn);
4866 } else {
4867 NTSTATUS status = sync_file(conn, fsp, True);
4868 if (!NT_STATUS_IS_OK(status)) {
4869 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
4870 fsp_str_dbg(fsp), nt_errstr(status)));
4871 reply_nterror(req, status);
4872 END_PROFILE(SMBflush);
4873 return;
4877 reply_outbuf(req, 0, 0);
4879 DEBUG(3,("flush\n"));
4880 END_PROFILE(SMBflush);
4881 return;
4884 /****************************************************************************
4885 Reply to a exit.
4886 conn POINTER CAN BE NULL HERE !
4887 ****************************************************************************/
4889 void reply_exit(struct smb_request *req)
4891 START_PROFILE(SMBexit);
4893 file_close_pid(req->sconn, req->smbpid, req->vuid);
4895 reply_outbuf(req, 0, 0);
4897 DEBUG(3,("exit\n"));
4899 END_PROFILE(SMBexit);
4900 return;
4903 struct reply_close_state {
4904 files_struct *fsp;
4905 struct smb_request *smbreq;
4908 static void do_smb1_close(struct tevent_req *req);
4910 void reply_close(struct smb_request *req)
4912 connection_struct *conn = req->conn;
4913 NTSTATUS status = NT_STATUS_OK;
4914 files_struct *fsp = NULL;
4915 START_PROFILE(SMBclose);
4917 if (req->wct < 3) {
4918 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4919 END_PROFILE(SMBclose);
4920 return;
4923 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4926 * We can only use check_fsp if we know it's not a directory.
4929 if (!check_fsp_open(conn, req, fsp)) {
4930 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
4931 END_PROFILE(SMBclose);
4932 return;
4935 DEBUG(3, ("Close %s fd=%d %s (numopen=%d)\n",
4936 fsp->is_directory ? "directory" : "file",
4937 fsp->fh->fd, fsp_fnum_dbg(fsp),
4938 conn->num_files_open));
4940 if (!fsp->is_directory) {
4941 time_t t;
4944 * Take care of any time sent in the close.
4947 t = srv_make_unix_date3(req->vwv+1);
4948 set_close_write_time(fsp, convert_time_t_to_timespec(t));
4951 if (fsp->num_aio_requests != 0) {
4953 struct reply_close_state *state;
4955 DEBUG(10, ("closing with aio %u requests pending\n",
4956 fsp->num_aio_requests));
4959 * We depend on the aio_extra destructor to take care of this
4960 * close request once fsp->num_aio_request drops to 0.
4963 fsp->deferred_close = tevent_wait_send(
4964 fsp, fsp->conn->sconn->ev_ctx);
4965 if (fsp->deferred_close == NULL) {
4966 status = NT_STATUS_NO_MEMORY;
4967 goto done;
4970 state = talloc(fsp, struct reply_close_state);
4971 if (state == NULL) {
4972 TALLOC_FREE(fsp->deferred_close);
4973 status = NT_STATUS_NO_MEMORY;
4974 goto done;
4976 state->fsp = fsp;
4977 state->smbreq = talloc_move(fsp, &req);
4978 tevent_req_set_callback(fsp->deferred_close, do_smb1_close,
4979 state);
4980 END_PROFILE(SMBclose);
4981 return;
4985 * close_file() returns the unix errno if an error was detected on
4986 * close - normally this is due to a disk full error. If not then it
4987 * was probably an I/O error.
4990 status = close_file(req, fsp, NORMAL_CLOSE);
4991 done:
4992 if (!NT_STATUS_IS_OK(status)) {
4993 reply_nterror(req, status);
4994 END_PROFILE(SMBclose);
4995 return;
4998 reply_outbuf(req, 0, 0);
4999 END_PROFILE(SMBclose);
5000 return;
5003 static void do_smb1_close(struct tevent_req *req)
5005 struct reply_close_state *state = tevent_req_callback_data(
5006 req, struct reply_close_state);
5007 struct smb_request *smbreq;
5008 NTSTATUS status;
5009 int ret;
5011 ret = tevent_wait_recv(req);
5012 TALLOC_FREE(req);
5013 if (ret != 0) {
5014 DEBUG(10, ("tevent_wait_recv returned %s\n",
5015 strerror(ret)));
5017 * Continue anyway, this should never happen
5022 * fsp->smb2_close_request right now is a talloc grandchild of
5023 * fsp. When we close_file(fsp), it would go with it. No chance to
5024 * reply...
5026 smbreq = talloc_move(talloc_tos(), &state->smbreq);
5028 status = close_file(smbreq, state->fsp, NORMAL_CLOSE);
5029 if (NT_STATUS_IS_OK(status)) {
5030 reply_outbuf(smbreq, 0, 0);
5031 } else {
5032 reply_nterror(smbreq, status);
5034 if (!srv_send_smb(smbreq->sconn,
5035 (char *)smbreq->outbuf,
5036 true,
5037 smbreq->seqnum+1,
5038 IS_CONN_ENCRYPTED(smbreq->conn)||smbreq->encrypted,
5039 NULL)) {
5040 exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
5041 "failed.");
5043 TALLOC_FREE(smbreq);
5046 /****************************************************************************
5047 Reply to a writeclose (Core+ protocol).
5048 ****************************************************************************/
5050 void reply_writeclose(struct smb_request *req)
5052 connection_struct *conn = req->conn;
5053 size_t numtowrite;
5054 ssize_t nwritten = -1;
5055 NTSTATUS close_status = NT_STATUS_OK;
5056 off_t startpos;
5057 const char *data;
5058 struct timespec mtime;
5059 files_struct *fsp;
5060 struct lock_struct lock;
5062 START_PROFILE(SMBwriteclose);
5064 if (req->wct < 6) {
5065 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5066 END_PROFILE(SMBwriteclose);
5067 return;
5070 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5072 if (!check_fsp(conn, req, fsp)) {
5073 END_PROFILE(SMBwriteclose);
5074 return;
5076 if (!CHECK_WRITE(fsp)) {
5077 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5078 END_PROFILE(SMBwriteclose);
5079 return;
5082 numtowrite = SVAL(req->vwv+1, 0);
5083 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
5084 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
5085 data = (const char *)req->buf + 1;
5087 if (!fsp->print_file) {
5088 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
5089 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
5090 &lock);
5092 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
5093 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
5094 END_PROFILE(SMBwriteclose);
5095 return;
5099 nwritten = write_file(req,fsp,data,startpos,numtowrite);
5101 set_close_write_time(fsp, mtime);
5104 * More insanity. W2K only closes the file if writelen > 0.
5105 * JRA.
5108 if (numtowrite) {
5109 DEBUG(3,("reply_writeclose: zero length write doesn't close "
5110 "file %s\n", fsp_str_dbg(fsp)));
5111 close_status = close_file(req, fsp, NORMAL_CLOSE);
5114 DEBUG(3,("writeclose %s num=%d wrote=%d (numopen=%d)\n",
5115 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten,
5116 conn->num_files_open));
5118 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
5119 reply_nterror(req, NT_STATUS_DISK_FULL);
5120 goto strict_unlock;
5123 if(!NT_STATUS_IS_OK(close_status)) {
5124 reply_nterror(req, close_status);
5125 goto strict_unlock;
5128 reply_outbuf(req, 1, 0);
5130 SSVAL(req->outbuf,smb_vwv0,nwritten);
5132 strict_unlock:
5133 if (numtowrite && !fsp->print_file) {
5134 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
5137 END_PROFILE(SMBwriteclose);
5138 return;
5141 #undef DBGC_CLASS
5142 #define DBGC_CLASS DBGC_LOCKING
5144 /****************************************************************************
5145 Reply to a lock.
5146 ****************************************************************************/
5148 void reply_lock(struct smb_request *req)
5150 connection_struct *conn = req->conn;
5151 uint64_t count,offset;
5152 NTSTATUS status;
5153 files_struct *fsp;
5154 struct byte_range_lock *br_lck = NULL;
5156 START_PROFILE(SMBlock);
5158 if (req->wct < 5) {
5159 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5160 END_PROFILE(SMBlock);
5161 return;
5164 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5166 if (!check_fsp(conn, req, fsp)) {
5167 END_PROFILE(SMBlock);
5168 return;
5171 count = (uint64_t)IVAL(req->vwv+1, 0);
5172 offset = (uint64_t)IVAL(req->vwv+3, 0);
5174 DEBUG(3,("lock fd=%d %s offset=%.0f count=%.0f\n",
5175 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count));
5177 br_lck = do_lock(req->sconn->msg_ctx,
5178 fsp,
5179 (uint64_t)req->smbpid,
5180 count,
5181 offset,
5182 WRITE_LOCK,
5183 WINDOWS_LOCK,
5184 False, /* Non-blocking lock. */
5185 &status,
5186 NULL,
5187 NULL);
5189 TALLOC_FREE(br_lck);
5191 if (NT_STATUS_V(status)) {
5192 reply_nterror(req, status);
5193 END_PROFILE(SMBlock);
5194 return;
5197 reply_outbuf(req, 0, 0);
5199 END_PROFILE(SMBlock);
5200 return;
5203 /****************************************************************************
5204 Reply to a unlock.
5205 ****************************************************************************/
5207 void reply_unlock(struct smb_request *req)
5209 connection_struct *conn = req->conn;
5210 uint64_t count,offset;
5211 NTSTATUS status;
5212 files_struct *fsp;
5214 START_PROFILE(SMBunlock);
5216 if (req->wct < 5) {
5217 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5218 END_PROFILE(SMBunlock);
5219 return;
5222 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5224 if (!check_fsp(conn, req, fsp)) {
5225 END_PROFILE(SMBunlock);
5226 return;
5229 count = (uint64_t)IVAL(req->vwv+1, 0);
5230 offset = (uint64_t)IVAL(req->vwv+3, 0);
5232 status = do_unlock(req->sconn->msg_ctx,
5233 fsp,
5234 (uint64_t)req->smbpid,
5235 count,
5236 offset,
5237 WINDOWS_LOCK);
5239 if (NT_STATUS_V(status)) {
5240 reply_nterror(req, status);
5241 END_PROFILE(SMBunlock);
5242 return;
5245 DEBUG( 3, ( "unlock fd=%d %s offset=%.0f count=%.0f\n",
5246 fsp->fh->fd, fsp_fnum_dbg(fsp), (double)offset, (double)count ) );
5248 reply_outbuf(req, 0, 0);
5250 END_PROFILE(SMBunlock);
5251 return;
5254 #undef DBGC_CLASS
5255 #define DBGC_CLASS DBGC_ALL
5257 /****************************************************************************
5258 Reply to a tdis.
5259 conn POINTER CAN BE NULL HERE !
5260 ****************************************************************************/
5262 void reply_tdis(struct smb_request *req)
5264 NTSTATUS status;
5265 connection_struct *conn = req->conn;
5266 struct smbXsrv_tcon *tcon;
5268 START_PROFILE(SMBtdis);
5270 if (!conn) {
5271 DEBUG(4,("Invalid connection in tdis\n"));
5272 reply_force_doserror(req, ERRSRV, ERRinvnid);
5273 END_PROFILE(SMBtdis);
5274 return;
5277 tcon = conn->tcon;
5278 req->conn = NULL;
5281 * TODO: cancel all outstanding requests on the tcon
5283 status = smbXsrv_tcon_disconnect(tcon, req->vuid);
5284 if (!NT_STATUS_IS_OK(status)) {
5285 DEBUG(0, ("reply_tdis: "
5286 "smbXsrv_tcon_disconnect() failed: %s\n",
5287 nt_errstr(status)));
5289 * If we hit this case, there is something completely
5290 * wrong, so we better disconnect the transport connection.
5292 END_PROFILE(SMBtdis);
5293 exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
5294 return;
5297 TALLOC_FREE(tcon);
5299 reply_outbuf(req, 0, 0);
5300 END_PROFILE(SMBtdis);
5301 return;
5304 /****************************************************************************
5305 Reply to a echo.
5306 conn POINTER CAN BE NULL HERE !
5307 ****************************************************************************/
5309 void reply_echo(struct smb_request *req)
5311 connection_struct *conn = req->conn;
5312 struct smb_perfcount_data local_pcd;
5313 struct smb_perfcount_data *cur_pcd;
5314 int smb_reverb;
5315 int seq_num;
5317 START_PROFILE(SMBecho);
5319 smb_init_perfcount_data(&local_pcd);
5321 if (req->wct < 1) {
5322 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5323 END_PROFILE(SMBecho);
5324 return;
5327 smb_reverb = SVAL(req->vwv+0, 0);
5329 reply_outbuf(req, 1, req->buflen);
5331 /* copy any incoming data back out */
5332 if (req->buflen > 0) {
5333 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
5336 if (smb_reverb > 100) {
5337 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
5338 smb_reverb = 100;
5341 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5343 /* this makes sure we catch the request pcd */
5344 if (seq_num == smb_reverb) {
5345 cur_pcd = &req->pcd;
5346 } else {
5347 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5348 cur_pcd = &local_pcd;
5351 SSVAL(req->outbuf,smb_vwv0,seq_num);
5353 show_msg((char *)req->outbuf);
5354 if (!srv_send_smb(req->sconn,
5355 (char *)req->outbuf,
5356 true, req->seqnum+1,
5357 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5358 cur_pcd))
5359 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5362 DEBUG(3,("echo %d times\n", smb_reverb));
5364 TALLOC_FREE(req->outbuf);
5366 END_PROFILE(SMBecho);
5367 return;
5370 /****************************************************************************
5371 Reply to a printopen.
5372 ****************************************************************************/
5374 void reply_printopen(struct smb_request *req)
5376 connection_struct *conn = req->conn;
5377 files_struct *fsp;
5378 NTSTATUS status;
5380 START_PROFILE(SMBsplopen);
5382 if (req->wct < 2) {
5383 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5384 END_PROFILE(SMBsplopen);
5385 return;
5388 if (!CAN_PRINT(conn)) {
5389 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5390 END_PROFILE(SMBsplopen);
5391 return;
5394 status = file_new(req, conn, &fsp);
5395 if(!NT_STATUS_IS_OK(status)) {
5396 reply_nterror(req, status);
5397 END_PROFILE(SMBsplopen);
5398 return;
5401 /* Open for exclusive use, write only. */
5402 status = print_spool_open(fsp, NULL, req->vuid);
5404 if (!NT_STATUS_IS_OK(status)) {
5405 file_free(req, fsp);
5406 reply_nterror(req, status);
5407 END_PROFILE(SMBsplopen);
5408 return;
5411 reply_outbuf(req, 1, 0);
5412 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5414 DEBUG(3,("openprint fd=%d %s\n",
5415 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5417 END_PROFILE(SMBsplopen);
5418 return;
5421 /****************************************************************************
5422 Reply to a printclose.
5423 ****************************************************************************/
5425 void reply_printclose(struct smb_request *req)
5427 connection_struct *conn = req->conn;
5428 files_struct *fsp;
5429 NTSTATUS status;
5431 START_PROFILE(SMBsplclose);
5433 if (req->wct < 1) {
5434 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5435 END_PROFILE(SMBsplclose);
5436 return;
5439 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5441 if (!check_fsp(conn, req, fsp)) {
5442 END_PROFILE(SMBsplclose);
5443 return;
5446 if (!CAN_PRINT(conn)) {
5447 reply_force_doserror(req, ERRSRV, ERRerror);
5448 END_PROFILE(SMBsplclose);
5449 return;
5452 DEBUG(3,("printclose fd=%d %s\n",
5453 fsp->fh->fd, fsp_fnum_dbg(fsp)));
5455 status = close_file(req, fsp, NORMAL_CLOSE);
5457 if(!NT_STATUS_IS_OK(status)) {
5458 reply_nterror(req, status);
5459 END_PROFILE(SMBsplclose);
5460 return;
5463 reply_outbuf(req, 0, 0);
5465 END_PROFILE(SMBsplclose);
5466 return;
5469 /****************************************************************************
5470 Reply to a printqueue.
5471 ****************************************************************************/
5473 void reply_printqueue(struct smb_request *req)
5475 connection_struct *conn = req->conn;
5476 int max_count;
5477 int start_index;
5479 START_PROFILE(SMBsplretq);
5481 if (req->wct < 2) {
5482 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5483 END_PROFILE(SMBsplretq);
5484 return;
5487 max_count = SVAL(req->vwv+0, 0);
5488 start_index = SVAL(req->vwv+1, 0);
5490 /* we used to allow the client to get the cnum wrong, but that
5491 is really quite gross and only worked when there was only
5492 one printer - I think we should now only accept it if they
5493 get it right (tridge) */
5494 if (!CAN_PRINT(conn)) {
5495 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5496 END_PROFILE(SMBsplretq);
5497 return;
5500 reply_outbuf(req, 2, 3);
5501 SSVAL(req->outbuf,smb_vwv0,0);
5502 SSVAL(req->outbuf,smb_vwv1,0);
5503 SCVAL(smb_buf(req->outbuf),0,1);
5504 SSVAL(smb_buf(req->outbuf),1,0);
5506 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5507 start_index, max_count));
5510 TALLOC_CTX *mem_ctx = talloc_tos();
5511 NTSTATUS status;
5512 WERROR werr;
5513 const char *sharename = lp_servicename(mem_ctx, SNUM(conn));
5514 struct rpc_pipe_client *cli = NULL;
5515 struct dcerpc_binding_handle *b = NULL;
5516 struct policy_handle handle;
5517 struct spoolss_DevmodeContainer devmode_ctr;
5518 union spoolss_JobInfo *info;
5519 uint32_t count;
5520 uint32_t num_to_get;
5521 uint32_t first;
5522 uint32_t i;
5524 ZERO_STRUCT(handle);
5526 status = rpc_pipe_open_interface(conn,
5527 &ndr_table_spoolss.syntax_id,
5528 conn->session_info,
5529 conn->sconn->remote_address,
5530 conn->sconn->msg_ctx,
5531 &cli);
5532 if (!NT_STATUS_IS_OK(status)) {
5533 DEBUG(0, ("reply_printqueue: "
5534 "could not connect to spoolss: %s\n",
5535 nt_errstr(status)));
5536 reply_nterror(req, status);
5537 goto out;
5539 b = cli->binding_handle;
5541 ZERO_STRUCT(devmode_ctr);
5543 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5544 sharename,
5545 NULL, devmode_ctr,
5546 SEC_FLAG_MAXIMUM_ALLOWED,
5547 &handle,
5548 &werr);
5549 if (!NT_STATUS_IS_OK(status)) {
5550 reply_nterror(req, status);
5551 goto out;
5553 if (!W_ERROR_IS_OK(werr)) {
5554 reply_nterror(req, werror_to_ntstatus(werr));
5555 goto out;
5558 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5559 &handle,
5560 0, /* firstjob */
5561 0xff, /* numjobs */
5562 2, /* level */
5563 0, /* offered */
5564 &count,
5565 &info);
5566 if (!W_ERROR_IS_OK(werr)) {
5567 reply_nterror(req, werror_to_ntstatus(werr));
5568 goto out;
5571 if (max_count > 0) {
5572 first = start_index;
5573 } else {
5574 first = start_index + max_count + 1;
5577 if (first >= count) {
5578 num_to_get = first;
5579 } else {
5580 num_to_get = first + MIN(ABS(max_count), count - first);
5583 for (i = first; i < num_to_get; i++) {
5584 char blob[28];
5585 char *p = blob;
5586 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
5587 int qstatus;
5588 uint16_t qrapjobid = pjobid_to_rap(sharename,
5589 info[i].info2.job_id);
5591 if (info[i].info2.status == JOB_STATUS_PRINTING) {
5592 qstatus = 2;
5593 } else {
5594 qstatus = 3;
5597 srv_put_dos_date2(p, 0, qtime);
5598 SCVAL(p, 4, qstatus);
5599 SSVAL(p, 5, qrapjobid);
5600 SIVAL(p, 7, info[i].info2.size);
5601 SCVAL(p, 11, 0);
5602 srvstr_push(blob, req->flags2, p+12,
5603 info[i].info2.notify_name, 16, STR_ASCII);
5605 if (message_push_blob(
5606 &req->outbuf,
5607 data_blob_const(
5608 blob, sizeof(blob))) == -1) {
5609 reply_nterror(req, NT_STATUS_NO_MEMORY);
5610 goto out;
5614 if (count > 0) {
5615 SSVAL(req->outbuf,smb_vwv0,count);
5616 SSVAL(req->outbuf,smb_vwv1,
5617 (max_count>0?first+count:first-1));
5618 SCVAL(smb_buf(req->outbuf),0,1);
5619 SSVAL(smb_buf(req->outbuf),1,28*count);
5623 DEBUG(3, ("%u entries returned in queue\n",
5624 (unsigned)count));
5626 out:
5627 if (b && is_valid_policy_hnd(&handle)) {
5628 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5633 END_PROFILE(SMBsplretq);
5634 return;
5637 /****************************************************************************
5638 Reply to a printwrite.
5639 ****************************************************************************/
5641 void reply_printwrite(struct smb_request *req)
5643 connection_struct *conn = req->conn;
5644 int numtowrite;
5645 const char *data;
5646 files_struct *fsp;
5648 START_PROFILE(SMBsplwr);
5650 if (req->wct < 1) {
5651 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5652 END_PROFILE(SMBsplwr);
5653 return;
5656 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5658 if (!check_fsp(conn, req, fsp)) {
5659 END_PROFILE(SMBsplwr);
5660 return;
5663 if (!fsp->print_file) {
5664 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5665 END_PROFILE(SMBsplwr);
5666 return;
5669 if (!CHECK_WRITE(fsp)) {
5670 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5671 END_PROFILE(SMBsplwr);
5672 return;
5675 numtowrite = SVAL(req->buf, 1);
5677 if (req->buflen < numtowrite + 3) {
5678 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5679 END_PROFILE(SMBsplwr);
5680 return;
5683 data = (const char *)req->buf + 3;
5685 if (write_file(req,fsp,data,(off_t)-1,numtowrite) != numtowrite) {
5686 reply_nterror(req, map_nt_error_from_unix(errno));
5687 END_PROFILE(SMBsplwr);
5688 return;
5691 DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
5693 END_PROFILE(SMBsplwr);
5694 return;
5697 /****************************************************************************
5698 Reply to a mkdir.
5699 ****************************************************************************/
5701 void reply_mkdir(struct smb_request *req)
5703 connection_struct *conn = req->conn;
5704 struct smb_filename *smb_dname = NULL;
5705 char *directory = NULL;
5706 NTSTATUS status;
5707 TALLOC_CTX *ctx = talloc_tos();
5709 START_PROFILE(SMBmkdir);
5711 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5712 STR_TERMINATE, &status);
5713 if (!NT_STATUS_IS_OK(status)) {
5714 reply_nterror(req, status);
5715 goto out;
5718 status = filename_convert(ctx, conn,
5719 req->flags2 & FLAGS2_DFS_PATHNAMES,
5720 directory,
5722 NULL,
5723 &smb_dname);
5724 if (!NT_STATUS_IS_OK(status)) {
5725 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5726 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5727 ERRSRV, ERRbadpath);
5728 goto out;
5730 reply_nterror(req, status);
5731 goto out;
5734 status = create_directory(conn, req, smb_dname);
5736 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
5738 if (!NT_STATUS_IS_OK(status)) {
5740 if (!use_nt_status()
5741 && NT_STATUS_EQUAL(status,
5742 NT_STATUS_OBJECT_NAME_COLLISION)) {
5744 * Yes, in the DOS error code case we get a
5745 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
5746 * samba4 torture test.
5748 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
5751 reply_nterror(req, status);
5752 goto out;
5755 reply_outbuf(req, 0, 0);
5757 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
5758 out:
5759 TALLOC_FREE(smb_dname);
5760 END_PROFILE(SMBmkdir);
5761 return;
5764 /****************************************************************************
5765 Reply to a rmdir.
5766 ****************************************************************************/
5768 void reply_rmdir(struct smb_request *req)
5770 connection_struct *conn = req->conn;
5771 struct smb_filename *smb_dname = NULL;
5772 char *directory = NULL;
5773 NTSTATUS status;
5774 TALLOC_CTX *ctx = talloc_tos();
5775 files_struct *fsp = NULL;
5776 int info = 0;
5777 struct smbd_server_connection *sconn = req->sconn;
5779 START_PROFILE(SMBrmdir);
5781 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5782 STR_TERMINATE, &status);
5783 if (!NT_STATUS_IS_OK(status)) {
5784 reply_nterror(req, status);
5785 goto out;
5788 status = filename_convert(ctx, conn,
5789 req->flags2 & FLAGS2_DFS_PATHNAMES,
5790 directory,
5792 NULL,
5793 &smb_dname);
5794 if (!NT_STATUS_IS_OK(status)) {
5795 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5796 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5797 ERRSRV, ERRbadpath);
5798 goto out;
5800 reply_nterror(req, status);
5801 goto out;
5804 if (is_ntfs_stream_smb_fname(smb_dname)) {
5805 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
5806 goto out;
5809 status = SMB_VFS_CREATE_FILE(
5810 conn, /* conn */
5811 req, /* req */
5812 0, /* root_dir_fid */
5813 smb_dname, /* fname */
5814 DELETE_ACCESS, /* access_mask */
5815 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5816 FILE_SHARE_DELETE),
5817 FILE_OPEN, /* create_disposition*/
5818 FILE_DIRECTORY_FILE, /* create_options */
5819 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
5820 0, /* oplock_request */
5821 0, /* allocation_size */
5822 0, /* private_flags */
5823 NULL, /* sd */
5824 NULL, /* ea_list */
5825 &fsp, /* result */
5826 &info); /* pinfo */
5828 if (!NT_STATUS_IS_OK(status)) {
5829 if (open_was_deferred(req->sconn, req->mid)) {
5830 /* We have re-scheduled this call. */
5831 goto out;
5833 reply_nterror(req, status);
5834 goto out;
5837 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
5838 if (!NT_STATUS_IS_OK(status)) {
5839 close_file(req, fsp, ERROR_CLOSE);
5840 reply_nterror(req, status);
5841 goto out;
5844 if (!set_delete_on_close(fsp, true,
5845 conn->session_info->security_token,
5846 conn->session_info->unix_token)) {
5847 close_file(req, fsp, ERROR_CLOSE);
5848 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5849 goto out;
5852 status = close_file(req, fsp, NORMAL_CLOSE);
5853 if (!NT_STATUS_IS_OK(status)) {
5854 reply_nterror(req, status);
5855 } else {
5856 reply_outbuf(req, 0, 0);
5859 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
5861 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
5862 out:
5863 TALLOC_FREE(smb_dname);
5864 END_PROFILE(SMBrmdir);
5865 return;
5868 /*******************************************************************
5869 Resolve wildcards in a filename rename.
5870 ********************************************************************/
5872 static bool resolve_wildcards(TALLOC_CTX *ctx,
5873 const char *name1,
5874 const char *name2,
5875 char **pp_newname)
5877 char *name2_copy = NULL;
5878 char *root1 = NULL;
5879 char *root2 = NULL;
5880 char *ext1 = NULL;
5881 char *ext2 = NULL;
5882 char *p,*p2, *pname1, *pname2;
5884 name2_copy = talloc_strdup(ctx, name2);
5885 if (!name2_copy) {
5886 return False;
5889 pname1 = strrchr_m(name1,'/');
5890 pname2 = strrchr_m(name2_copy,'/');
5892 if (!pname1 || !pname2) {
5893 return False;
5896 /* Truncate the copy of name2 at the last '/' */
5897 *pname2 = '\0';
5899 /* Now go past the '/' */
5900 pname1++;
5901 pname2++;
5903 root1 = talloc_strdup(ctx, pname1);
5904 root2 = talloc_strdup(ctx, pname2);
5906 if (!root1 || !root2) {
5907 return False;
5910 p = strrchr_m(root1,'.');
5911 if (p) {
5912 *p = 0;
5913 ext1 = talloc_strdup(ctx, p+1);
5914 } else {
5915 ext1 = talloc_strdup(ctx, "");
5917 p = strrchr_m(root2,'.');
5918 if (p) {
5919 *p = 0;
5920 ext2 = talloc_strdup(ctx, p+1);
5921 } else {
5922 ext2 = talloc_strdup(ctx, "");
5925 if (!ext1 || !ext2) {
5926 return False;
5929 p = root1;
5930 p2 = root2;
5931 while (*p2) {
5932 if (*p2 == '?') {
5933 /* Hmmm. Should this be mb-aware ? */
5934 *p2 = *p;
5935 p2++;
5936 } else if (*p2 == '*') {
5937 *p2 = '\0';
5938 root2 = talloc_asprintf(ctx, "%s%s",
5939 root2,
5941 if (!root2) {
5942 return False;
5944 break;
5945 } else {
5946 p2++;
5948 if (*p) {
5949 p++;
5953 p = ext1;
5954 p2 = ext2;
5955 while (*p2) {
5956 if (*p2 == '?') {
5957 /* Hmmm. Should this be mb-aware ? */
5958 *p2 = *p;
5959 p2++;
5960 } else if (*p2 == '*') {
5961 *p2 = '\0';
5962 ext2 = talloc_asprintf(ctx, "%s%s",
5963 ext2,
5965 if (!ext2) {
5966 return False;
5968 break;
5969 } else {
5970 p2++;
5972 if (*p) {
5973 p++;
5977 if (*ext2) {
5978 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
5979 name2_copy,
5980 root2,
5981 ext2);
5982 } else {
5983 *pp_newname = talloc_asprintf(ctx, "%s/%s",
5984 name2_copy,
5985 root2);
5988 if (!*pp_newname) {
5989 return False;
5992 return True;
5995 /****************************************************************************
5996 Ensure open files have their names updated. Updated to notify other smbd's
5997 asynchronously.
5998 ****************************************************************************/
6000 static void rename_open_files(connection_struct *conn,
6001 struct share_mode_lock *lck,
6002 uint32_t orig_name_hash,
6003 const struct smb_filename *smb_fname_dst)
6005 files_struct *fsp;
6006 bool did_rename = False;
6007 NTSTATUS status;
6008 uint32_t new_name_hash = 0;
6010 for(fsp = file_find_di_first(conn->sconn, lck->data->id); fsp;
6011 fsp = file_find_di_next(fsp)) {
6012 /* fsp_name is a relative path under the fsp. To change this for other
6013 sharepaths we need to manipulate relative paths. */
6014 /* TODO - create the absolute path and manipulate the newname
6015 relative to the sharepath. */
6016 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
6017 continue;
6019 if (fsp->name_hash != orig_name_hash) {
6020 continue;
6022 DEBUG(10, ("rename_open_files: renaming file %s "
6023 "(file_id %s) from %s -> %s\n", fsp_fnum_dbg(fsp),
6024 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
6025 smb_fname_str_dbg(smb_fname_dst)));
6027 status = fsp_set_smb_fname(fsp, smb_fname_dst);
6028 if (NT_STATUS_IS_OK(status)) {
6029 did_rename = True;
6030 new_name_hash = fsp->name_hash;
6034 if (!did_rename) {
6035 DEBUG(10, ("rename_open_files: no open files on file_id %s "
6036 "for %s\n", file_id_string_tos(&lck->data->id),
6037 smb_fname_str_dbg(smb_fname_dst)));
6040 /* Send messages to all smbd's (not ourself) that the name has changed. */
6041 rename_share_filename(conn->sconn->msg_ctx, lck, conn->connectpath,
6042 orig_name_hash, new_name_hash,
6043 smb_fname_dst);
6047 /****************************************************************************
6048 We need to check if the source path is a parent directory of the destination
6049 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
6050 refuse the rename with a sharing violation. Under UNIX the above call can
6051 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
6052 probably need to check that the client is a Windows one before disallowing
6053 this as a UNIX client (one with UNIX extensions) can know the source is a
6054 symlink and make this decision intelligently. Found by an excellent bug
6055 report from <AndyLiebman@aol.com>.
6056 ****************************************************************************/
6058 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
6059 const struct smb_filename *smb_fname_dst)
6061 const char *psrc = smb_fname_src->base_name;
6062 const char *pdst = smb_fname_dst->base_name;
6063 size_t slen;
6065 if (psrc[0] == '.' && psrc[1] == '/') {
6066 psrc += 2;
6068 if (pdst[0] == '.' && pdst[1] == '/') {
6069 pdst += 2;
6071 if ((slen = strlen(psrc)) > strlen(pdst)) {
6072 return False;
6074 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
6078 * Do the notify calls from a rename
6081 static void notify_rename(connection_struct *conn, bool is_dir,
6082 const struct smb_filename *smb_fname_src,
6083 const struct smb_filename *smb_fname_dst)
6085 char *parent_dir_src = NULL;
6086 char *parent_dir_dst = NULL;
6087 uint32 mask;
6089 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
6090 : FILE_NOTIFY_CHANGE_FILE_NAME;
6092 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
6093 &parent_dir_src, NULL) ||
6094 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
6095 &parent_dir_dst, NULL)) {
6096 goto out;
6099 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
6100 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
6101 smb_fname_src->base_name);
6102 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
6103 smb_fname_dst->base_name);
6105 else {
6106 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
6107 smb_fname_src->base_name);
6108 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
6109 smb_fname_dst->base_name);
6112 /* this is a strange one. w2k3 gives an additional event for
6113 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
6114 files, but not directories */
6115 if (!is_dir) {
6116 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6117 FILE_NOTIFY_CHANGE_ATTRIBUTES
6118 |FILE_NOTIFY_CHANGE_CREATION,
6119 smb_fname_dst->base_name);
6121 out:
6122 TALLOC_FREE(parent_dir_src);
6123 TALLOC_FREE(parent_dir_dst);
6126 /****************************************************************************
6127 Returns an error if the parent directory for a filename is open in an
6128 incompatible way.
6129 ****************************************************************************/
6131 static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
6132 const struct smb_filename *smb_fname_dst_in)
6134 char *parent_dir = NULL;
6135 struct smb_filename smb_fname_parent;
6136 struct file_id id;
6137 files_struct *fsp = NULL;
6138 int ret;
6140 if (!parent_dirname(talloc_tos(), smb_fname_dst_in->base_name,
6141 &parent_dir, NULL)) {
6142 return NT_STATUS_NO_MEMORY;
6144 ZERO_STRUCT(smb_fname_parent);
6145 smb_fname_parent.base_name = parent_dir;
6147 ret = SMB_VFS_LSTAT(conn, &smb_fname_parent);
6148 if (ret == -1) {
6149 return map_nt_error_from_unix(errno);
6153 * We're only checking on this smbd here, mostly good
6154 * enough.. and will pass tests.
6157 id = vfs_file_id_from_sbuf(conn, &smb_fname_parent.st);
6158 for (fsp = file_find_di_first(conn->sconn, id); fsp;
6159 fsp = file_find_di_next(fsp)) {
6160 if (fsp->access_mask & DELETE_ACCESS) {
6161 return NT_STATUS_SHARING_VIOLATION;
6164 return NT_STATUS_OK;
6167 /****************************************************************************
6168 Rename an open file - given an fsp.
6169 ****************************************************************************/
6171 NTSTATUS rename_internals_fsp(connection_struct *conn,
6172 files_struct *fsp,
6173 const struct smb_filename *smb_fname_dst_in,
6174 uint32 attrs,
6175 bool replace_if_exists)
6177 TALLOC_CTX *ctx = talloc_tos();
6178 struct smb_filename *smb_fname_dst = NULL;
6179 NTSTATUS status = NT_STATUS_OK;
6180 struct share_mode_lock *lck = NULL;
6181 bool dst_exists, old_is_stream, new_is_stream;
6183 status = check_name(conn, smb_fname_dst_in->base_name);
6184 if (!NT_STATUS_IS_OK(status)) {
6185 return status;
6188 status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
6189 if (!NT_STATUS_IS_OK(status)) {
6190 return status;
6193 /* Make a copy of the dst smb_fname structs */
6195 status = copy_smb_filename(ctx, smb_fname_dst_in, &smb_fname_dst);
6196 if (!NT_STATUS_IS_OK(status)) {
6197 goto out;
6201 * Check for special case with case preserving and not
6202 * case sensitive. If the old last component differs from the original
6203 * last component only by case, then we should allow
6204 * the rename (user is trying to change the case of the
6205 * filename).
6207 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
6208 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6209 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
6210 char *last_slash;
6211 char *fname_dst_lcomp_base_mod = NULL;
6212 struct smb_filename *smb_fname_orig_lcomp = NULL;
6215 * Get the last component of the destination name.
6217 last_slash = strrchr_m(smb_fname_dst->base_name, '/');
6218 if (last_slash) {
6219 fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1);
6220 } else {
6221 fname_dst_lcomp_base_mod = talloc_strdup(ctx, smb_fname_dst->base_name);
6223 if (!fname_dst_lcomp_base_mod) {
6224 status = NT_STATUS_NO_MEMORY;
6225 goto out;
6229 * Create an smb_filename struct using the original last
6230 * component of the destination.
6232 status = create_synthetic_smb_fname_split(ctx,
6233 smb_fname_dst->original_lcomp, NULL,
6234 &smb_fname_orig_lcomp);
6235 if (!NT_STATUS_IS_OK(status)) {
6236 TALLOC_FREE(fname_dst_lcomp_base_mod);
6237 goto out;
6240 /* If the base names only differ by case, use original. */
6241 if(!strcsequal(fname_dst_lcomp_base_mod,
6242 smb_fname_orig_lcomp->base_name)) {
6243 char *tmp;
6245 * Replace the modified last component with the
6246 * original.
6248 if (last_slash) {
6249 *last_slash = '\0'; /* Truncate at the '/' */
6250 tmp = talloc_asprintf(smb_fname_dst,
6251 "%s/%s",
6252 smb_fname_dst->base_name,
6253 smb_fname_orig_lcomp->base_name);
6254 } else {
6255 tmp = talloc_asprintf(smb_fname_dst,
6256 "%s",
6257 smb_fname_orig_lcomp->base_name);
6259 if (tmp == NULL) {
6260 status = NT_STATUS_NO_MEMORY;
6261 TALLOC_FREE(fname_dst_lcomp_base_mod);
6262 TALLOC_FREE(smb_fname_orig_lcomp);
6263 goto out;
6265 TALLOC_FREE(smb_fname_dst->base_name);
6266 smb_fname_dst->base_name = tmp;
6269 /* If the stream_names only differ by case, use original. */
6270 if(!strcsequal(smb_fname_dst->stream_name,
6271 smb_fname_orig_lcomp->stream_name)) {
6272 char *tmp = NULL;
6273 /* Use the original stream. */
6274 tmp = talloc_strdup(smb_fname_dst,
6275 smb_fname_orig_lcomp->stream_name);
6276 if (tmp == NULL) {
6277 status = NT_STATUS_NO_MEMORY;
6278 TALLOC_FREE(fname_dst_lcomp_base_mod);
6279 TALLOC_FREE(smb_fname_orig_lcomp);
6280 goto out;
6282 TALLOC_FREE(smb_fname_dst->stream_name);
6283 smb_fname_dst->stream_name = tmp;
6285 TALLOC_FREE(fname_dst_lcomp_base_mod);
6286 TALLOC_FREE(smb_fname_orig_lcomp);
6290 * If the src and dest names are identical - including case,
6291 * don't do the rename, just return success.
6294 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
6295 strcsequal(fsp->fsp_name->stream_name,
6296 smb_fname_dst->stream_name)) {
6297 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
6298 "- returning success\n",
6299 smb_fname_str_dbg(smb_fname_dst)));
6300 status = NT_STATUS_OK;
6301 goto out;
6304 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
6305 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
6307 /* Return the correct error code if both names aren't streams. */
6308 if (!old_is_stream && new_is_stream) {
6309 status = NT_STATUS_OBJECT_NAME_INVALID;
6310 goto out;
6313 if (old_is_stream && !new_is_stream) {
6314 status = NT_STATUS_INVALID_PARAMETER;
6315 goto out;
6318 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
6320 if(!replace_if_exists && dst_exists) {
6321 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
6322 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6323 smb_fname_str_dbg(smb_fname_dst)));
6324 status = NT_STATUS_OBJECT_NAME_COLLISION;
6325 goto out;
6328 if (dst_exists) {
6329 struct file_id fileid = vfs_file_id_from_sbuf(conn,
6330 &smb_fname_dst->st);
6331 files_struct *dst_fsp = file_find_di_first(conn->sconn,
6332 fileid);
6333 /* The file can be open when renaming a stream */
6334 if (dst_fsp && !new_is_stream) {
6335 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
6336 status = NT_STATUS_ACCESS_DENIED;
6337 goto out;
6341 /* Ensure we have a valid stat struct for the source. */
6342 status = vfs_stat_fsp(fsp);
6343 if (!NT_STATUS_IS_OK(status)) {
6344 goto out;
6347 status = can_rename(conn, fsp, attrs);
6349 if (!NT_STATUS_IS_OK(status)) {
6350 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6351 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6352 smb_fname_str_dbg(smb_fname_dst)));
6353 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
6354 status = NT_STATUS_ACCESS_DENIED;
6355 goto out;
6358 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
6359 status = NT_STATUS_ACCESS_DENIED;
6362 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
6365 * We have the file open ourselves, so not being able to get the
6366 * corresponding share mode lock is a fatal error.
6369 SMB_ASSERT(lck != NULL);
6371 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
6372 uint32 create_options = fsp->fh->private_options;
6374 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
6375 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
6376 smb_fname_str_dbg(smb_fname_dst)));
6378 if (!lp_posix_pathnames() &&
6379 (lp_map_archive(SNUM(conn)) ||
6380 lp_store_dos_attributes(SNUM(conn)))) {
6381 /* We must set the archive bit on the newly
6382 renamed file. */
6383 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
6384 uint32_t old_dosmode = dos_mode(conn,
6385 smb_fname_dst);
6386 file_set_dosmode(conn,
6387 smb_fname_dst,
6388 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
6389 NULL,
6390 true);
6394 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
6395 smb_fname_dst);
6397 rename_open_files(conn, lck, fsp->name_hash, smb_fname_dst);
6400 * A rename acts as a new file create w.r.t. allowing an initial delete
6401 * on close, probably because in Windows there is a new handle to the
6402 * new file. If initial delete on close was requested but not
6403 * originally set, we need to set it here. This is probably not 100% correct,
6404 * but will work for the CIFSFS client which in non-posix mode
6405 * depends on these semantics. JRA.
6408 if (create_options & FILE_DELETE_ON_CLOSE) {
6409 status = can_set_delete_on_close(fsp, 0);
6411 if (NT_STATUS_IS_OK(status)) {
6412 /* Note that here we set the *inital* delete on close flag,
6413 * not the regular one. The magic gets handled in close. */
6414 fsp->initial_delete_on_close = True;
6417 TALLOC_FREE(lck);
6418 status = NT_STATUS_OK;
6419 goto out;
6422 TALLOC_FREE(lck);
6424 if (errno == ENOTDIR || errno == EISDIR) {
6425 status = NT_STATUS_OBJECT_NAME_COLLISION;
6426 } else {
6427 status = map_nt_error_from_unix(errno);
6430 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6431 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6432 smb_fname_str_dbg(smb_fname_dst)));
6434 out:
6435 TALLOC_FREE(smb_fname_dst);
6437 return status;
6440 /****************************************************************************
6441 The guts of the rename command, split out so it may be called by the NT SMB
6442 code.
6443 ****************************************************************************/
6445 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6446 connection_struct *conn,
6447 struct smb_request *req,
6448 struct smb_filename *smb_fname_src,
6449 struct smb_filename *smb_fname_dst,
6450 uint32 attrs,
6451 bool replace_if_exists,
6452 bool src_has_wild,
6453 bool dest_has_wild,
6454 uint32_t access_mask)
6456 char *fname_src_dir = NULL;
6457 char *fname_src_mask = NULL;
6458 int count=0;
6459 NTSTATUS status = NT_STATUS_OK;
6460 struct smb_Dir *dir_hnd = NULL;
6461 const char *dname = NULL;
6462 char *talloced = NULL;
6463 long offset = 0;
6464 int create_options = 0;
6465 bool posix_pathnames = lp_posix_pathnames();
6468 * Split the old name into directory and last component
6469 * strings. Note that unix_convert may have stripped off a
6470 * leading ./ from both name and newname if the rename is
6471 * at the root of the share. We need to make sure either both
6472 * name and newname contain a / character or neither of them do
6473 * as this is checked in resolve_wildcards().
6476 /* Split up the directory from the filename/mask. */
6477 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6478 &fname_src_dir, &fname_src_mask);
6479 if (!NT_STATUS_IS_OK(status)) {
6480 status = NT_STATUS_NO_MEMORY;
6481 goto out;
6485 * We should only check the mangled cache
6486 * here if unix_convert failed. This means
6487 * that the path in 'mask' doesn't exist
6488 * on the file system and so we need to look
6489 * for a possible mangle. This patch from
6490 * Tine Smukavec <valentin.smukavec@hermes.si>.
6493 if (!VALID_STAT(smb_fname_src->st) &&
6494 mangle_is_mangled(fname_src_mask, conn->params)) {
6495 char *new_mask = NULL;
6496 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6497 conn->params);
6498 if (new_mask) {
6499 TALLOC_FREE(fname_src_mask);
6500 fname_src_mask = new_mask;
6504 if (!src_has_wild) {
6505 files_struct *fsp;
6508 * Only one file needs to be renamed. Append the mask back
6509 * onto the directory.
6511 TALLOC_FREE(smb_fname_src->base_name);
6512 if (ISDOT(fname_src_dir)) {
6513 /* Ensure we use canonical names on open. */
6514 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6515 "%s",
6516 fname_src_mask);
6517 } else {
6518 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6519 "%s/%s",
6520 fname_src_dir,
6521 fname_src_mask);
6523 if (!smb_fname_src->base_name) {
6524 status = NT_STATUS_NO_MEMORY;
6525 goto out;
6528 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6529 "case_preserve = %d, short case preserve = %d, "
6530 "directory = %s, newname = %s, "
6531 "last_component_dest = %s\n",
6532 conn->case_sensitive, conn->case_preserve,
6533 conn->short_case_preserve,
6534 smb_fname_str_dbg(smb_fname_src),
6535 smb_fname_str_dbg(smb_fname_dst),
6536 smb_fname_dst->original_lcomp));
6538 /* The dest name still may have wildcards. */
6539 if (dest_has_wild) {
6540 char *fname_dst_mod = NULL;
6541 if (!resolve_wildcards(smb_fname_dst,
6542 smb_fname_src->base_name,
6543 smb_fname_dst->base_name,
6544 &fname_dst_mod)) {
6545 DEBUG(6, ("rename_internals: resolve_wildcards "
6546 "%s %s failed\n",
6547 smb_fname_src->base_name,
6548 smb_fname_dst->base_name));
6549 status = NT_STATUS_NO_MEMORY;
6550 goto out;
6552 TALLOC_FREE(smb_fname_dst->base_name);
6553 smb_fname_dst->base_name = fname_dst_mod;
6556 ZERO_STRUCT(smb_fname_src->st);
6557 if (posix_pathnames) {
6558 SMB_VFS_LSTAT(conn, smb_fname_src);
6559 } else {
6560 SMB_VFS_STAT(conn, smb_fname_src);
6563 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6564 create_options |= FILE_DIRECTORY_FILE;
6567 status = SMB_VFS_CREATE_FILE(
6568 conn, /* conn */
6569 req, /* req */
6570 0, /* root_dir_fid */
6571 smb_fname_src, /* fname */
6572 access_mask, /* access_mask */
6573 (FILE_SHARE_READ | /* share_access */
6574 FILE_SHARE_WRITE),
6575 FILE_OPEN, /* create_disposition*/
6576 create_options, /* create_options */
6577 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6578 0, /* oplock_request */
6579 0, /* allocation_size */
6580 0, /* private_flags */
6581 NULL, /* sd */
6582 NULL, /* ea_list */
6583 &fsp, /* result */
6584 NULL); /* pinfo */
6586 if (!NT_STATUS_IS_OK(status)) {
6587 DEBUG(3, ("Could not open rename source %s: %s\n",
6588 smb_fname_str_dbg(smb_fname_src),
6589 nt_errstr(status)));
6590 goto out;
6593 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6594 attrs, replace_if_exists);
6596 close_file(req, fsp, NORMAL_CLOSE);
6598 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
6599 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
6600 smb_fname_str_dbg(smb_fname_dst)));
6602 goto out;
6606 * Wildcards - process each file that matches.
6608 if (strequal(fname_src_mask, "????????.???")) {
6609 TALLOC_FREE(fname_src_mask);
6610 fname_src_mask = talloc_strdup(ctx, "*");
6611 if (!fname_src_mask) {
6612 status = NT_STATUS_NO_MEMORY;
6613 goto out;
6617 status = check_name(conn, fname_src_dir);
6618 if (!NT_STATUS_IS_OK(status)) {
6619 goto out;
6622 dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask,
6623 attrs);
6624 if (dir_hnd == NULL) {
6625 status = map_nt_error_from_unix(errno);
6626 goto out;
6629 status = NT_STATUS_NO_SUCH_FILE;
6631 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
6632 * - gentest fix. JRA
6635 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
6636 &talloced))) {
6637 files_struct *fsp = NULL;
6638 char *destname = NULL;
6639 bool sysdir_entry = False;
6641 /* Quick check for "." and ".." */
6642 if (ISDOT(dname) || ISDOTDOT(dname)) {
6643 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
6644 sysdir_entry = True;
6645 } else {
6646 TALLOC_FREE(talloced);
6647 continue;
6651 if (!is_visible_file(conn, fname_src_dir, dname,
6652 &smb_fname_src->st, false)) {
6653 TALLOC_FREE(talloced);
6654 continue;
6657 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
6658 TALLOC_FREE(talloced);
6659 continue;
6662 if (sysdir_entry) {
6663 status = NT_STATUS_OBJECT_NAME_INVALID;
6664 break;
6667 TALLOC_FREE(smb_fname_src->base_name);
6668 if (ISDOT(fname_src_dir)) {
6669 /* Ensure we use canonical names on open. */
6670 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6671 "%s",
6672 dname);
6673 } else {
6674 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6675 "%s/%s",
6676 fname_src_dir,
6677 dname);
6679 if (!smb_fname_src->base_name) {
6680 status = NT_STATUS_NO_MEMORY;
6681 goto out;
6684 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6685 smb_fname_dst->base_name,
6686 &destname)) {
6687 DEBUG(6, ("resolve_wildcards %s %s failed\n",
6688 smb_fname_src->base_name, destname));
6689 TALLOC_FREE(talloced);
6690 continue;
6692 if (!destname) {
6693 status = NT_STATUS_NO_MEMORY;
6694 goto out;
6697 TALLOC_FREE(smb_fname_dst->base_name);
6698 smb_fname_dst->base_name = destname;
6700 ZERO_STRUCT(smb_fname_src->st);
6701 if (posix_pathnames) {
6702 SMB_VFS_LSTAT(conn, smb_fname_src);
6703 } else {
6704 SMB_VFS_STAT(conn, smb_fname_src);
6707 create_options = 0;
6709 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6710 create_options |= FILE_DIRECTORY_FILE;
6713 status = SMB_VFS_CREATE_FILE(
6714 conn, /* conn */
6715 req, /* req */
6716 0, /* root_dir_fid */
6717 smb_fname_src, /* fname */
6718 access_mask, /* access_mask */
6719 (FILE_SHARE_READ | /* share_access */
6720 FILE_SHARE_WRITE),
6721 FILE_OPEN, /* create_disposition*/
6722 create_options, /* create_options */
6723 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6724 0, /* oplock_request */
6725 0, /* allocation_size */
6726 0, /* private_flags */
6727 NULL, /* sd */
6728 NULL, /* ea_list */
6729 &fsp, /* result */
6730 NULL); /* pinfo */
6732 if (!NT_STATUS_IS_OK(status)) {
6733 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
6734 "returned %s rename %s -> %s\n",
6735 nt_errstr(status),
6736 smb_fname_str_dbg(smb_fname_src),
6737 smb_fname_str_dbg(smb_fname_dst)));
6738 break;
6741 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6742 dname);
6743 if (!smb_fname_dst->original_lcomp) {
6744 status = NT_STATUS_NO_MEMORY;
6745 goto out;
6748 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6749 attrs, replace_if_exists);
6751 close_file(req, fsp, NORMAL_CLOSE);
6753 if (!NT_STATUS_IS_OK(status)) {
6754 DEBUG(3, ("rename_internals_fsp returned %s for "
6755 "rename %s -> %s\n", nt_errstr(status),
6756 smb_fname_str_dbg(smb_fname_src),
6757 smb_fname_str_dbg(smb_fname_dst)));
6758 break;
6761 count++;
6763 DEBUG(3,("rename_internals: doing rename on %s -> "
6764 "%s\n", smb_fname_str_dbg(smb_fname_src),
6765 smb_fname_str_dbg(smb_fname_src)));
6766 TALLOC_FREE(talloced);
6768 TALLOC_FREE(dir_hnd);
6770 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
6771 status = map_nt_error_from_unix(errno);
6774 out:
6775 TALLOC_FREE(talloced);
6776 TALLOC_FREE(fname_src_dir);
6777 TALLOC_FREE(fname_src_mask);
6778 return status;
6781 /****************************************************************************
6782 Reply to a mv.
6783 ****************************************************************************/
6785 void reply_mv(struct smb_request *req)
6787 connection_struct *conn = req->conn;
6788 char *name = NULL;
6789 char *newname = NULL;
6790 const char *p;
6791 uint32 attrs;
6792 NTSTATUS status;
6793 bool src_has_wcard = False;
6794 bool dest_has_wcard = False;
6795 TALLOC_CTX *ctx = talloc_tos();
6796 struct smb_filename *smb_fname_src = NULL;
6797 struct smb_filename *smb_fname_dst = NULL;
6798 uint32_t src_ucf_flags = lp_posix_pathnames() ? UCF_UNIX_NAME_LOOKUP : UCF_COND_ALLOW_WCARD_LCOMP;
6799 uint32_t dst_ucf_flags = UCF_SAVE_LCOMP | (lp_posix_pathnames() ? 0 : UCF_COND_ALLOW_WCARD_LCOMP);
6800 bool stream_rename = false;
6802 START_PROFILE(SMBmv);
6804 if (req->wct < 1) {
6805 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6806 goto out;
6809 attrs = SVAL(req->vwv+0, 0);
6811 p = (const char *)req->buf + 1;
6812 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
6813 &status, &src_has_wcard);
6814 if (!NT_STATUS_IS_OK(status)) {
6815 reply_nterror(req, status);
6816 goto out;
6818 p++;
6819 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
6820 &status, &dest_has_wcard);
6821 if (!NT_STATUS_IS_OK(status)) {
6822 reply_nterror(req, status);
6823 goto out;
6826 if (!lp_posix_pathnames()) {
6827 /* The newname must begin with a ':' if the
6828 name contains a ':'. */
6829 if (strchr_m(name, ':')) {
6830 if (newname[0] != ':') {
6831 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6832 goto out;
6834 stream_rename = true;
6838 status = filename_convert(ctx,
6839 conn,
6840 req->flags2 & FLAGS2_DFS_PATHNAMES,
6841 name,
6842 src_ucf_flags,
6843 &src_has_wcard,
6844 &smb_fname_src);
6846 if (!NT_STATUS_IS_OK(status)) {
6847 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6848 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6849 ERRSRV, ERRbadpath);
6850 goto out;
6852 reply_nterror(req, status);
6853 goto out;
6856 status = filename_convert(ctx,
6857 conn,
6858 req->flags2 & FLAGS2_DFS_PATHNAMES,
6859 newname,
6860 dst_ucf_flags,
6861 &dest_has_wcard,
6862 &smb_fname_dst);
6864 if (!NT_STATUS_IS_OK(status)) {
6865 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6866 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6867 ERRSRV, ERRbadpath);
6868 goto out;
6870 reply_nterror(req, status);
6871 goto out;
6874 if (stream_rename) {
6875 /* smb_fname_dst->base_name must be the same as
6876 smb_fname_src->base_name. */
6877 TALLOC_FREE(smb_fname_dst->base_name);
6878 smb_fname_dst->base_name = talloc_strdup(smb_fname_dst,
6879 smb_fname_src->base_name);
6880 if (!smb_fname_dst->base_name) {
6881 reply_nterror(req, NT_STATUS_NO_MEMORY);
6882 goto out;
6886 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
6887 smb_fname_str_dbg(smb_fname_dst)));
6889 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
6890 attrs, False, src_has_wcard, dest_has_wcard,
6891 DELETE_ACCESS);
6892 if (!NT_STATUS_IS_OK(status)) {
6893 if (open_was_deferred(req->sconn, req->mid)) {
6894 /* We have re-scheduled this call. */
6895 goto out;
6897 reply_nterror(req, status);
6898 goto out;
6901 reply_outbuf(req, 0, 0);
6902 out:
6903 TALLOC_FREE(smb_fname_src);
6904 TALLOC_FREE(smb_fname_dst);
6905 END_PROFILE(SMBmv);
6906 return;
6909 /*******************************************************************
6910 Copy a file as part of a reply_copy.
6911 ******************************************************************/
6914 * TODO: check error codes on all callers
6917 NTSTATUS copy_file(TALLOC_CTX *ctx,
6918 connection_struct *conn,
6919 struct smb_filename *smb_fname_src,
6920 struct smb_filename *smb_fname_dst,
6921 int ofun,
6922 int count,
6923 bool target_is_directory)
6925 struct smb_filename *smb_fname_dst_tmp = NULL;
6926 off_t ret=-1;
6927 files_struct *fsp1,*fsp2;
6928 uint32 dosattrs;
6929 uint32 new_create_disposition;
6930 NTSTATUS status;
6933 status = copy_smb_filename(ctx, smb_fname_dst, &smb_fname_dst_tmp);
6934 if (!NT_STATUS_IS_OK(status)) {
6935 return status;
6939 * If the target is a directory, extract the last component from the
6940 * src filename and append it to the dst filename
6942 if (target_is_directory) {
6943 const char *p;
6945 /* dest/target can't be a stream if it's a directory. */
6946 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
6948 p = strrchr_m(smb_fname_src->base_name,'/');
6949 if (p) {
6950 p++;
6951 } else {
6952 p = smb_fname_src->base_name;
6954 smb_fname_dst_tmp->base_name =
6955 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
6957 if (!smb_fname_dst_tmp->base_name) {
6958 status = NT_STATUS_NO_MEMORY;
6959 goto out;
6963 status = vfs_file_exist(conn, smb_fname_src);
6964 if (!NT_STATUS_IS_OK(status)) {
6965 goto out;
6968 if (!target_is_directory && count) {
6969 new_create_disposition = FILE_OPEN;
6970 } else {
6971 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
6972 0, ofun,
6973 NULL, NULL,
6974 &new_create_disposition,
6975 NULL,
6976 NULL)) {
6977 status = NT_STATUS_INVALID_PARAMETER;
6978 goto out;
6982 /* Open the src file for reading. */
6983 status = SMB_VFS_CREATE_FILE(
6984 conn, /* conn */
6985 NULL, /* req */
6986 0, /* root_dir_fid */
6987 smb_fname_src, /* fname */
6988 FILE_GENERIC_READ, /* access_mask */
6989 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6990 FILE_OPEN, /* create_disposition*/
6991 0, /* create_options */
6992 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
6993 INTERNAL_OPEN_ONLY, /* oplock_request */
6994 0, /* allocation_size */
6995 0, /* private_flags */
6996 NULL, /* sd */
6997 NULL, /* ea_list */
6998 &fsp1, /* result */
6999 NULL); /* psbuf */
7001 if (!NT_STATUS_IS_OK(status)) {
7002 goto out;
7005 dosattrs = dos_mode(conn, smb_fname_src);
7007 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
7008 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
7011 /* Open the dst file for writing. */
7012 status = SMB_VFS_CREATE_FILE(
7013 conn, /* conn */
7014 NULL, /* req */
7015 0, /* root_dir_fid */
7016 smb_fname_dst, /* fname */
7017 FILE_GENERIC_WRITE, /* access_mask */
7018 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
7019 new_create_disposition, /* create_disposition*/
7020 0, /* create_options */
7021 dosattrs, /* file_attributes */
7022 INTERNAL_OPEN_ONLY, /* oplock_request */
7023 0, /* allocation_size */
7024 0, /* private_flags */
7025 NULL, /* sd */
7026 NULL, /* ea_list */
7027 &fsp2, /* result */
7028 NULL); /* psbuf */
7030 if (!NT_STATUS_IS_OK(status)) {
7031 close_file(NULL, fsp1, ERROR_CLOSE);
7032 goto out;
7035 if (ofun & OPENX_FILE_EXISTS_OPEN) {
7036 ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
7037 if (ret == -1) {
7038 DEBUG(0, ("error - vfs lseek returned error %s\n",
7039 strerror(errno)));
7040 status = map_nt_error_from_unix(errno);
7041 close_file(NULL, fsp1, ERROR_CLOSE);
7042 close_file(NULL, fsp2, ERROR_CLOSE);
7043 goto out;
7047 /* Do the actual copy. */
7048 if (smb_fname_src->st.st_ex_size) {
7049 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
7050 } else {
7051 ret = 0;
7054 close_file(NULL, fsp1, NORMAL_CLOSE);
7056 /* Ensure the modtime is set correctly on the destination file. */
7057 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
7060 * As we are opening fsp1 read-only we only expect
7061 * an error on close on fsp2 if we are out of space.
7062 * Thus we don't look at the error return from the
7063 * close of fsp1.
7065 status = close_file(NULL, fsp2, NORMAL_CLOSE);
7067 if (!NT_STATUS_IS_OK(status)) {
7068 goto out;
7071 if (ret != (off_t)smb_fname_src->st.st_ex_size) {
7072 status = NT_STATUS_DISK_FULL;
7073 goto out;
7076 status = NT_STATUS_OK;
7078 out:
7079 TALLOC_FREE(smb_fname_dst_tmp);
7080 return status;
7083 /****************************************************************************
7084 Reply to a file copy.
7085 ****************************************************************************/
7087 void reply_copy(struct smb_request *req)
7089 connection_struct *conn = req->conn;
7090 struct smb_filename *smb_fname_src = NULL;
7091 struct smb_filename *smb_fname_dst = NULL;
7092 char *fname_src = NULL;
7093 char *fname_dst = NULL;
7094 char *fname_src_mask = NULL;
7095 char *fname_src_dir = NULL;
7096 const char *p;
7097 int count=0;
7098 int error = ERRnoaccess;
7099 int tid2;
7100 int ofun;
7101 int flags;
7102 bool target_is_directory=False;
7103 bool source_has_wild = False;
7104 bool dest_has_wild = False;
7105 NTSTATUS status;
7106 TALLOC_CTX *ctx = talloc_tos();
7108 START_PROFILE(SMBcopy);
7110 if (req->wct < 3) {
7111 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7112 goto out;
7115 tid2 = SVAL(req->vwv+0, 0);
7116 ofun = SVAL(req->vwv+1, 0);
7117 flags = SVAL(req->vwv+2, 0);
7119 p = (const char *)req->buf;
7120 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
7121 &status, &source_has_wild);
7122 if (!NT_STATUS_IS_OK(status)) {
7123 reply_nterror(req, status);
7124 goto out;
7126 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
7127 &status, &dest_has_wild);
7128 if (!NT_STATUS_IS_OK(status)) {
7129 reply_nterror(req, status);
7130 goto out;
7133 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
7135 if (tid2 != conn->cnum) {
7136 /* can't currently handle inter share copies XXXX */
7137 DEBUG(3,("Rejecting inter-share copy\n"));
7138 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
7139 goto out;
7142 status = filename_convert(ctx, conn,
7143 req->flags2 & FLAGS2_DFS_PATHNAMES,
7144 fname_src,
7145 UCF_COND_ALLOW_WCARD_LCOMP,
7146 &source_has_wild,
7147 &smb_fname_src);
7148 if (!NT_STATUS_IS_OK(status)) {
7149 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7150 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7151 ERRSRV, ERRbadpath);
7152 goto out;
7154 reply_nterror(req, status);
7155 goto out;
7158 status = filename_convert(ctx, conn,
7159 req->flags2 & FLAGS2_DFS_PATHNAMES,
7160 fname_dst,
7161 UCF_COND_ALLOW_WCARD_LCOMP,
7162 &dest_has_wild,
7163 &smb_fname_dst);
7164 if (!NT_STATUS_IS_OK(status)) {
7165 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7166 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7167 ERRSRV, ERRbadpath);
7168 goto out;
7170 reply_nterror(req, status);
7171 goto out;
7174 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
7176 if ((flags&1) && target_is_directory) {
7177 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
7178 goto out;
7181 if ((flags&2) && !target_is_directory) {
7182 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
7183 goto out;
7186 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
7187 /* wants a tree copy! XXXX */
7188 DEBUG(3,("Rejecting tree copy\n"));
7189 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7190 goto out;
7193 /* Split up the directory from the filename/mask. */
7194 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
7195 &fname_src_dir, &fname_src_mask);
7196 if (!NT_STATUS_IS_OK(status)) {
7197 reply_nterror(req, NT_STATUS_NO_MEMORY);
7198 goto out;
7202 * We should only check the mangled cache
7203 * here if unix_convert failed. This means
7204 * that the path in 'mask' doesn't exist
7205 * on the file system and so we need to look
7206 * for a possible mangle. This patch from
7207 * Tine Smukavec <valentin.smukavec@hermes.si>.
7209 if (!VALID_STAT(smb_fname_src->st) &&
7210 mangle_is_mangled(fname_src_mask, conn->params)) {
7211 char *new_mask = NULL;
7212 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
7213 &new_mask, conn->params);
7215 /* Use demangled name if one was successfully found. */
7216 if (new_mask) {
7217 TALLOC_FREE(fname_src_mask);
7218 fname_src_mask = new_mask;
7222 if (!source_has_wild) {
7225 * Only one file needs to be copied. Append the mask back onto
7226 * the directory.
7228 TALLOC_FREE(smb_fname_src->base_name);
7229 if (ISDOT(fname_src_dir)) {
7230 /* Ensure we use canonical names on open. */
7231 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7232 "%s",
7233 fname_src_mask);
7234 } else {
7235 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
7236 "%s/%s",
7237 fname_src_dir,
7238 fname_src_mask);
7240 if (!smb_fname_src->base_name) {
7241 reply_nterror(req, NT_STATUS_NO_MEMORY);
7242 goto out;
7245 if (dest_has_wild) {
7246 char *fname_dst_mod = NULL;
7247 if (!resolve_wildcards(smb_fname_dst,
7248 smb_fname_src->base_name,
7249 smb_fname_dst->base_name,
7250 &fname_dst_mod)) {
7251 reply_nterror(req, NT_STATUS_NO_MEMORY);
7252 goto out;
7254 TALLOC_FREE(smb_fname_dst->base_name);
7255 smb_fname_dst->base_name = fname_dst_mod;
7258 status = check_name(conn, smb_fname_src->base_name);
7259 if (!NT_STATUS_IS_OK(status)) {
7260 reply_nterror(req, status);
7261 goto out;
7264 status = check_name(conn, smb_fname_dst->base_name);
7265 if (!NT_STATUS_IS_OK(status)) {
7266 reply_nterror(req, status);
7267 goto out;
7270 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
7271 ofun, count, target_is_directory);
7273 if(!NT_STATUS_IS_OK(status)) {
7274 reply_nterror(req, status);
7275 goto out;
7276 } else {
7277 count++;
7279 } else {
7280 struct smb_Dir *dir_hnd = NULL;
7281 const char *dname = NULL;
7282 char *talloced = NULL;
7283 long offset = 0;
7286 * There is a wildcard that requires us to actually read the
7287 * src dir and copy each file matching the mask to the dst.
7288 * Right now streams won't be copied, but this could
7289 * presumably be added with a nested loop for reach dir entry.
7291 SMB_ASSERT(!smb_fname_src->stream_name);
7292 SMB_ASSERT(!smb_fname_dst->stream_name);
7294 smb_fname_src->stream_name = NULL;
7295 smb_fname_dst->stream_name = NULL;
7297 if (strequal(fname_src_mask,"????????.???")) {
7298 TALLOC_FREE(fname_src_mask);
7299 fname_src_mask = talloc_strdup(ctx, "*");
7300 if (!fname_src_mask) {
7301 reply_nterror(req, NT_STATUS_NO_MEMORY);
7302 goto out;
7306 status = check_name(conn, fname_src_dir);
7307 if (!NT_STATUS_IS_OK(status)) {
7308 reply_nterror(req, status);
7309 goto out;
7312 dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0);
7313 if (dir_hnd == NULL) {
7314 status = map_nt_error_from_unix(errno);
7315 reply_nterror(req, status);
7316 goto out;
7319 error = ERRbadfile;
7321 /* Iterate over the src dir copying each entry to the dst. */
7322 while ((dname = ReadDirName(dir_hnd, &offset,
7323 &smb_fname_src->st, &talloced))) {
7324 char *destname = NULL;
7326 if (ISDOT(dname) || ISDOTDOT(dname)) {
7327 TALLOC_FREE(talloced);
7328 continue;
7331 if (!is_visible_file(conn, fname_src_dir, dname,
7332 &smb_fname_src->st, false)) {
7333 TALLOC_FREE(talloced);
7334 continue;
7337 if(!mask_match(dname, fname_src_mask,
7338 conn->case_sensitive)) {
7339 TALLOC_FREE(talloced);
7340 continue;
7343 error = ERRnoaccess;
7345 /* Get the src smb_fname struct setup. */
7346 TALLOC_FREE(smb_fname_src->base_name);
7347 if (ISDOT(fname_src_dir)) {
7348 /* Ensure we use canonical names on open. */
7349 smb_fname_src->base_name =
7350 talloc_asprintf(smb_fname_src, "%s",
7351 dname);
7352 } else {
7353 smb_fname_src->base_name =
7354 talloc_asprintf(smb_fname_src, "%s/%s",
7355 fname_src_dir, dname);
7358 if (!smb_fname_src->base_name) {
7359 TALLOC_FREE(dir_hnd);
7360 TALLOC_FREE(talloced);
7361 reply_nterror(req, NT_STATUS_NO_MEMORY);
7362 goto out;
7365 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
7366 smb_fname_dst->base_name,
7367 &destname)) {
7368 TALLOC_FREE(talloced);
7369 continue;
7371 if (!destname) {
7372 TALLOC_FREE(dir_hnd);
7373 TALLOC_FREE(talloced);
7374 reply_nterror(req, NT_STATUS_NO_MEMORY);
7375 goto out;
7378 TALLOC_FREE(smb_fname_dst->base_name);
7379 smb_fname_dst->base_name = destname;
7381 status = check_name(conn, smb_fname_src->base_name);
7382 if (!NT_STATUS_IS_OK(status)) {
7383 TALLOC_FREE(dir_hnd);
7384 TALLOC_FREE(talloced);
7385 reply_nterror(req, status);
7386 goto out;
7389 status = check_name(conn, smb_fname_dst->base_name);
7390 if (!NT_STATUS_IS_OK(status)) {
7391 TALLOC_FREE(dir_hnd);
7392 TALLOC_FREE(talloced);
7393 reply_nterror(req, status);
7394 goto out;
7397 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
7398 smb_fname_src->base_name,
7399 smb_fname_dst->base_name));
7401 status = copy_file(ctx, conn, smb_fname_src,
7402 smb_fname_dst, ofun, count,
7403 target_is_directory);
7404 if (NT_STATUS_IS_OK(status)) {
7405 count++;
7408 TALLOC_FREE(talloced);
7410 TALLOC_FREE(dir_hnd);
7413 if (count == 0) {
7414 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
7415 goto out;
7418 reply_outbuf(req, 1, 0);
7419 SSVAL(req->outbuf,smb_vwv0,count);
7420 out:
7421 TALLOC_FREE(smb_fname_src);
7422 TALLOC_FREE(smb_fname_dst);
7423 TALLOC_FREE(fname_src);
7424 TALLOC_FREE(fname_dst);
7425 TALLOC_FREE(fname_src_mask);
7426 TALLOC_FREE(fname_src_dir);
7428 END_PROFILE(SMBcopy);
7429 return;
7432 #undef DBGC_CLASS
7433 #define DBGC_CLASS DBGC_LOCKING
7435 /****************************************************************************
7436 Get a lock pid, dealing with large count requests.
7437 ****************************************************************************/
7439 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
7440 bool large_file_format)
7442 if(!large_file_format)
7443 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
7444 else
7445 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7448 /****************************************************************************
7449 Get a lock count, dealing with large count requests.
7450 ****************************************************************************/
7452 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7453 bool large_file_format)
7455 uint64_t count = 0;
7457 if(!large_file_format) {
7458 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7459 } else {
7461 #if defined(HAVE_LONGLONG)
7462 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7463 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7464 #else /* HAVE_LONGLONG */
7467 * NT4.x seems to be broken in that it sends large file (64 bit)
7468 * lockingX calls even if the CAP_LARGE_FILES was *not*
7469 * negotiated. For boxes without large unsigned ints truncate the
7470 * lock count by dropping the top 32 bits.
7473 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
7474 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
7475 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
7476 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
7477 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
7480 count = (uint64_t)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
7481 #endif /* HAVE_LONGLONG */
7484 return count;
7487 #if !defined(HAVE_LONGLONG)
7488 /****************************************************************************
7489 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
7490 ****************************************************************************/
7492 static uint32 map_lock_offset(uint32 high, uint32 low)
7494 unsigned int i;
7495 uint32 mask = 0;
7496 uint32 highcopy = high;
7499 * Try and find out how many significant bits there are in high.
7502 for(i = 0; highcopy; i++)
7503 highcopy >>= 1;
7506 * We use 31 bits not 32 here as POSIX
7507 * lock offsets may not be negative.
7510 mask = (~0) << (31 - i);
7512 if(low & mask)
7513 return 0; /* Fail. */
7515 high <<= (31 - i);
7517 return (high|low);
7519 #endif /* !defined(HAVE_LONGLONG) */
7521 /****************************************************************************
7522 Get a lock offset, dealing with large offset requests.
7523 ****************************************************************************/
7525 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7526 bool large_file_format, bool *err)
7528 uint64_t offset = 0;
7530 *err = False;
7532 if(!large_file_format) {
7533 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7534 } else {
7536 #if defined(HAVE_LONGLONG)
7537 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7538 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7539 #else /* HAVE_LONGLONG */
7542 * NT4.x seems to be broken in that it sends large file (64 bit)
7543 * lockingX calls even if the CAP_LARGE_FILES was *not*
7544 * negotiated. For boxes without large unsigned ints mangle the
7545 * lock offset by mapping the top 32 bits onto the lower 32.
7548 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
7549 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7550 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
7551 uint32 new_low = 0;
7553 if((new_low = map_lock_offset(high, low)) == 0) {
7554 *err = True;
7555 return (uint64_t)-1;
7558 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
7559 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
7560 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
7561 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
7564 offset = (uint64_t)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7565 #endif /* HAVE_LONGLONG */
7568 return offset;
7571 NTSTATUS smbd_do_locking(struct smb_request *req,
7572 files_struct *fsp,
7573 uint8_t type,
7574 int32_t timeout,
7575 uint16_t num_ulocks,
7576 struct smbd_lock_element *ulocks,
7577 uint16_t num_locks,
7578 struct smbd_lock_element *locks,
7579 bool *async)
7581 connection_struct *conn = req->conn;
7582 int i;
7583 NTSTATUS status = NT_STATUS_OK;
7585 *async = false;
7587 /* Data now points at the beginning of the list
7588 of smb_unlkrng structs */
7589 for(i = 0; i < (int)num_ulocks; i++) {
7590 struct smbd_lock_element *e = &ulocks[i];
7592 DEBUG(10,("smbd_do_locking: unlock start=%.0f, len=%.0f for "
7593 "pid %u, file %s\n",
7594 (double)e->offset,
7595 (double)e->count,
7596 (unsigned int)e->smblctx,
7597 fsp_str_dbg(fsp)));
7599 if (e->brltype != UNLOCK_LOCK) {
7600 /* this can only happen with SMB2 */
7601 return NT_STATUS_INVALID_PARAMETER;
7604 status = do_unlock(req->sconn->msg_ctx,
7605 fsp,
7606 e->smblctx,
7607 e->count,
7608 e->offset,
7609 WINDOWS_LOCK);
7611 DEBUG(10, ("smbd_do_locking: unlock returned %s\n",
7612 nt_errstr(status)));
7614 if (!NT_STATUS_IS_OK(status)) {
7615 return status;
7619 /* Setup the timeout in seconds. */
7621 if (!lp_blocking_locks(SNUM(conn))) {
7622 timeout = 0;
7625 /* Data now points at the beginning of the list
7626 of smb_lkrng structs */
7628 for(i = 0; i < (int)num_locks; i++) {
7629 struct smbd_lock_element *e = &locks[i];
7631 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
7632 "%llu, file %s timeout = %d\n",
7633 (double)e->offset,
7634 (double)e->count,
7635 (unsigned long long)e->smblctx,
7636 fsp_str_dbg(fsp),
7637 (int)timeout));
7639 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7640 struct blocking_lock_record *blr = NULL;
7642 if (num_locks > 1) {
7644 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
7645 * if the lock vector contains one entry. When given mutliple cancel
7646 * requests in a single PDU we expect the server to return an
7647 * error. Windows servers seem to accept the request but only
7648 * cancel the first lock.
7649 * JRA - Do what Windows does (tm) :-).
7652 #if 0
7653 /* MS-CIFS (2.2.4.32.1) behavior. */
7654 return NT_STATUS_DOS(ERRDOS,
7655 ERRcancelviolation);
7656 #else
7657 /* Windows behavior. */
7658 if (i != 0) {
7659 DEBUG(10,("smbd_do_locking: ignoring subsequent "
7660 "cancel request\n"));
7661 continue;
7663 #endif
7666 if (lp_blocking_locks(SNUM(conn))) {
7668 /* Schedule a message to ourselves to
7669 remove the blocking lock record and
7670 return the right error. */
7672 blr = blocking_lock_cancel_smb1(fsp,
7673 e->smblctx,
7674 e->offset,
7675 e->count,
7676 WINDOWS_LOCK,
7677 type,
7678 NT_STATUS_FILE_LOCK_CONFLICT);
7679 if (blr == NULL) {
7680 return NT_STATUS_DOS(
7681 ERRDOS,
7682 ERRcancelviolation);
7685 /* Remove a matching pending lock. */
7686 status = do_lock_cancel(fsp,
7687 e->smblctx,
7688 e->count,
7689 e->offset,
7690 WINDOWS_LOCK,
7691 blr);
7692 } else {
7693 bool blocking_lock = timeout ? true : false;
7694 bool defer_lock = false;
7695 struct byte_range_lock *br_lck;
7696 uint64_t block_smblctx;
7698 br_lck = do_lock(req->sconn->msg_ctx,
7699 fsp,
7700 e->smblctx,
7701 e->count,
7702 e->offset,
7703 e->brltype,
7704 WINDOWS_LOCK,
7705 blocking_lock,
7706 &status,
7707 &block_smblctx,
7708 NULL);
7710 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
7711 /* Windows internal resolution for blocking locks seems
7712 to be about 200ms... Don't wait for less than that. JRA. */
7713 if (timeout != -1 && timeout < lp_lock_spin_time()) {
7714 timeout = lp_lock_spin_time();
7716 defer_lock = true;
7719 /* If a lock sent with timeout of zero would fail, and
7720 * this lock has been requested multiple times,
7721 * according to brl_lock_failed() we convert this
7722 * request to a blocking lock with a timeout of between
7723 * 150 - 300 milliseconds.
7725 * If lp_lock_spin_time() has been set to 0, we skip
7726 * this blocking retry and fail immediately.
7728 * Replacement for do_lock_spin(). JRA. */
7730 if (!req->sconn->using_smb2 &&
7731 br_lck && lp_blocking_locks(SNUM(conn)) &&
7732 lp_lock_spin_time() && !blocking_lock &&
7733 NT_STATUS_EQUAL((status),
7734 NT_STATUS_FILE_LOCK_CONFLICT))
7736 defer_lock = true;
7737 timeout = lp_lock_spin_time();
7740 if (br_lck && defer_lock) {
7742 * A blocking lock was requested. Package up
7743 * this smb into a queued request and push it
7744 * onto the blocking lock queue.
7746 if(push_blocking_lock_request(br_lck,
7747 req,
7748 fsp,
7749 timeout,
7751 e->smblctx,
7752 e->brltype,
7753 WINDOWS_LOCK,
7754 e->offset,
7755 e->count,
7756 block_smblctx)) {
7757 TALLOC_FREE(br_lck);
7758 *async = true;
7759 return NT_STATUS_OK;
7763 TALLOC_FREE(br_lck);
7766 if (!NT_STATUS_IS_OK(status)) {
7767 break;
7771 /* If any of the above locks failed, then we must unlock
7772 all of the previous locks (X/Open spec). */
7774 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
7776 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7777 i = -1; /* we want to skip the for loop */
7781 * Ensure we don't do a remove on the lock that just failed,
7782 * as under POSIX rules, if we have a lock already there, we
7783 * will delete it (and we shouldn't) .....
7785 for(i--; i >= 0; i--) {
7786 struct smbd_lock_element *e = &locks[i];
7788 do_unlock(req->sconn->msg_ctx,
7789 fsp,
7790 e->smblctx,
7791 e->count,
7792 e->offset,
7793 WINDOWS_LOCK);
7795 return status;
7798 DEBUG(3, ("smbd_do_locking: %s type=%d num_locks=%d num_ulocks=%d\n",
7799 fsp_fnum_dbg(fsp), (unsigned int)type, num_locks, num_ulocks));
7801 return NT_STATUS_OK;
7804 /****************************************************************************
7805 Reply to a lockingX request.
7806 ****************************************************************************/
7808 void reply_lockingX(struct smb_request *req)
7810 connection_struct *conn = req->conn;
7811 files_struct *fsp;
7812 unsigned char locktype;
7813 unsigned char oplocklevel;
7814 uint16 num_ulocks;
7815 uint16 num_locks;
7816 int32 lock_timeout;
7817 int i;
7818 const uint8_t *data;
7819 bool large_file_format;
7820 bool err;
7821 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
7822 struct smbd_lock_element *ulocks;
7823 struct smbd_lock_element *locks;
7824 bool async = false;
7826 START_PROFILE(SMBlockingX);
7828 if (req->wct < 8) {
7829 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7830 END_PROFILE(SMBlockingX);
7831 return;
7834 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
7835 locktype = CVAL(req->vwv+3, 0);
7836 oplocklevel = CVAL(req->vwv+3, 1);
7837 num_ulocks = SVAL(req->vwv+6, 0);
7838 num_locks = SVAL(req->vwv+7, 0);
7839 lock_timeout = IVAL(req->vwv+4, 0);
7840 large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
7842 if (!check_fsp(conn, req, fsp)) {
7843 END_PROFILE(SMBlockingX);
7844 return;
7847 data = req->buf;
7849 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
7850 /* we don't support these - and CANCEL_LOCK makes w2k
7851 and XP reboot so I don't really want to be
7852 compatible! (tridge) */
7853 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
7854 END_PROFILE(SMBlockingX);
7855 return;
7858 /* Check if this is an oplock break on a file
7859 we have granted an oplock on.
7861 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
7862 /* Client can insist on breaking to none. */
7863 bool break_to_none = (oplocklevel == 0);
7864 bool result;
7866 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
7867 "for %s\n", (unsigned int)oplocklevel,
7868 fsp_fnum_dbg(fsp)));
7871 * Make sure we have granted an exclusive or batch oplock on
7872 * this file.
7875 if (fsp->oplock_type == 0) {
7877 /* The Samba4 nbench simulator doesn't understand
7878 the difference between break to level2 and break
7879 to none from level2 - it sends oplock break
7880 replies in both cases. Don't keep logging an error
7881 message here - just ignore it. JRA. */
7883 DEBUG(5,("reply_lockingX: Error : oplock break from "
7884 "client for %s (oplock=%d) and no "
7885 "oplock granted on this file (%s).\n",
7886 fsp_fnum_dbg(fsp), fsp->oplock_type,
7887 fsp_str_dbg(fsp)));
7889 /* if this is a pure oplock break request then don't
7890 * send a reply */
7891 if (num_locks == 0 && num_ulocks == 0) {
7892 END_PROFILE(SMBlockingX);
7893 return;
7894 } else {
7895 END_PROFILE(SMBlockingX);
7896 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
7897 return;
7901 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
7902 (break_to_none)) {
7903 result = remove_oplock(fsp);
7904 } else {
7905 result = downgrade_oplock(fsp);
7908 if (!result) {
7909 DEBUG(0, ("reply_lockingX: error in removing "
7910 "oplock on file %s\n", fsp_str_dbg(fsp)));
7911 /* Hmmm. Is this panic justified? */
7912 smb_panic("internal tdb error");
7915 reply_to_oplock_break_requests(fsp);
7917 /* if this is a pure oplock break request then don't send a
7918 * reply */
7919 if (num_locks == 0 && num_ulocks == 0) {
7920 /* Sanity check - ensure a pure oplock break is not a
7921 chained request. */
7922 if(CVAL(req->vwv+0, 0) != 0xff)
7923 DEBUG(0,("reply_lockingX: Error : pure oplock "
7924 "break is a chained %d request !\n",
7925 (unsigned int)CVAL(req->vwv+0, 0)));
7926 END_PROFILE(SMBlockingX);
7927 return;
7931 if (req->buflen <
7932 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
7933 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7934 END_PROFILE(SMBlockingX);
7935 return;
7938 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
7939 if (ulocks == NULL) {
7940 reply_nterror(req, NT_STATUS_NO_MEMORY);
7941 END_PROFILE(SMBlockingX);
7942 return;
7945 locks = talloc_array(req, struct smbd_lock_element, num_locks);
7946 if (locks == NULL) {
7947 reply_nterror(req, NT_STATUS_NO_MEMORY);
7948 END_PROFILE(SMBlockingX);
7949 return;
7952 /* Data now points at the beginning of the list
7953 of smb_unlkrng structs */
7954 for(i = 0; i < (int)num_ulocks; i++) {
7955 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
7956 ulocks[i].count = get_lock_count(data, i, large_file_format);
7957 ulocks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7958 ulocks[i].brltype = UNLOCK_LOCK;
7961 * There is no error code marked "stupid client bug".... :-).
7963 if(err) {
7964 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7965 END_PROFILE(SMBlockingX);
7966 return;
7970 /* Now do any requested locks */
7971 data += ((large_file_format ? 20 : 10)*num_ulocks);
7973 /* Data now points at the beginning of the list
7974 of smb_lkrng structs */
7976 for(i = 0; i < (int)num_locks; i++) {
7977 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
7978 locks[i].count = get_lock_count(data, i, large_file_format);
7979 locks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7981 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
7982 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7983 locks[i].brltype = PENDING_READ_LOCK;
7984 } else {
7985 locks[i].brltype = READ_LOCK;
7987 } else {
7988 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7989 locks[i].brltype = PENDING_WRITE_LOCK;
7990 } else {
7991 locks[i].brltype = WRITE_LOCK;
7996 * There is no error code marked "stupid client bug".... :-).
7998 if(err) {
7999 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8000 END_PROFILE(SMBlockingX);
8001 return;
8005 status = smbd_do_locking(req, fsp,
8006 locktype, lock_timeout,
8007 num_ulocks, ulocks,
8008 num_locks, locks,
8009 &async);
8010 if (!NT_STATUS_IS_OK(status)) {
8011 END_PROFILE(SMBlockingX);
8012 reply_nterror(req, status);
8013 return;
8015 if (async) {
8016 END_PROFILE(SMBlockingX);
8017 return;
8020 reply_outbuf(req, 2, 0);
8021 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
8022 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */
8024 DEBUG(3, ("lockingX %s type=%d num_locks=%d num_ulocks=%d\n",
8025 fsp_fnum_dbg(fsp), (unsigned int)locktype, num_locks, num_ulocks));
8027 END_PROFILE(SMBlockingX);
8030 #undef DBGC_CLASS
8031 #define DBGC_CLASS DBGC_ALL
8033 /****************************************************************************
8034 Reply to a SMBreadbmpx (read block multiplex) request.
8035 Always reply with an error, if someone has a platform really needs this,
8036 please contact vl@samba.org
8037 ****************************************************************************/
8039 void reply_readbmpx(struct smb_request *req)
8041 START_PROFILE(SMBreadBmpx);
8042 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8043 END_PROFILE(SMBreadBmpx);
8044 return;
8047 /****************************************************************************
8048 Reply to a SMBreadbs (read block multiplex secondary) request.
8049 Always reply with an error, if someone has a platform really needs this,
8050 please contact vl@samba.org
8051 ****************************************************************************/
8053 void reply_readbs(struct smb_request *req)
8055 START_PROFILE(SMBreadBs);
8056 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8057 END_PROFILE(SMBreadBs);
8058 return;
8061 /****************************************************************************
8062 Reply to a SMBsetattrE.
8063 ****************************************************************************/
8065 void reply_setattrE(struct smb_request *req)
8067 connection_struct *conn = req->conn;
8068 struct smb_file_time ft;
8069 files_struct *fsp;
8070 NTSTATUS status;
8072 START_PROFILE(SMBsetattrE);
8073 ZERO_STRUCT(ft);
8075 if (req->wct < 7) {
8076 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8077 goto out;
8080 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8082 if(!fsp || (fsp->conn != conn)) {
8083 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8084 goto out;
8088 * Convert the DOS times into unix times.
8091 ft.atime = convert_time_t_to_timespec(
8092 srv_make_unix_date2(req->vwv+3));
8093 ft.mtime = convert_time_t_to_timespec(
8094 srv_make_unix_date2(req->vwv+5));
8095 ft.create_time = convert_time_t_to_timespec(
8096 srv_make_unix_date2(req->vwv+1));
8098 reply_outbuf(req, 0, 0);
8101 * Patch from Ray Frush <frush@engr.colostate.edu>
8102 * Sometimes times are sent as zero - ignore them.
8105 /* Ensure we have a valid stat struct for the source. */
8106 status = vfs_stat_fsp(fsp);
8107 if (!NT_STATUS_IS_OK(status)) {
8108 reply_nterror(req, status);
8109 goto out;
8112 if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
8113 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8114 goto out;
8117 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
8118 if (!NT_STATUS_IS_OK(status)) {
8119 reply_nterror(req, status);
8120 goto out;
8123 DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
8124 " createtime=%u\n",
8125 fsp_fnum_dbg(fsp),
8126 (unsigned int)ft.atime.tv_sec,
8127 (unsigned int)ft.mtime.tv_sec,
8128 (unsigned int)ft.create_time.tv_sec
8130 out:
8131 END_PROFILE(SMBsetattrE);
8132 return;
8136 /* Back from the dead for OS/2..... JRA. */
8138 /****************************************************************************
8139 Reply to a SMBwritebmpx (write block multiplex primary) request.
8140 Always reply with an error, if someone has a platform really needs this,
8141 please contact vl@samba.org
8142 ****************************************************************************/
8144 void reply_writebmpx(struct smb_request *req)
8146 START_PROFILE(SMBwriteBmpx);
8147 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8148 END_PROFILE(SMBwriteBmpx);
8149 return;
8152 /****************************************************************************
8153 Reply to a SMBwritebs (write block multiplex secondary) request.
8154 Always reply with an error, if someone has a platform really needs this,
8155 please contact vl@samba.org
8156 ****************************************************************************/
8158 void reply_writebs(struct smb_request *req)
8160 START_PROFILE(SMBwriteBs);
8161 reply_force_doserror(req, ERRSRV, ERRuseSTD);
8162 END_PROFILE(SMBwriteBs);
8163 return;
8166 /****************************************************************************
8167 Reply to a SMBgetattrE.
8168 ****************************************************************************/
8170 void reply_getattrE(struct smb_request *req)
8172 connection_struct *conn = req->conn;
8173 int mode;
8174 files_struct *fsp;
8175 struct timespec create_ts;
8177 START_PROFILE(SMBgetattrE);
8179 if (req->wct < 1) {
8180 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8181 END_PROFILE(SMBgetattrE);
8182 return;
8185 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
8187 if(!fsp || (fsp->conn != conn)) {
8188 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8189 END_PROFILE(SMBgetattrE);
8190 return;
8193 /* Do an fstat on this file */
8194 if(fsp_stat(fsp)) {
8195 reply_nterror(req, map_nt_error_from_unix(errno));
8196 END_PROFILE(SMBgetattrE);
8197 return;
8200 mode = dos_mode(conn, fsp->fsp_name);
8203 * Convert the times into dos times. Set create
8204 * date to be last modify date as UNIX doesn't save
8205 * this.
8208 reply_outbuf(req, 11, 0);
8210 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
8211 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
8212 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
8213 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
8214 /* Should we check pending modtime here ? JRA */
8215 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
8216 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
8218 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
8219 SIVAL(req->outbuf, smb_vwv6, 0);
8220 SIVAL(req->outbuf, smb_vwv8, 0);
8221 } else {
8222 uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
8223 SIVAL(req->outbuf, smb_vwv6, (uint32)fsp->fsp_name->st.st_ex_size);
8224 SIVAL(req->outbuf, smb_vwv8, allocation_size);
8226 SSVAL(req->outbuf,smb_vwv10, mode);
8228 DEBUG( 3, ( "reply_getattrE %s\n", fsp_fnum_dbg(fsp)));
8230 END_PROFILE(SMBgetattrE);
8231 return;