s3: Remove smbd_server_fd from netbios_session_retarget
[Samba/wip.git] / source3 / smbd / reply.c
blobf909fd696d2f9dd0ed544c946c410017067ce4f4
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 "printing.h"
29 #include "smbd/globals.h"
30 #include "../librpc/gen_ndr/cli_spoolss.h"
31 #include "rpc_client/cli_spoolss.h"
32 #include "rpc_client/init_spoolss.h"
34 /****************************************************************************
35 Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
36 path or anything including wildcards.
37 We're assuming here that '/' is not the second byte in any multibyte char
38 set (a safe assumption). '\\' *may* be the second byte in a multibyte char
39 set.
40 ****************************************************************************/
42 /* Custom version for processing POSIX paths. */
43 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
45 static NTSTATUS check_path_syntax_internal(char *path,
46 bool posix_path,
47 bool *p_last_component_contains_wcard)
49 char *d = path;
50 const char *s = path;
51 NTSTATUS ret = NT_STATUS_OK;
52 bool start_of_name_component = True;
53 bool stream_started = false;
55 *p_last_component_contains_wcard = False;
57 while (*s) {
58 if (stream_started) {
59 switch (*s) {
60 case '/':
61 case '\\':
62 return NT_STATUS_OBJECT_NAME_INVALID;
63 case ':':
64 if (s[1] == '\0') {
65 return NT_STATUS_OBJECT_NAME_INVALID;
67 if (strchr_m(&s[1], ':')) {
68 return NT_STATUS_OBJECT_NAME_INVALID;
70 break;
74 if ((*s == ':') && !posix_path && !stream_started) {
75 if (*p_last_component_contains_wcard) {
76 return NT_STATUS_OBJECT_NAME_INVALID;
78 /* Stream names allow more characters than file names.
79 We're overloading posix_path here to allow a wider
80 range of characters. If stream_started is true this
81 is still a Windows path even if posix_path is true.
82 JRA.
84 stream_started = true;
85 start_of_name_component = false;
86 posix_path = true;
88 if (s[1] == '\0') {
89 return NT_STATUS_OBJECT_NAME_INVALID;
93 if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
95 * Safe to assume is not the second part of a mb char
96 * as this is handled below.
98 /* Eat multiple '/' or '\\' */
99 while (IS_PATH_SEP(*s,posix_path)) {
100 s++;
102 if ((d != path) && (*s != '\0')) {
103 /* We only care about non-leading or trailing '/' or '\\' */
104 *d++ = '/';
107 start_of_name_component = True;
108 /* New component. */
109 *p_last_component_contains_wcard = False;
110 continue;
113 if (start_of_name_component) {
114 if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
115 /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
118 * No mb char starts with '.' so we're safe checking the directory separator here.
121 /* If we just added a '/' - delete it */
122 if ((d > path) && (*(d-1) == '/')) {
123 *(d-1) = '\0';
124 d--;
127 /* Are we at the start ? Can't go back further if so. */
128 if (d <= path) {
129 ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
130 break;
132 /* Go back one level... */
133 /* We know this is safe as '/' cannot be part of a mb sequence. */
134 /* NOTE - if this assumption is invalid we are not in good shape... */
135 /* Decrement d first as d points to the *next* char to write into. */
136 for (d--; d > path; d--) {
137 if (*d == '/')
138 break;
140 s += 2; /* Else go past the .. */
141 /* We're still at the start of a name component, just the previous one. */
142 continue;
144 } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
145 if (posix_path) {
146 /* Eat the '.' */
147 s++;
148 continue;
154 if (!(*s & 0x80)) {
155 if (!posix_path) {
156 if (*s <= 0x1f || *s == '|') {
157 return NT_STATUS_OBJECT_NAME_INVALID;
159 switch (*s) {
160 case '*':
161 case '?':
162 case '<':
163 case '>':
164 case '"':
165 *p_last_component_contains_wcard = True;
166 break;
167 default:
168 break;
171 *d++ = *s++;
172 } else {
173 size_t siz;
174 /* Get the size of the next MB character. */
175 next_codepoint(s,&siz);
176 switch(siz) {
177 case 5:
178 *d++ = *s++;
179 /*fall through*/
180 case 4:
181 *d++ = *s++;
182 /*fall through*/
183 case 3:
184 *d++ = *s++;
185 /*fall through*/
186 case 2:
187 *d++ = *s++;
188 /*fall through*/
189 case 1:
190 *d++ = *s++;
191 break;
192 default:
193 DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
194 *d = '\0';
195 return NT_STATUS_INVALID_PARAMETER;
198 start_of_name_component = False;
201 *d = '\0';
203 return ret;
206 /****************************************************************************
207 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
208 No wildcards allowed.
209 ****************************************************************************/
211 NTSTATUS check_path_syntax(char *path)
213 bool ignore;
214 return check_path_syntax_internal(path, False, &ignore);
217 /****************************************************************************
218 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
219 Wildcards allowed - p_contains_wcard returns true if the last component contained
220 a wildcard.
221 ****************************************************************************/
223 NTSTATUS check_path_syntax_wcard(char *path, bool *p_contains_wcard)
225 return check_path_syntax_internal(path, False, p_contains_wcard);
228 /****************************************************************************
229 Check the path for a POSIX client.
230 We're assuming here that '/' is not the second byte in any multibyte char
231 set (a safe assumption).
232 ****************************************************************************/
234 NTSTATUS check_path_syntax_posix(char *path)
236 bool ignore;
237 return check_path_syntax_internal(path, True, &ignore);
240 /****************************************************************************
241 Pull a string and check the path allowing a wilcard - provide for error return.
242 ****************************************************************************/
244 size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
245 const char *base_ptr,
246 uint16 smb_flags2,
247 char **pp_dest,
248 const char *src,
249 size_t src_len,
250 int flags,
251 NTSTATUS *err,
252 bool *contains_wcard)
254 size_t ret;
256 *pp_dest = NULL;
258 ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
259 src_len, flags);
261 if (!*pp_dest) {
262 *err = NT_STATUS_INVALID_PARAMETER;
263 return ret;
266 *contains_wcard = False;
268 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
270 * For a DFS path the function parse_dfs_path()
271 * will do the path processing, just make a copy.
273 *err = NT_STATUS_OK;
274 return ret;
277 if (lp_posix_pathnames()) {
278 *err = check_path_syntax_posix(*pp_dest);
279 } else {
280 *err = check_path_syntax_wcard(*pp_dest, contains_wcard);
283 return ret;
286 /****************************************************************************
287 Pull a string and check the path - provide for error return.
288 ****************************************************************************/
290 size_t srvstr_get_path(TALLOC_CTX *ctx,
291 const char *base_ptr,
292 uint16 smb_flags2,
293 char **pp_dest,
294 const char *src,
295 size_t src_len,
296 int flags,
297 NTSTATUS *err)
299 bool ignore;
300 return srvstr_get_path_wcard(ctx, base_ptr, smb_flags2, pp_dest, src,
301 src_len, flags, err, &ignore);
304 size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req,
305 char **pp_dest, const char *src, int flags,
306 NTSTATUS *err, bool *contains_wcard)
308 return srvstr_get_path_wcard(mem_ctx, (char *)req->inbuf, req->flags2,
309 pp_dest, src, smbreq_bufrem(req, src),
310 flags, err, contains_wcard);
313 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
314 char **pp_dest, const char *src, int flags,
315 NTSTATUS *err)
317 bool ignore;
318 return srvstr_get_path_req_wcard(mem_ctx, req, pp_dest, src,
319 flags, err, &ignore);
322 /****************************************************************************
323 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
324 ****************************************************************************/
326 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
327 files_struct *fsp)
329 if ((fsp == NULL) || (conn == NULL)) {
330 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
331 return False;
333 if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
334 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
335 return False;
337 return True;
340 /****************************************************************************
341 Check if we have a correct fsp pointing to a file.
342 ****************************************************************************/
344 bool check_fsp(connection_struct *conn, struct smb_request *req,
345 files_struct *fsp)
347 if (!check_fsp_open(conn, req, fsp)) {
348 return False;
350 if (fsp->is_directory) {
351 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
352 return False;
354 if (fsp->fh->fd == -1) {
355 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
356 return False;
358 fsp->num_smb_operations++;
359 return True;
362 /****************************************************************************
363 Check if we have a correct fsp pointing to a quota fake file. Replacement for
364 the CHECK_NTQUOTA_HANDLE_OK macro.
365 ****************************************************************************/
367 bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
368 files_struct *fsp)
370 if (!check_fsp_open(conn, req, fsp)) {
371 return false;
374 if (fsp->is_directory) {
375 return false;
378 if (fsp->fake_file_handle == NULL) {
379 return false;
382 if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
383 return false;
386 if (fsp->fake_file_handle->private_data == NULL) {
387 return false;
390 return true;
393 static bool netbios_session_retarget(struct smbd_server_connection *sconn,
394 const char *name, int name_type)
396 char *trim_name;
397 char *trim_name_type;
398 const char *retarget_parm;
399 char *retarget;
400 char *p;
401 int retarget_type = 0x20;
402 int retarget_port = 139;
403 struct sockaddr_storage retarget_addr;
404 struct sockaddr_in *in_addr;
405 bool ret = false;
406 uint8_t outbuf[10];
408 if (get_socket_port(sconn->sock) != 139) {
409 return false;
412 trim_name = talloc_strdup(talloc_tos(), name);
413 if (trim_name == NULL) {
414 goto fail;
416 trim_char(trim_name, ' ', ' ');
418 trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
419 name_type);
420 if (trim_name_type == NULL) {
421 goto fail;
424 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
425 trim_name_type, NULL);
426 if (retarget_parm == NULL) {
427 retarget_parm = lp_parm_const_string(-1, "netbios retarget",
428 trim_name, NULL);
430 if (retarget_parm == NULL) {
431 goto fail;
434 retarget = talloc_strdup(trim_name, retarget_parm);
435 if (retarget == NULL) {
436 goto fail;
439 DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
441 p = strchr(retarget, ':');
442 if (p != NULL) {
443 *p++ = '\0';
444 retarget_port = atoi(p);
447 p = strchr_m(retarget, '#');
448 if (p != NULL) {
449 *p++ = '\0';
450 sscanf(p, "%x", &retarget_type);
453 ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
454 if (!ret) {
455 DEBUG(10, ("could not resolve %s\n", retarget));
456 goto fail;
459 if (retarget_addr.ss_family != AF_INET) {
460 DEBUG(10, ("Retarget target not an IPv4 addr\n"));
461 goto fail;
464 in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
466 _smb_setlen(outbuf, 6);
467 SCVAL(outbuf, 0, 0x84);
468 *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
469 *(uint16_t *)(outbuf+8) = htons(retarget_port);
471 if (!srv_send_smb(sconn->sock, (char *)outbuf, false, 0, false,
472 NULL)) {
473 exit_server_cleanly("netbios_session_regarget: srv_send_smb "
474 "failed.");
477 ret = true;
478 fail:
479 TALLOC_FREE(trim_name);
480 return ret;
483 /****************************************************************************
484 Reply to a (netbios-level) special message.
485 ****************************************************************************/
487 void reply_special(struct smbd_server_connection *sconn, char *inbuf)
489 int msg_type = CVAL(inbuf,0);
490 int msg_flags = CVAL(inbuf,1);
491 fstring name1,name2;
492 char name_type1, name_type2;
495 * We only really use 4 bytes of the outbuf, but for the smb_setlen
496 * calculation & friends (srv_send_smb uses that) we need the full smb
497 * header.
499 char outbuf[smb_size];
501 *name1 = *name2 = 0;
503 memset(outbuf, '\0', sizeof(outbuf));
505 smb_setlen(outbuf,0);
507 switch (msg_type) {
508 case 0x81: /* session request */
510 if (sconn->nbt.got_session) {
511 exit_server_cleanly("multiple session request not permitted");
514 SCVAL(outbuf,0,0x82);
515 SCVAL(outbuf,3,0);
516 if (name_len(inbuf+4) > 50 ||
517 name_len(inbuf+4 + name_len(inbuf + 4)) > 50) {
518 DEBUG(0,("Invalid name length in session request\n"));
519 return;
521 name_type1 = name_extract(inbuf,4,name1);
522 name_type2 = name_extract(inbuf,4 + name_len(inbuf + 4),name2);
523 DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
524 name1, name_type1, name2, name_type2));
526 if (netbios_session_retarget(sconn, name1, name_type1)) {
527 exit_server_cleanly("retargeted client");
530 set_local_machine_name(name1, True);
531 set_remote_machine_name(name2, True);
533 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
534 get_local_machine_name(), get_remote_machine_name(),
535 name_type2));
537 if (name_type2 == 'R') {
538 /* We are being asked for a pathworks session ---
539 no thanks! */
540 SCVAL(outbuf, 0,0x83);
541 break;
544 /* only add the client's machine name to the list
545 of possibly valid usernames if we are operating
546 in share mode security */
547 if (lp_security() == SEC_SHARE) {
548 add_session_user(sconn, get_remote_machine_name());
551 reload_services(sconn->msg_ctx, True);
552 reopen_logs();
554 sconn->nbt.got_session = true;
555 break;
557 case 0x89: /* session keepalive request
558 (some old clients produce this?) */
559 SCVAL(outbuf,0,SMBkeepalive);
560 SCVAL(outbuf,3,0);
561 break;
563 case 0x82: /* positive session response */
564 case 0x83: /* negative session response */
565 case 0x84: /* retarget session response */
566 DEBUG(0,("Unexpected session response\n"));
567 break;
569 case SMBkeepalive: /* session keepalive */
570 default:
571 return;
574 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
575 msg_type, msg_flags));
577 srv_send_smb(sconn->sock, outbuf, false, 0, false, NULL);
578 return;
581 /****************************************************************************
582 Reply to a tcon.
583 conn POINTER CAN BE NULL HERE !
584 ****************************************************************************/
586 void reply_tcon(struct smb_request *req)
588 connection_struct *conn = req->conn;
589 const char *service;
590 char *service_buf = NULL;
591 char *password = NULL;
592 char *dev = NULL;
593 int pwlen=0;
594 NTSTATUS nt_status;
595 const char *p;
596 DATA_BLOB password_blob;
597 TALLOC_CTX *ctx = talloc_tos();
598 struct smbd_server_connection *sconn = req->sconn;
600 START_PROFILE(SMBtcon);
602 if (req->buflen < 4) {
603 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
604 END_PROFILE(SMBtcon);
605 return;
608 p = (const char *)req->buf + 1;
609 p += srvstr_pull_req_talloc(ctx, req, &service_buf, p, STR_TERMINATE);
610 p += 1;
611 pwlen = srvstr_pull_req_talloc(ctx, req, &password, p, STR_TERMINATE);
612 p += pwlen+1;
613 p += srvstr_pull_req_talloc(ctx, req, &dev, p, STR_TERMINATE);
614 p += 1;
616 if (service_buf == NULL || password == NULL || dev == NULL) {
617 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
618 END_PROFILE(SMBtcon);
619 return;
621 p = strrchr_m(service_buf,'\\');
622 if (p) {
623 service = p+1;
624 } else {
625 service = service_buf;
628 password_blob = data_blob(password, pwlen+1);
630 conn = make_connection(sconn,service,password_blob,dev,
631 req->vuid,&nt_status);
632 req->conn = conn;
634 data_blob_clear_free(&password_blob);
636 if (!conn) {
637 reply_nterror(req, nt_status);
638 END_PROFILE(SMBtcon);
639 return;
642 reply_outbuf(req, 2, 0);
643 SSVAL(req->outbuf,smb_vwv0,sconn->smb1.negprot.max_recv);
644 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
645 SSVAL(req->outbuf,smb_tid,conn->cnum);
647 DEBUG(3,("tcon service=%s cnum=%d\n",
648 service, conn->cnum));
650 END_PROFILE(SMBtcon);
651 return;
654 /****************************************************************************
655 Reply to a tcon and X.
656 conn POINTER CAN BE NULL HERE !
657 ****************************************************************************/
659 void reply_tcon_and_X(struct smb_request *req)
661 connection_struct *conn = req->conn;
662 const char *service = NULL;
663 DATA_BLOB password;
664 TALLOC_CTX *ctx = talloc_tos();
665 /* what the cleint thinks the device is */
666 char *client_devicetype = NULL;
667 /* what the server tells the client the share represents */
668 const char *server_devicetype;
669 NTSTATUS nt_status;
670 int passlen;
671 char *path = NULL;
672 const char *p, *q;
673 uint16 tcon_flags;
674 struct smbd_server_connection *sconn = req->sconn;
676 START_PROFILE(SMBtconX);
678 if (req->wct < 4) {
679 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
680 END_PROFILE(SMBtconX);
681 return;
684 passlen = SVAL(req->vwv+3, 0);
685 tcon_flags = SVAL(req->vwv+2, 0);
687 /* we might have to close an old one */
688 if ((tcon_flags & 0x1) && conn) {
689 close_cnum(conn,req->vuid);
690 req->conn = NULL;
691 conn = NULL;
694 if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
695 reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
696 END_PROFILE(SMBtconX);
697 return;
700 if (sconn->smb1.negprot.encrypted_passwords) {
701 password = data_blob_talloc(talloc_tos(), req->buf, passlen);
702 if (lp_security() == SEC_SHARE) {
704 * Security = share always has a pad byte
705 * after the password.
707 p = (const char *)req->buf + passlen + 1;
708 } else {
709 p = (const char *)req->buf + passlen;
711 } else {
712 password = data_blob_talloc(talloc_tos(), req->buf, passlen+1);
713 /* Ensure correct termination */
714 password.data[passlen]=0;
715 p = (const char *)req->buf + passlen + 1;
718 p += srvstr_pull_req_talloc(ctx, req, &path, p, STR_TERMINATE);
720 if (path == NULL) {
721 data_blob_clear_free(&password);
722 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
723 END_PROFILE(SMBtconX);
724 return;
728 * the service name can be either: \\server\share
729 * or share directly like on the DELL PowerVault 705
731 if (*path=='\\') {
732 q = strchr_m(path+2,'\\');
733 if (!q) {
734 data_blob_clear_free(&password);
735 reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
736 END_PROFILE(SMBtconX);
737 return;
739 service = q+1;
740 } else {
741 service = path;
744 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
745 &client_devicetype, p,
746 MIN(6, smbreq_bufrem(req, p)), STR_ASCII);
748 if (client_devicetype == NULL) {
749 data_blob_clear_free(&password);
750 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
751 END_PROFILE(SMBtconX);
752 return;
755 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
757 conn = make_connection(sconn, service, password, client_devicetype,
758 req->vuid, &nt_status);
759 req->conn =conn;
761 data_blob_clear_free(&password);
763 if (!conn) {
764 reply_nterror(req, nt_status);
765 END_PROFILE(SMBtconX);
766 return;
769 if ( IS_IPC(conn) )
770 server_devicetype = "IPC";
771 else if ( IS_PRINT(conn) )
772 server_devicetype = "LPT1:";
773 else
774 server_devicetype = "A:";
776 if (get_Protocol() < PROTOCOL_NT1) {
777 reply_outbuf(req, 2, 0);
778 if (message_push_string(&req->outbuf, server_devicetype,
779 STR_TERMINATE|STR_ASCII) == -1) {
780 reply_nterror(req, NT_STATUS_NO_MEMORY);
781 END_PROFILE(SMBtconX);
782 return;
784 } else {
785 /* NT sets the fstype of IPC$ to the null string */
786 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
788 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
789 /* Return permissions. */
790 uint32 perm1 = 0;
791 uint32 perm2 = 0;
793 reply_outbuf(req, 7, 0);
795 if (IS_IPC(conn)) {
796 perm1 = FILE_ALL_ACCESS;
797 perm2 = FILE_ALL_ACCESS;
798 } else {
799 perm1 = CAN_WRITE(conn) ?
800 SHARE_ALL_ACCESS :
801 SHARE_READ_ONLY;
804 SIVAL(req->outbuf, smb_vwv3, perm1);
805 SIVAL(req->outbuf, smb_vwv5, perm2);
806 } else {
807 reply_outbuf(req, 3, 0);
810 if ((message_push_string(&req->outbuf, server_devicetype,
811 STR_TERMINATE|STR_ASCII) == -1)
812 || (message_push_string(&req->outbuf, fstype,
813 STR_TERMINATE) == -1)) {
814 reply_nterror(req, NT_STATUS_NO_MEMORY);
815 END_PROFILE(SMBtconX);
816 return;
819 /* what does setting this bit do? It is set by NT4 and
820 may affect the ability to autorun mounted cdroms */
821 SSVAL(req->outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS|
822 (lp_csc_policy(SNUM(conn)) << 2));
824 if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
825 DEBUG(2,("Serving %s as a Dfs root\n",
826 lp_servicename(SNUM(conn)) ));
827 SSVAL(req->outbuf, smb_vwv2,
828 SMB_SHARE_IN_DFS | SVAL(req->outbuf, smb_vwv2));
833 DEBUG(3,("tconX service=%s \n",
834 service));
836 /* set the incoming and outgoing tid to the just created one */
837 SSVAL(req->inbuf,smb_tid,conn->cnum);
838 SSVAL(req->outbuf,smb_tid,conn->cnum);
840 END_PROFILE(SMBtconX);
842 req->tid = conn->cnum;
843 chain_reply(req);
844 return;
847 /****************************************************************************
848 Reply to an unknown type.
849 ****************************************************************************/
851 void reply_unknown_new(struct smb_request *req, uint8 type)
853 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
854 smb_fn_name(type), type, type));
855 reply_force_doserror(req, ERRSRV, ERRunknownsmb);
856 return;
859 /****************************************************************************
860 Reply to an ioctl.
861 conn POINTER CAN BE NULL HERE !
862 ****************************************************************************/
864 void reply_ioctl(struct smb_request *req)
866 connection_struct *conn = req->conn;
867 uint16 device;
868 uint16 function;
869 uint32 ioctl_code;
870 int replysize;
871 char *p;
873 START_PROFILE(SMBioctl);
875 if (req->wct < 3) {
876 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
877 END_PROFILE(SMBioctl);
878 return;
881 device = SVAL(req->vwv+1, 0);
882 function = SVAL(req->vwv+2, 0);
883 ioctl_code = (device << 16) + function;
885 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
887 switch (ioctl_code) {
888 case IOCTL_QUERY_JOB_INFO:
889 replysize = 32;
890 break;
891 default:
892 reply_force_doserror(req, ERRSRV, ERRnosupport);
893 END_PROFILE(SMBioctl);
894 return;
897 reply_outbuf(req, 8, replysize+1);
898 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
899 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
900 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
901 p = smb_buf(req->outbuf);
902 memset(p, '\0', replysize+1); /* valgrind-safe. */
903 p += 1; /* Allow for alignment */
905 switch (ioctl_code) {
906 case IOCTL_QUERY_JOB_INFO:
908 files_struct *fsp = file_fsp(
909 req, SVAL(req->vwv+0, 0));
910 if (!fsp) {
911 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
912 END_PROFILE(SMBioctl);
913 return;
915 /* Job number */
916 if (fsp->print_file) {
917 SSVAL(p, 0, fsp->print_file->rap_jobid);
918 } else {
919 SSVAL(p, 0, 0);
921 srvstr_push((char *)req->outbuf, req->flags2, p+2,
922 global_myname(), 15,
923 STR_TERMINATE|STR_ASCII);
924 if (conn) {
925 srvstr_push((char *)req->outbuf, req->flags2,
926 p+18, lp_servicename(SNUM(conn)),
927 13, STR_TERMINATE|STR_ASCII);
928 } else {
929 memset(p+18, 0, 13);
931 break;
935 END_PROFILE(SMBioctl);
936 return;
939 /****************************************************************************
940 Strange checkpath NTSTATUS mapping.
941 ****************************************************************************/
943 static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
945 /* Strange DOS error code semantics only for checkpath... */
946 if (!(flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
947 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
948 /* We need to map to ERRbadpath */
949 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
952 return status;
955 /****************************************************************************
956 Reply to a checkpath.
957 ****************************************************************************/
959 void reply_checkpath(struct smb_request *req)
961 connection_struct *conn = req->conn;
962 struct smb_filename *smb_fname = NULL;
963 char *name = NULL;
964 NTSTATUS status;
965 TALLOC_CTX *ctx = talloc_tos();
967 START_PROFILE(SMBcheckpath);
969 srvstr_get_path_req(ctx, req, &name, (const char *)req->buf + 1,
970 STR_TERMINATE, &status);
972 if (!NT_STATUS_IS_OK(status)) {
973 status = map_checkpath_error(req->flags2, status);
974 reply_nterror(req, status);
975 END_PROFILE(SMBcheckpath);
976 return;
979 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
981 status = filename_convert(ctx,
982 conn,
983 req->flags2 & FLAGS2_DFS_PATHNAMES,
984 name,
986 NULL,
987 &smb_fname);
989 if (!NT_STATUS_IS_OK(status)) {
990 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
991 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
992 ERRSRV, ERRbadpath);
993 END_PROFILE(SMBcheckpath);
994 return;
996 goto path_err;
999 if (!VALID_STAT(smb_fname->st) &&
1000 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1001 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",
1002 smb_fname_str_dbg(smb_fname), strerror(errno)));
1003 status = map_nt_error_from_unix(errno);
1004 goto path_err;
1007 if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1008 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
1009 ERRDOS, ERRbadpath);
1010 goto out;
1013 reply_outbuf(req, 0, 0);
1015 path_err:
1016 /* We special case this - as when a Windows machine
1017 is parsing a path is steps through the components
1018 one at a time - if a component fails it expects
1019 ERRbadpath, not ERRbadfile.
1021 status = map_checkpath_error(req->flags2, status);
1022 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1024 * Windows returns different error codes if
1025 * the parent directory is valid but not the
1026 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
1027 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
1028 * if the path is invalid.
1030 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
1031 ERRDOS, ERRbadpath);
1032 goto out;
1035 reply_nterror(req, status);
1037 out:
1038 TALLOC_FREE(smb_fname);
1039 END_PROFILE(SMBcheckpath);
1040 return;
1043 /****************************************************************************
1044 Reply to a getatr.
1045 ****************************************************************************/
1047 void reply_getatr(struct smb_request *req)
1049 connection_struct *conn = req->conn;
1050 struct smb_filename *smb_fname = NULL;
1051 char *fname = NULL;
1052 int mode=0;
1053 SMB_OFF_T size=0;
1054 time_t mtime=0;
1055 const char *p;
1056 NTSTATUS status;
1057 TALLOC_CTX *ctx = talloc_tos();
1058 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1060 START_PROFILE(SMBgetatr);
1062 p = (const char *)req->buf + 1;
1063 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1064 if (!NT_STATUS_IS_OK(status)) {
1065 reply_nterror(req, status);
1066 goto out;
1069 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1070 under WfWg - weird! */
1071 if (*fname == '\0') {
1072 mode = aHIDDEN | aDIR;
1073 if (!CAN_WRITE(conn)) {
1074 mode |= aRONLY;
1076 size = 0;
1077 mtime = 0;
1078 } else {
1079 status = filename_convert(ctx,
1080 conn,
1081 req->flags2 & FLAGS2_DFS_PATHNAMES,
1082 fname,
1084 NULL,
1085 &smb_fname);
1086 if (!NT_STATUS_IS_OK(status)) {
1087 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1088 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1089 ERRSRV, ERRbadpath);
1090 goto out;
1092 reply_nterror(req, status);
1093 goto out;
1095 if (!VALID_STAT(smb_fname->st) &&
1096 (SMB_VFS_STAT(conn, smb_fname) != 0)) {
1097 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",
1098 smb_fname_str_dbg(smb_fname),
1099 strerror(errno)));
1100 reply_nterror(req, map_nt_error_from_unix(errno));
1101 goto out;
1104 mode = dos_mode(conn, smb_fname);
1105 size = smb_fname->st.st_ex_size;
1107 if (ask_sharemode) {
1108 struct timespec write_time_ts;
1109 struct file_id fileid;
1111 ZERO_STRUCT(write_time_ts);
1112 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1113 get_file_infos(fileid, NULL, &write_time_ts);
1114 if (!null_timespec(write_time_ts)) {
1115 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1119 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1120 if (mode & aDIR) {
1121 size = 0;
1125 reply_outbuf(req, 10, 0);
1127 SSVAL(req->outbuf,smb_vwv0,mode);
1128 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1129 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1130 } else {
1131 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1133 SIVAL(req->outbuf,smb_vwv3,(uint32)size);
1135 if (get_Protocol() >= PROTOCOL_NT1) {
1136 SSVAL(req->outbuf, smb_flg2,
1137 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1140 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n",
1141 smb_fname_str_dbg(smb_fname), mode, (unsigned int)size));
1143 out:
1144 TALLOC_FREE(smb_fname);
1145 TALLOC_FREE(fname);
1146 END_PROFILE(SMBgetatr);
1147 return;
1150 /****************************************************************************
1151 Reply to a setatr.
1152 ****************************************************************************/
1154 void reply_setatr(struct smb_request *req)
1156 struct smb_file_time ft;
1157 connection_struct *conn = req->conn;
1158 struct smb_filename *smb_fname = NULL;
1159 char *fname = NULL;
1160 int mode;
1161 time_t mtime;
1162 const char *p;
1163 NTSTATUS status;
1164 TALLOC_CTX *ctx = talloc_tos();
1166 START_PROFILE(SMBsetatr);
1168 ZERO_STRUCT(ft);
1170 if (req->wct < 2) {
1171 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1172 goto out;
1175 p = (const char *)req->buf + 1;
1176 p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
1177 if (!NT_STATUS_IS_OK(status)) {
1178 reply_nterror(req, status);
1179 goto out;
1182 status = filename_convert(ctx,
1183 conn,
1184 req->flags2 & FLAGS2_DFS_PATHNAMES,
1185 fname,
1187 NULL,
1188 &smb_fname);
1189 if (!NT_STATUS_IS_OK(status)) {
1190 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1191 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1192 ERRSRV, ERRbadpath);
1193 goto out;
1195 reply_nterror(req, status);
1196 goto out;
1199 if (smb_fname->base_name[0] == '.' &&
1200 smb_fname->base_name[1] == '\0') {
1202 * Not sure here is the right place to catch this
1203 * condition. Might be moved to somewhere else later -- vl
1205 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1206 goto out;
1209 mode = SVAL(req->vwv+0, 0);
1210 mtime = srv_make_unix_date3(req->vwv+1);
1212 ft.mtime = convert_time_t_to_timespec(mtime);
1213 status = smb_set_file_time(conn, NULL, smb_fname, &ft, true);
1214 if (!NT_STATUS_IS_OK(status)) {
1215 reply_nterror(req, status);
1216 goto out;
1219 if (mode != FILE_ATTRIBUTE_NORMAL) {
1220 if (VALID_STAT_OF_DIR(smb_fname->st))
1221 mode |= aDIR;
1222 else
1223 mode &= ~aDIR;
1225 if (file_set_dosmode(conn, smb_fname, mode, NULL,
1226 false) != 0) {
1227 reply_nterror(req, map_nt_error_from_unix(errno));
1228 goto out;
1232 reply_outbuf(req, 0, 0);
1234 DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname),
1235 mode));
1236 out:
1237 TALLOC_FREE(smb_fname);
1238 END_PROFILE(SMBsetatr);
1239 return;
1242 /****************************************************************************
1243 Reply to a dskattr.
1244 ****************************************************************************/
1246 void reply_dskattr(struct smb_request *req)
1248 connection_struct *conn = req->conn;
1249 uint64_t dfree,dsize,bsize;
1250 START_PROFILE(SMBdskattr);
1252 if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (uint64_t)-1) {
1253 reply_nterror(req, map_nt_error_from_unix(errno));
1254 END_PROFILE(SMBdskattr);
1255 return;
1258 reply_outbuf(req, 5, 0);
1260 if (get_Protocol() <= PROTOCOL_LANMAN2) {
1261 double total_space, free_space;
1262 /* we need to scale this to a number that DOS6 can handle. We
1263 use floating point so we can handle large drives on systems
1264 that don't have 64 bit integers
1266 we end up displaying a maximum of 2G to DOS systems
1268 total_space = dsize * (double)bsize;
1269 free_space = dfree * (double)bsize;
1271 dsize = (uint64_t)((total_space+63*512) / (64*512));
1272 dfree = (uint64_t)((free_space+63*512) / (64*512));
1274 if (dsize > 0xFFFF) dsize = 0xFFFF;
1275 if (dfree > 0xFFFF) dfree = 0xFFFF;
1277 SSVAL(req->outbuf,smb_vwv0,dsize);
1278 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1279 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1280 SSVAL(req->outbuf,smb_vwv3,dfree);
1281 } else {
1282 SSVAL(req->outbuf,smb_vwv0,dsize);
1283 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1284 SSVAL(req->outbuf,smb_vwv2,512);
1285 SSVAL(req->outbuf,smb_vwv3,dfree);
1288 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1290 END_PROFILE(SMBdskattr);
1291 return;
1295 * Utility function to split the filename from the directory.
1297 static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in,
1298 char **fname_dir_out,
1299 char **fname_mask_out)
1301 const char *p = NULL;
1302 char *fname_dir = NULL;
1303 char *fname_mask = NULL;
1305 p = strrchr_m(fname_in, '/');
1306 if (!p) {
1307 fname_dir = talloc_strdup(ctx, ".");
1308 fname_mask = talloc_strdup(ctx, fname_in);
1309 } else {
1310 fname_dir = talloc_strndup(ctx, fname_in,
1311 PTR_DIFF(p, fname_in));
1312 fname_mask = talloc_strdup(ctx, p+1);
1315 if (!fname_dir || !fname_mask) {
1316 TALLOC_FREE(fname_dir);
1317 TALLOC_FREE(fname_mask);
1318 return NT_STATUS_NO_MEMORY;
1321 *fname_dir_out = fname_dir;
1322 *fname_mask_out = fname_mask;
1323 return NT_STATUS_OK;
1326 /****************************************************************************
1327 Reply to a search.
1328 Can be called from SMBsearch, SMBffirst or SMBfunique.
1329 ****************************************************************************/
1331 void reply_search(struct smb_request *req)
1333 connection_struct *conn = req->conn;
1334 char *path = NULL;
1335 const char *mask = NULL;
1336 char *directory = NULL;
1337 struct smb_filename *smb_fname = NULL;
1338 char *fname = NULL;
1339 SMB_OFF_T size;
1340 uint32 mode;
1341 struct timespec date;
1342 uint32 dirtype;
1343 unsigned int numentries = 0;
1344 unsigned int maxentries = 0;
1345 bool finished = False;
1346 const char *p;
1347 int status_len;
1348 char status[21];
1349 int dptr_num= -1;
1350 bool check_descend = False;
1351 bool expect_close = False;
1352 NTSTATUS nt_status;
1353 bool mask_contains_wcard = False;
1354 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1355 TALLOC_CTX *ctx = talloc_tos();
1356 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1357 struct dptr_struct *dirptr = NULL;
1358 struct smbd_server_connection *sconn = req->sconn;
1360 START_PROFILE(SMBsearch);
1362 if (req->wct < 2) {
1363 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1364 goto out;
1367 if (lp_posix_pathnames()) {
1368 reply_unknown_new(req, req->cmd);
1369 goto out;
1372 /* If we were called as SMBffirst then we must expect close. */
1373 if(req->cmd == SMBffirst) {
1374 expect_close = True;
1377 reply_outbuf(req, 1, 3);
1378 maxentries = SVAL(req->vwv+0, 0);
1379 dirtype = SVAL(req->vwv+1, 0);
1380 p = (const char *)req->buf + 1;
1381 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1382 &nt_status, &mask_contains_wcard);
1383 if (!NT_STATUS_IS_OK(nt_status)) {
1384 reply_nterror(req, nt_status);
1385 goto out;
1388 p++;
1389 status_len = SVAL(p, 0);
1390 p += 2;
1392 /* dirtype &= ~aDIR; */
1394 if (status_len == 0) {
1395 nt_status = filename_convert(ctx, conn,
1396 req->flags2 & FLAGS2_DFS_PATHNAMES,
1397 path,
1398 UCF_ALWAYS_ALLOW_WCARD_LCOMP,
1399 &mask_contains_wcard,
1400 &smb_fname);
1401 if (!NT_STATUS_IS_OK(nt_status)) {
1402 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1403 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1404 ERRSRV, ERRbadpath);
1405 goto out;
1407 reply_nterror(req, nt_status);
1408 goto out;
1411 directory = smb_fname->base_name;
1413 p = strrchr_m(directory,'/');
1414 if ((p != NULL) && (*directory != '/')) {
1415 mask = p + 1;
1416 directory = talloc_strndup(ctx, directory,
1417 PTR_DIFF(p, directory));
1418 } else {
1419 mask = directory;
1420 directory = talloc_strdup(ctx,".");
1423 if (!directory) {
1424 reply_nterror(req, NT_STATUS_NO_MEMORY);
1425 goto out;
1428 memset((char *)status,'\0',21);
1429 SCVAL(status,0,(dirtype & 0x1F));
1431 nt_status = dptr_create(conn,
1432 directory,
1433 True,
1434 expect_close,
1435 req->smbpid,
1436 mask,
1437 mask_contains_wcard,
1438 dirtype,
1439 &dirptr);
1440 if (!NT_STATUS_IS_OK(nt_status)) {
1441 reply_nterror(req, nt_status);
1442 goto out;
1444 dptr_num = dptr_dnum(dirptr);
1445 } else {
1446 int status_dirtype;
1447 const char *dirpath;
1449 memcpy(status,p,21);
1450 status_dirtype = CVAL(status,0) & 0x1F;
1451 if (status_dirtype != (dirtype & 0x1F)) {
1452 dirtype = status_dirtype;
1455 dirptr = dptr_fetch(sconn, status+12,&dptr_num);
1456 if (!dirptr) {
1457 goto SearchEmpty;
1459 dirpath = dptr_path(sconn, dptr_num);
1460 directory = talloc_strdup(ctx, dirpath);
1461 if (!directory) {
1462 reply_nterror(req, NT_STATUS_NO_MEMORY);
1463 goto out;
1466 mask = dptr_wcard(sconn, dptr_num);
1467 if (!mask) {
1468 goto SearchEmpty;
1471 * For a 'continue' search we have no string. So
1472 * check from the initial saved string.
1474 mask_contains_wcard = ms_has_wild(mask);
1475 dirtype = dptr_attr(sconn, dptr_num);
1478 DEBUG(4,("dptr_num is %d\n",dptr_num));
1480 /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
1481 dptr_init_search_op(dirptr);
1483 if ((dirtype&0x1F) == aVOLID) {
1484 char buf[DIR_STRUCT_SIZE];
1485 memcpy(buf,status,21);
1486 if (!make_dir_struct(ctx,buf,"???????????",volume_label(SNUM(conn)),
1487 0,aVOLID,0,!allow_long_path_components)) {
1488 reply_nterror(req, NT_STATUS_NO_MEMORY);
1489 goto out;
1491 dptr_fill(sconn, buf+12,dptr_num);
1492 if (dptr_zero(buf+12) && (status_len==0)) {
1493 numentries = 1;
1494 } else {
1495 numentries = 0;
1497 if (message_push_blob(&req->outbuf,
1498 data_blob_const(buf, sizeof(buf)))
1499 == -1) {
1500 reply_nterror(req, NT_STATUS_NO_MEMORY);
1501 goto out;
1503 } else {
1504 unsigned int i;
1505 maxentries = MIN(
1506 maxentries,
1507 ((BUFFER_SIZE -
1508 ((uint8 *)smb_buf(req->outbuf) + 3 - req->outbuf))
1509 /DIR_STRUCT_SIZE));
1511 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1512 directory,lp_dontdescend(SNUM(conn))));
1513 if (in_list(directory, lp_dontdescend(SNUM(conn)),True)) {
1514 check_descend = True;
1517 for (i=numentries;(i<maxentries) && !finished;i++) {
1518 finished = !get_dir_entry(ctx,
1519 dirptr,
1520 mask,
1521 dirtype,
1522 &fname,
1523 &size,
1524 &mode,
1525 &date,
1526 check_descend,
1527 ask_sharemode);
1528 if (!finished) {
1529 char buf[DIR_STRUCT_SIZE];
1530 memcpy(buf,status,21);
1531 if (!make_dir_struct(ctx,
1532 buf,
1533 mask,
1534 fname,
1535 size,
1536 mode,
1537 convert_timespec_to_time_t(date),
1538 !allow_long_path_components)) {
1539 reply_nterror(req, NT_STATUS_NO_MEMORY);
1540 goto out;
1542 if (!dptr_fill(sconn, buf+12,dptr_num)) {
1543 break;
1545 if (message_push_blob(&req->outbuf,
1546 data_blob_const(buf, sizeof(buf)))
1547 == -1) {
1548 reply_nterror(req, NT_STATUS_NO_MEMORY);
1549 goto out;
1551 numentries++;
1556 SearchEmpty:
1558 /* If we were called as SMBffirst with smb_search_id == NULL
1559 and no entries were found then return error and close dirptr
1560 (X/Open spec) */
1562 if (numentries == 0) {
1563 dptr_close(sconn, &dptr_num);
1564 } else if(expect_close && status_len == 0) {
1565 /* Close the dptr - we know it's gone */
1566 dptr_close(sconn, &dptr_num);
1569 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1570 if(dptr_num >= 0 && req->cmd == SMBfunique) {
1571 dptr_close(sconn, &dptr_num);
1574 if ((numentries == 0) && !mask_contains_wcard) {
1575 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1576 goto out;
1579 SSVAL(req->outbuf,smb_vwv0,numentries);
1580 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1581 SCVAL(smb_buf(req->outbuf),0,5);
1582 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1584 /* The replies here are never long name. */
1585 SSVAL(req->outbuf, smb_flg2,
1586 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1587 if (!allow_long_path_components) {
1588 SSVAL(req->outbuf, smb_flg2,
1589 SVAL(req->outbuf, smb_flg2)
1590 & (~FLAGS2_LONG_PATH_COMPONENTS));
1593 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
1594 SSVAL(req->outbuf, smb_flg2,
1595 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
1597 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
1598 smb_fn_name(req->cmd),
1599 mask,
1600 directory,
1601 dirtype,
1602 numentries,
1603 maxentries ));
1604 out:
1605 TALLOC_FREE(directory);
1606 TALLOC_FREE(smb_fname);
1607 END_PROFILE(SMBsearch);
1608 return;
1611 /****************************************************************************
1612 Reply to a fclose (stop directory search).
1613 ****************************************************************************/
1615 void reply_fclose(struct smb_request *req)
1617 int status_len;
1618 char status[21];
1619 int dptr_num= -2;
1620 const char *p;
1621 char *path = NULL;
1622 NTSTATUS err;
1623 bool path_contains_wcard = False;
1624 TALLOC_CTX *ctx = talloc_tos();
1625 struct smbd_server_connection *sconn = req->sconn;
1627 START_PROFILE(SMBfclose);
1629 if (lp_posix_pathnames()) {
1630 reply_unknown_new(req, req->cmd);
1631 END_PROFILE(SMBfclose);
1632 return;
1635 p = (const char *)req->buf + 1;
1636 p += srvstr_get_path_req_wcard(ctx, req, &path, p, STR_TERMINATE,
1637 &err, &path_contains_wcard);
1638 if (!NT_STATUS_IS_OK(err)) {
1639 reply_nterror(req, err);
1640 END_PROFILE(SMBfclose);
1641 return;
1643 p++;
1644 status_len = SVAL(p,0);
1645 p += 2;
1647 if (status_len == 0) {
1648 reply_force_doserror(req, ERRSRV, ERRsrverror);
1649 END_PROFILE(SMBfclose);
1650 return;
1653 memcpy(status,p,21);
1655 if(dptr_fetch(sconn, status+12,&dptr_num)) {
1656 /* Close the dptr - we know it's gone */
1657 dptr_close(sconn, &dptr_num);
1660 reply_outbuf(req, 1, 0);
1661 SSVAL(req->outbuf,smb_vwv0,0);
1663 DEBUG(3,("search close\n"));
1665 END_PROFILE(SMBfclose);
1666 return;
1669 /****************************************************************************
1670 Reply to an open.
1671 ****************************************************************************/
1673 void reply_open(struct smb_request *req)
1675 connection_struct *conn = req->conn;
1676 struct smb_filename *smb_fname = NULL;
1677 char *fname = NULL;
1678 uint32 fattr=0;
1679 SMB_OFF_T size = 0;
1680 time_t mtime=0;
1681 int info;
1682 files_struct *fsp;
1683 int oplock_request;
1684 int deny_mode;
1685 uint32 dos_attr;
1686 uint32 access_mask;
1687 uint32 share_mode;
1688 uint32 create_disposition;
1689 uint32 create_options = 0;
1690 uint32_t private_flags = 0;
1691 NTSTATUS status;
1692 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
1693 TALLOC_CTX *ctx = talloc_tos();
1695 START_PROFILE(SMBopen);
1697 if (req->wct < 2) {
1698 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1699 goto out;
1702 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1703 deny_mode = SVAL(req->vwv+0, 0);
1704 dos_attr = SVAL(req->vwv+1, 0);
1706 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
1707 STR_TERMINATE, &status);
1708 if (!NT_STATUS_IS_OK(status)) {
1709 reply_nterror(req, status);
1710 goto out;
1713 status = filename_convert(ctx,
1714 conn,
1715 req->flags2 & FLAGS2_DFS_PATHNAMES,
1716 fname,
1718 NULL,
1719 &smb_fname);
1720 if (!NT_STATUS_IS_OK(status)) {
1721 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1722 reply_botherror(req,
1723 NT_STATUS_PATH_NOT_COVERED,
1724 ERRSRV, ERRbadpath);
1725 goto out;
1727 reply_nterror(req, status);
1728 goto out;
1731 if (!map_open_params_to_ntcreate(smb_fname, deny_mode,
1732 OPENX_FILE_EXISTS_OPEN, &access_mask,
1733 &share_mode, &create_disposition,
1734 &create_options, &private_flags)) {
1735 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1736 goto out;
1739 status = SMB_VFS_CREATE_FILE(
1740 conn, /* conn */
1741 req, /* req */
1742 0, /* root_dir_fid */
1743 smb_fname, /* fname */
1744 access_mask, /* access_mask */
1745 share_mode, /* share_access */
1746 create_disposition, /* create_disposition*/
1747 create_options, /* create_options */
1748 dos_attr, /* file_attributes */
1749 oplock_request, /* oplock_request */
1750 0, /* allocation_size */
1751 private_flags,
1752 NULL, /* sd */
1753 NULL, /* ea_list */
1754 &fsp, /* result */
1755 &info); /* pinfo */
1757 if (!NT_STATUS_IS_OK(status)) {
1758 if (open_was_deferred(req->mid)) {
1759 /* We have re-scheduled this call. */
1760 goto out;
1762 reply_openerror(req, status);
1763 goto out;
1766 size = smb_fname->st.st_ex_size;
1767 fattr = dos_mode(conn, smb_fname);
1769 /* Deal with other possible opens having a modified
1770 write time. JRA. */
1771 if (ask_sharemode) {
1772 struct timespec write_time_ts;
1774 ZERO_STRUCT(write_time_ts);
1775 get_file_infos(fsp->file_id, NULL, &write_time_ts);
1776 if (!null_timespec(write_time_ts)) {
1777 update_stat_ex_mtime(&smb_fname->st, write_time_ts);
1781 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1783 if (fattr & aDIR) {
1784 DEBUG(3,("attempt to open a directory %s\n",
1785 fsp_str_dbg(fsp)));
1786 close_file(req, fsp, ERROR_CLOSE);
1787 reply_botherror(req, NT_STATUS_ACCESS_DENIED,
1788 ERRDOS, ERRnoaccess);
1789 goto out;
1792 reply_outbuf(req, 7, 0);
1793 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
1794 SSVAL(req->outbuf,smb_vwv1,fattr);
1795 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1796 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
1797 } else {
1798 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
1800 SIVAL(req->outbuf,smb_vwv4,(uint32)size);
1801 SSVAL(req->outbuf,smb_vwv6,deny_mode);
1803 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1804 SCVAL(req->outbuf,smb_flg,
1805 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1808 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1809 SCVAL(req->outbuf,smb_flg,
1810 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1812 out:
1813 TALLOC_FREE(smb_fname);
1814 END_PROFILE(SMBopen);
1815 return;
1818 /****************************************************************************
1819 Reply to an open and X.
1820 ****************************************************************************/
1822 void reply_open_and_X(struct smb_request *req)
1824 connection_struct *conn = req->conn;
1825 struct smb_filename *smb_fname = NULL;
1826 char *fname = NULL;
1827 uint16 open_flags;
1828 int deny_mode;
1829 uint32 smb_attr;
1830 /* Breakout the oplock request bits so we can set the
1831 reply bits separately. */
1832 int ex_oplock_request;
1833 int core_oplock_request;
1834 int oplock_request;
1835 #if 0
1836 int smb_sattr = SVAL(req->vwv+4, 0);
1837 uint32 smb_time = make_unix_date3(req->vwv+6);
1838 #endif
1839 int smb_ofun;
1840 uint32 fattr=0;
1841 int mtime=0;
1842 int smb_action = 0;
1843 files_struct *fsp;
1844 NTSTATUS status;
1845 uint64_t allocation_size;
1846 ssize_t retval = -1;
1847 uint32 access_mask;
1848 uint32 share_mode;
1849 uint32 create_disposition;
1850 uint32 create_options = 0;
1851 uint32_t private_flags = 0;
1852 TALLOC_CTX *ctx = talloc_tos();
1854 START_PROFILE(SMBopenX);
1856 if (req->wct < 15) {
1857 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1858 goto out;
1861 open_flags = SVAL(req->vwv+2, 0);
1862 deny_mode = SVAL(req->vwv+3, 0);
1863 smb_attr = SVAL(req->vwv+5, 0);
1864 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
1865 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1866 oplock_request = ex_oplock_request | core_oplock_request;
1867 smb_ofun = SVAL(req->vwv+8, 0);
1868 allocation_size = (uint64_t)IVAL(req->vwv+9, 0);
1870 /* If it's an IPC, pass off the pipe handler. */
1871 if (IS_IPC(conn)) {
1872 if (lp_nt_pipe_support()) {
1873 reply_open_pipe_and_X(conn, req);
1874 } else {
1875 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
1877 goto out;
1880 /* XXXX we need to handle passed times, sattr and flags */
1881 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf,
1882 STR_TERMINATE, &status);
1883 if (!NT_STATUS_IS_OK(status)) {
1884 reply_nterror(req, status);
1885 goto out;
1888 status = filename_convert(ctx,
1889 conn,
1890 req->flags2 & FLAGS2_DFS_PATHNAMES,
1891 fname,
1893 NULL,
1894 &smb_fname);
1895 if (!NT_STATUS_IS_OK(status)) {
1896 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1897 reply_botherror(req,
1898 NT_STATUS_PATH_NOT_COVERED,
1899 ERRSRV, ERRbadpath);
1900 goto out;
1902 reply_nterror(req, status);
1903 goto out;
1906 if (!map_open_params_to_ntcreate(smb_fname, deny_mode, smb_ofun,
1907 &access_mask, &share_mode,
1908 &create_disposition,
1909 &create_options,
1910 &private_flags)) {
1911 reply_force_doserror(req, ERRDOS, ERRbadaccess);
1912 goto out;
1915 status = SMB_VFS_CREATE_FILE(
1916 conn, /* conn */
1917 req, /* req */
1918 0, /* root_dir_fid */
1919 smb_fname, /* fname */
1920 access_mask, /* access_mask */
1921 share_mode, /* share_access */
1922 create_disposition, /* create_disposition*/
1923 create_options, /* create_options */
1924 smb_attr, /* file_attributes */
1925 oplock_request, /* oplock_request */
1926 0, /* allocation_size */
1927 private_flags,
1928 NULL, /* sd */
1929 NULL, /* ea_list */
1930 &fsp, /* result */
1931 &smb_action); /* pinfo */
1933 if (!NT_STATUS_IS_OK(status)) {
1934 if (open_was_deferred(req->mid)) {
1935 /* We have re-scheduled this call. */
1936 goto out;
1938 reply_openerror(req, status);
1939 goto out;
1942 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
1943 if the file is truncated or created. */
1944 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
1945 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
1946 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
1947 close_file(req, fsp, ERROR_CLOSE);
1948 reply_nterror(req, NT_STATUS_DISK_FULL);
1949 goto out;
1951 retval = vfs_set_filelen(fsp, (SMB_OFF_T)allocation_size);
1952 if (retval < 0) {
1953 close_file(req, fsp, ERROR_CLOSE);
1954 reply_nterror(req, NT_STATUS_DISK_FULL);
1955 goto out;
1957 smb_fname->st.st_ex_size =
1958 SMB_VFS_GET_ALLOC_SIZE(conn, fsp, &smb_fname->st);
1961 fattr = dos_mode(conn, smb_fname);
1962 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1963 if (fattr & aDIR) {
1964 close_file(req, fsp, ERROR_CLOSE);
1965 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1966 goto out;
1969 /* If the caller set the extended oplock request bit
1970 and we granted one (by whatever means) - set the
1971 correct bit for extended oplock reply.
1974 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
1975 smb_action |= EXTENDED_OPLOCK_GRANTED;
1978 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1979 smb_action |= EXTENDED_OPLOCK_GRANTED;
1982 /* If the caller set the core oplock request bit
1983 and we granted one (by whatever means) - set the
1984 correct bit for core oplock reply.
1987 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
1988 reply_outbuf(req, 19, 0);
1989 } else {
1990 reply_outbuf(req, 15, 0);
1993 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
1994 SCVAL(req->outbuf, smb_flg,
1995 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1998 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1999 SCVAL(req->outbuf, smb_flg,
2000 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2003 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
2004 SSVAL(req->outbuf,smb_vwv3,fattr);
2005 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
2006 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
2007 } else {
2008 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
2010 SIVAL(req->outbuf,smb_vwv6,(uint32)smb_fname->st.st_ex_size);
2011 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
2012 SSVAL(req->outbuf,smb_vwv11,smb_action);
2014 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
2015 SIVAL(req->outbuf, smb_vwv15, SEC_STD_ALL);
2018 chain_reply(req);
2019 out:
2020 TALLOC_FREE(smb_fname);
2021 END_PROFILE(SMBopenX);
2022 return;
2025 /****************************************************************************
2026 Reply to a SMBulogoffX.
2027 ****************************************************************************/
2029 void reply_ulogoffX(struct smb_request *req)
2031 struct smbd_server_connection *sconn = req->sconn;
2032 user_struct *vuser;
2034 START_PROFILE(SMBulogoffX);
2036 vuser = get_valid_user_struct(sconn, req->vuid);
2038 if(vuser == NULL) {
2039 DEBUG(3,("ulogoff, vuser id %d does not map to user.\n",
2040 req->vuid));
2043 /* in user level security we are supposed to close any files
2044 open by this user */
2045 if ((vuser != NULL) && (lp_security() != SEC_SHARE)) {
2046 file_close_user(req->vuid);
2049 invalidate_vuid(sconn, req->vuid);
2051 reply_outbuf(req, 2, 0);
2053 DEBUG( 3, ( "ulogoffX vuid=%d\n", req->vuid ) );
2055 END_PROFILE(SMBulogoffX);
2056 req->vuid = UID_FIELD_INVALID;
2057 chain_reply(req);
2060 /****************************************************************************
2061 Reply to a mknew or a create.
2062 ****************************************************************************/
2064 void reply_mknew(struct smb_request *req)
2066 connection_struct *conn = req->conn;
2067 struct smb_filename *smb_fname = NULL;
2068 char *fname = NULL;
2069 uint32 fattr = 0;
2070 struct smb_file_time ft;
2071 files_struct *fsp;
2072 int oplock_request = 0;
2073 NTSTATUS status;
2074 uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
2075 uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
2076 uint32 create_disposition;
2077 uint32 create_options = 0;
2078 TALLOC_CTX *ctx = talloc_tos();
2080 START_PROFILE(SMBcreate);
2081 ZERO_STRUCT(ft);
2083 if (req->wct < 3) {
2084 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2085 goto out;
2088 fattr = SVAL(req->vwv+0, 0);
2089 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2091 /* mtime. */
2092 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
2094 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
2095 STR_TERMINATE, &status);
2096 if (!NT_STATUS_IS_OK(status)) {
2097 reply_nterror(req, status);
2098 goto out;
2101 status = filename_convert(ctx,
2102 conn,
2103 req->flags2 & FLAGS2_DFS_PATHNAMES,
2104 fname,
2106 NULL,
2107 &smb_fname);
2108 if (!NT_STATUS_IS_OK(status)) {
2109 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2110 reply_botherror(req,
2111 NT_STATUS_PATH_NOT_COVERED,
2112 ERRSRV, ERRbadpath);
2113 goto out;
2115 reply_nterror(req, status);
2116 goto out;
2119 if (fattr & aVOLID) {
2120 DEBUG(0,("Attempt to create file (%s) with volid set - "
2121 "please report this\n",
2122 smb_fname_str_dbg(smb_fname)));
2125 if(req->cmd == SMBmknew) {
2126 /* We should fail if file exists. */
2127 create_disposition = FILE_CREATE;
2128 } else {
2129 /* Create if file doesn't exist, truncate if it does. */
2130 create_disposition = FILE_OVERWRITE_IF;
2133 status = SMB_VFS_CREATE_FILE(
2134 conn, /* conn */
2135 req, /* req */
2136 0, /* root_dir_fid */
2137 smb_fname, /* fname */
2138 access_mask, /* access_mask */
2139 share_mode, /* share_access */
2140 create_disposition, /* create_disposition*/
2141 create_options, /* create_options */
2142 fattr, /* file_attributes */
2143 oplock_request, /* oplock_request */
2144 0, /* allocation_size */
2145 0, /* private_flags */
2146 NULL, /* sd */
2147 NULL, /* ea_list */
2148 &fsp, /* result */
2149 NULL); /* pinfo */
2151 if (!NT_STATUS_IS_OK(status)) {
2152 if (open_was_deferred(req->mid)) {
2153 /* We have re-scheduled this call. */
2154 goto out;
2156 reply_openerror(req, status);
2157 goto out;
2160 ft.atime = smb_fname->st.st_ex_atime; /* atime. */
2161 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
2162 if (!NT_STATUS_IS_OK(status)) {
2163 END_PROFILE(SMBcreate);
2164 goto out;
2167 reply_outbuf(req, 1, 0);
2168 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2170 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2171 SCVAL(req->outbuf,smb_flg,
2172 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2175 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2176 SCVAL(req->outbuf,smb_flg,
2177 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2180 DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname)));
2181 DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n",
2182 smb_fname_str_dbg(smb_fname), fsp->fh->fd,
2183 (unsigned int)fattr));
2185 out:
2186 TALLOC_FREE(smb_fname);
2187 END_PROFILE(SMBcreate);
2188 return;
2191 /****************************************************************************
2192 Reply to a create temporary file.
2193 ****************************************************************************/
2195 void reply_ctemp(struct smb_request *req)
2197 connection_struct *conn = req->conn;
2198 struct smb_filename *smb_fname = NULL;
2199 char *fname = NULL;
2200 uint32 fattr;
2201 files_struct *fsp;
2202 int oplock_request;
2203 int tmpfd;
2204 char *s;
2205 NTSTATUS status;
2206 TALLOC_CTX *ctx = talloc_tos();
2208 START_PROFILE(SMBctemp);
2210 if (req->wct < 3) {
2211 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2212 goto out;
2215 fattr = SVAL(req->vwv+0, 0);
2216 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2218 srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
2219 STR_TERMINATE, &status);
2220 if (!NT_STATUS_IS_OK(status)) {
2221 reply_nterror(req, status);
2222 goto out;
2224 if (*fname) {
2225 fname = talloc_asprintf(ctx,
2226 "%s/TMXXXXXX",
2227 fname);
2228 } else {
2229 fname = talloc_strdup(ctx, "TMXXXXXX");
2232 if (!fname) {
2233 reply_nterror(req, NT_STATUS_NO_MEMORY);
2234 goto out;
2237 status = filename_convert(ctx, conn,
2238 req->flags2 & FLAGS2_DFS_PATHNAMES,
2239 fname,
2241 NULL,
2242 &smb_fname);
2243 if (!NT_STATUS_IS_OK(status)) {
2244 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2245 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2246 ERRSRV, ERRbadpath);
2247 goto out;
2249 reply_nterror(req, status);
2250 goto out;
2253 tmpfd = mkstemp(smb_fname->base_name);
2254 if (tmpfd == -1) {
2255 reply_nterror(req, map_nt_error_from_unix(errno));
2256 goto out;
2259 SMB_VFS_STAT(conn, smb_fname);
2261 /* We should fail if file does not exist. */
2262 status = SMB_VFS_CREATE_FILE(
2263 conn, /* conn */
2264 req, /* req */
2265 0, /* root_dir_fid */
2266 smb_fname, /* fname */
2267 FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
2268 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2269 FILE_OPEN, /* create_disposition*/
2270 0, /* create_options */
2271 fattr, /* file_attributes */
2272 oplock_request, /* oplock_request */
2273 0, /* allocation_size */
2274 0, /* private_flags */
2275 NULL, /* sd */
2276 NULL, /* ea_list */
2277 &fsp, /* result */
2278 NULL); /* pinfo */
2280 /* close fd from mkstemp() */
2281 close(tmpfd);
2283 if (!NT_STATUS_IS_OK(status)) {
2284 if (open_was_deferred(req->mid)) {
2285 /* We have re-scheduled this call. */
2286 goto out;
2288 reply_openerror(req, status);
2289 goto out;
2292 reply_outbuf(req, 1, 0);
2293 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2295 /* the returned filename is relative to the directory */
2296 s = strrchr_m(fsp->fsp_name->base_name, '/');
2297 if (!s) {
2298 s = fsp->fsp_name->base_name;
2299 } else {
2300 s++;
2303 #if 0
2304 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2305 thing in the byte section. JRA */
2306 SSVALS(p, 0, -1); /* what is this? not in spec */
2307 #endif
2308 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2309 == -1) {
2310 reply_nterror(req, NT_STATUS_NO_MEMORY);
2311 goto out;
2314 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2315 SCVAL(req->outbuf, smb_flg,
2316 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2319 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2320 SCVAL(req->outbuf, smb_flg,
2321 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2324 DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp)));
2325 DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp),
2326 fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
2327 out:
2328 TALLOC_FREE(smb_fname);
2329 END_PROFILE(SMBctemp);
2330 return;
2333 /*******************************************************************
2334 Check if a user is allowed to rename a file.
2335 ********************************************************************/
2337 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2338 uint16 dirtype)
2340 uint32 fmode;
2342 if (!CAN_WRITE(conn)) {
2343 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2346 fmode = dos_mode(conn, fsp->fsp_name);
2347 if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM)) {
2348 return NT_STATUS_NO_SUCH_FILE;
2351 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
2352 if (fsp->posix_open) {
2353 return NT_STATUS_OK;
2356 /* If no pathnames are open below this
2357 directory, allow the rename. */
2359 if (file_find_subpath(fsp)) {
2360 return NT_STATUS_ACCESS_DENIED;
2362 return NT_STATUS_OK;
2365 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2366 return NT_STATUS_OK;
2369 return NT_STATUS_ACCESS_DENIED;
2372 /*******************************************************************
2373 * unlink a file with all relevant access checks
2374 *******************************************************************/
2376 static NTSTATUS do_unlink(connection_struct *conn,
2377 struct smb_request *req,
2378 struct smb_filename *smb_fname,
2379 uint32 dirtype)
2381 uint32 fattr;
2382 files_struct *fsp;
2383 uint32 dirtype_orig = dirtype;
2384 NTSTATUS status;
2385 int ret;
2386 bool posix_paths = lp_posix_pathnames();
2388 DEBUG(10,("do_unlink: %s, dirtype = %d\n",
2389 smb_fname_str_dbg(smb_fname),
2390 dirtype));
2392 if (!CAN_WRITE(conn)) {
2393 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2396 if (posix_paths) {
2397 ret = SMB_VFS_LSTAT(conn, smb_fname);
2398 } else {
2399 ret = SMB_VFS_STAT(conn, smb_fname);
2401 if (ret != 0) {
2402 return map_nt_error_from_unix(errno);
2405 fattr = dos_mode(conn, smb_fname);
2407 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2408 dirtype = aDIR|aARCH|aRONLY;
2411 dirtype &= (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM);
2412 if (!dirtype) {
2413 return NT_STATUS_NO_SUCH_FILE;
2416 if (!dir_check_ftype(conn, fattr, dirtype)) {
2417 if (fattr & aDIR) {
2418 return NT_STATUS_FILE_IS_A_DIRECTORY;
2420 return NT_STATUS_NO_SUCH_FILE;
2423 if (dirtype_orig & 0x8000) {
2424 /* These will never be set for POSIX. */
2425 return NT_STATUS_NO_SUCH_FILE;
2428 #if 0
2429 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2430 return NT_STATUS_FILE_IS_A_DIRECTORY;
2433 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2434 return NT_STATUS_NO_SUCH_FILE;
2437 if (dirtype & 0xFF00) {
2438 /* These will never be set for POSIX. */
2439 return NT_STATUS_NO_SUCH_FILE;
2442 dirtype &= 0xFF;
2443 if (!dirtype) {
2444 return NT_STATUS_NO_SUCH_FILE;
2447 /* Can't delete a directory. */
2448 if (fattr & aDIR) {
2449 return NT_STATUS_FILE_IS_A_DIRECTORY;
2451 #endif
2453 #if 0 /* JRATEST */
2454 else if (dirtype & aDIR) /* Asked for a directory and it isn't. */
2455 return NT_STATUS_OBJECT_NAME_INVALID;
2456 #endif /* JRATEST */
2458 /* On open checks the open itself will check the share mode, so
2459 don't do it here as we'll get it wrong. */
2461 status = SMB_VFS_CREATE_FILE
2462 (conn, /* conn */
2463 req, /* req */
2464 0, /* root_dir_fid */
2465 smb_fname, /* fname */
2466 DELETE_ACCESS, /* access_mask */
2467 FILE_SHARE_NONE, /* share_access */
2468 FILE_OPEN, /* create_disposition*/
2469 FILE_NON_DIRECTORY_FILE, /* create_options */
2470 /* file_attributes */
2471 posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
2472 FILE_ATTRIBUTE_NORMAL,
2473 0, /* oplock_request */
2474 0, /* allocation_size */
2475 0, /* private_flags */
2476 NULL, /* sd */
2477 NULL, /* ea_list */
2478 &fsp, /* result */
2479 NULL); /* pinfo */
2481 if (!NT_STATUS_IS_OK(status)) {
2482 DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
2483 nt_errstr(status)));
2484 return status;
2487 status = can_set_delete_on_close(fsp, fattr);
2488 if (!NT_STATUS_IS_OK(status)) {
2489 DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
2490 "(%s)\n",
2491 smb_fname_str_dbg(smb_fname),
2492 nt_errstr(status)));
2493 close_file(req, fsp, NORMAL_CLOSE);
2494 return status;
2497 /* The set is across all open files on this dev/inode pair. */
2498 if (!set_delete_on_close(fsp, True, &conn->server_info->utok)) {
2499 close_file(req, fsp, NORMAL_CLOSE);
2500 return NT_STATUS_ACCESS_DENIED;
2503 return close_file(req, fsp, NORMAL_CLOSE);
2506 /****************************************************************************
2507 The guts of the unlink command, split out so it may be called by the NT SMB
2508 code.
2509 ****************************************************************************/
2511 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2512 uint32 dirtype, struct smb_filename *smb_fname,
2513 bool has_wild)
2515 char *fname_dir = NULL;
2516 char *fname_mask = NULL;
2517 int count=0;
2518 NTSTATUS status = NT_STATUS_OK;
2519 TALLOC_CTX *ctx = talloc_tos();
2521 /* Split up the directory from the filename/mask. */
2522 status = split_fname_dir_mask(ctx, smb_fname->base_name,
2523 &fname_dir, &fname_mask);
2524 if (!NT_STATUS_IS_OK(status)) {
2525 goto out;
2529 * We should only check the mangled cache
2530 * here if unix_convert failed. This means
2531 * that the path in 'mask' doesn't exist
2532 * on the file system and so we need to look
2533 * for a possible mangle. This patch from
2534 * Tine Smukavec <valentin.smukavec@hermes.si>.
2537 if (!VALID_STAT(smb_fname->st) &&
2538 mangle_is_mangled(fname_mask, conn->params)) {
2539 char *new_mask = NULL;
2540 mangle_lookup_name_from_8_3(ctx, fname_mask,
2541 &new_mask, conn->params);
2542 if (new_mask) {
2543 TALLOC_FREE(fname_mask);
2544 fname_mask = new_mask;
2548 if (!has_wild) {
2551 * Only one file needs to be unlinked. Append the mask back
2552 * onto the directory.
2554 TALLOC_FREE(smb_fname->base_name);
2555 smb_fname->base_name = talloc_asprintf(smb_fname,
2556 "%s/%s",
2557 fname_dir,
2558 fname_mask);
2559 if (!smb_fname->base_name) {
2560 status = NT_STATUS_NO_MEMORY;
2561 goto out;
2563 if (dirtype == 0) {
2564 dirtype = FILE_ATTRIBUTE_NORMAL;
2567 status = check_name(conn, smb_fname->base_name);
2568 if (!NT_STATUS_IS_OK(status)) {
2569 goto out;
2572 status = do_unlink(conn, req, smb_fname, dirtype);
2573 if (!NT_STATUS_IS_OK(status)) {
2574 goto out;
2577 count++;
2578 } else {
2579 struct smb_Dir *dir_hnd = NULL;
2580 long offset = 0;
2581 const char *dname = NULL;
2582 char *talloced = NULL;
2584 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == aDIR) {
2585 status = NT_STATUS_OBJECT_NAME_INVALID;
2586 goto out;
2589 if (strequal(fname_mask,"????????.???")) {
2590 TALLOC_FREE(fname_mask);
2591 fname_mask = talloc_strdup(ctx, "*");
2592 if (!fname_mask) {
2593 status = NT_STATUS_NO_MEMORY;
2594 goto out;
2598 status = check_name(conn, fname_dir);
2599 if (!NT_STATUS_IS_OK(status)) {
2600 goto out;
2603 dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask,
2604 dirtype);
2605 if (dir_hnd == NULL) {
2606 status = map_nt_error_from_unix(errno);
2607 goto out;
2610 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2611 the pattern matches against the long name, otherwise the short name
2612 We don't implement this yet XXXX
2615 status = NT_STATUS_NO_SUCH_FILE;
2617 while ((dname = ReadDirName(dir_hnd, &offset,
2618 &smb_fname->st, &talloced))) {
2619 TALLOC_CTX *frame = talloc_stackframe();
2621 if (!is_visible_file(conn, fname_dir, dname,
2622 &smb_fname->st, true)) {
2623 TALLOC_FREE(frame);
2624 TALLOC_FREE(talloced);
2625 continue;
2628 /* Quick check for "." and ".." */
2629 if (ISDOT(dname) || ISDOTDOT(dname)) {
2630 TALLOC_FREE(frame);
2631 TALLOC_FREE(talloced);
2632 continue;
2635 if(!mask_match(dname, fname_mask,
2636 conn->case_sensitive)) {
2637 TALLOC_FREE(frame);
2638 TALLOC_FREE(talloced);
2639 continue;
2642 TALLOC_FREE(smb_fname->base_name);
2643 smb_fname->base_name =
2644 talloc_asprintf(smb_fname, "%s/%s",
2645 fname_dir, dname);
2647 if (!smb_fname->base_name) {
2648 TALLOC_FREE(dir_hnd);
2649 status = NT_STATUS_NO_MEMORY;
2650 TALLOC_FREE(frame);
2651 TALLOC_FREE(talloced);
2652 goto out;
2655 status = check_name(conn, smb_fname->base_name);
2656 if (!NT_STATUS_IS_OK(status)) {
2657 TALLOC_FREE(dir_hnd);
2658 TALLOC_FREE(frame);
2659 TALLOC_FREE(talloced);
2660 goto out;
2663 status = do_unlink(conn, req, smb_fname, dirtype);
2664 if (!NT_STATUS_IS_OK(status)) {
2665 TALLOC_FREE(frame);
2666 TALLOC_FREE(talloced);
2667 continue;
2670 count++;
2671 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
2672 smb_fname->base_name));
2674 TALLOC_FREE(frame);
2675 TALLOC_FREE(talloced);
2677 TALLOC_FREE(dir_hnd);
2680 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
2681 status = map_nt_error_from_unix(errno);
2684 out:
2685 TALLOC_FREE(fname_dir);
2686 TALLOC_FREE(fname_mask);
2687 return status;
2690 /****************************************************************************
2691 Reply to a unlink
2692 ****************************************************************************/
2694 void reply_unlink(struct smb_request *req)
2696 connection_struct *conn = req->conn;
2697 char *name = NULL;
2698 struct smb_filename *smb_fname = NULL;
2699 uint32 dirtype;
2700 NTSTATUS status;
2701 bool path_contains_wcard = False;
2702 TALLOC_CTX *ctx = talloc_tos();
2704 START_PROFILE(SMBunlink);
2706 if (req->wct < 1) {
2707 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2708 goto out;
2711 dirtype = SVAL(req->vwv+0, 0);
2713 srvstr_get_path_req_wcard(ctx, req, &name, (const char *)req->buf + 1,
2714 STR_TERMINATE, &status,
2715 &path_contains_wcard);
2716 if (!NT_STATUS_IS_OK(status)) {
2717 reply_nterror(req, status);
2718 goto out;
2721 status = filename_convert(ctx, conn,
2722 req->flags2 & FLAGS2_DFS_PATHNAMES,
2723 name,
2724 UCF_COND_ALLOW_WCARD_LCOMP,
2725 &path_contains_wcard,
2726 &smb_fname);
2727 if (!NT_STATUS_IS_OK(status)) {
2728 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2729 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2730 ERRSRV, ERRbadpath);
2731 goto out;
2733 reply_nterror(req, status);
2734 goto out;
2737 DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname)));
2739 status = unlink_internals(conn, req, dirtype, smb_fname,
2740 path_contains_wcard);
2741 if (!NT_STATUS_IS_OK(status)) {
2742 if (open_was_deferred(req->mid)) {
2743 /* We have re-scheduled this call. */
2744 goto out;
2746 reply_nterror(req, status);
2747 goto out;
2750 reply_outbuf(req, 0, 0);
2751 out:
2752 TALLOC_FREE(smb_fname);
2753 END_PROFILE(SMBunlink);
2754 return;
2757 /****************************************************************************
2758 Fail for readbraw.
2759 ****************************************************************************/
2761 static void fail_readraw(void)
2763 const char *errstr = talloc_asprintf(talloc_tos(),
2764 "FAIL ! reply_readbraw: socket write fail (%s)",
2765 strerror(errno));
2766 if (!errstr) {
2767 errstr = "";
2769 exit_server_cleanly(errstr);
2772 /****************************************************************************
2773 Fake (read/write) sendfile. Returns -1 on read or write fail.
2774 ****************************************************************************/
2776 static ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos,
2777 size_t nread)
2779 size_t bufsize;
2780 size_t tosend = nread;
2781 char *buf;
2783 if (nread == 0) {
2784 return 0;
2787 bufsize = MIN(nread, 65536);
2789 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
2790 return -1;
2793 while (tosend > 0) {
2794 ssize_t ret;
2795 size_t cur_read;
2797 if (tosend > bufsize) {
2798 cur_read = bufsize;
2799 } else {
2800 cur_read = tosend;
2802 ret = read_file(fsp,buf,startpos,cur_read);
2803 if (ret == -1) {
2804 SAFE_FREE(buf);
2805 return -1;
2808 /* If we had a short read, fill with zeros. */
2809 if (ret < cur_read) {
2810 memset(buf + ret, '\0', cur_read - ret);
2813 if (write_data(smbd_server_fd(),buf,cur_read) != cur_read) {
2814 SAFE_FREE(buf);
2815 return -1;
2817 tosend -= cur_read;
2818 startpos += cur_read;
2821 SAFE_FREE(buf);
2822 return (ssize_t)nread;
2825 #if defined(WITH_SENDFILE)
2826 /****************************************************************************
2827 Deal with the case of sendfile reading less bytes from the file than
2828 requested. Fill with zeros (all we can do).
2829 ****************************************************************************/
2831 static void sendfile_short_send(files_struct *fsp,
2832 ssize_t nread,
2833 size_t headersize,
2834 size_t smb_maxcnt)
2836 #define SHORT_SEND_BUFSIZE 1024
2837 if (nread < headersize) {
2838 DEBUG(0,("sendfile_short_send: sendfile failed to send "
2839 "header for file %s (%s). Terminating\n",
2840 fsp_str_dbg(fsp), strerror(errno)));
2841 exit_server_cleanly("sendfile_short_send failed");
2844 nread -= headersize;
2846 if (nread < smb_maxcnt) {
2847 char *buf = SMB_CALLOC_ARRAY(char, SHORT_SEND_BUFSIZE);
2848 if (!buf) {
2849 exit_server_cleanly("sendfile_short_send: "
2850 "malloc failed");
2853 DEBUG(0,("sendfile_short_send: filling truncated file %s "
2854 "with zeros !\n", fsp_str_dbg(fsp)));
2856 while (nread < smb_maxcnt) {
2858 * We asked for the real file size and told sendfile
2859 * to not go beyond the end of the file. But it can
2860 * happen that in between our fstat call and the
2861 * sendfile call the file was truncated. This is very
2862 * bad because we have already announced the larger
2863 * number of bytes to the client.
2865 * The best we can do now is to send 0-bytes, just as
2866 * a read from a hole in a sparse file would do.
2868 * This should happen rarely enough that I don't care
2869 * about efficiency here :-)
2871 size_t to_write;
2873 to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
2874 if (write_data(smbd_server_fd(), buf, to_write) != to_write) {
2875 exit_server_cleanly("sendfile_short_send: "
2876 "write_data failed");
2878 nread += to_write;
2880 SAFE_FREE(buf);
2883 #endif /* defined WITH_SENDFILE */
2885 /****************************************************************************
2886 Return a readbraw error (4 bytes of zero).
2887 ****************************************************************************/
2889 static void reply_readbraw_error(struct smbd_server_connection *sconn)
2891 char header[4];
2893 SIVAL(header,0,0);
2895 smbd_lock_socket(sconn);
2896 if (write_data(smbd_server_fd(),header,4) != 4) {
2897 fail_readraw();
2899 smbd_unlock_socket(sconn);
2902 /****************************************************************************
2903 Use sendfile in readbraw.
2904 ****************************************************************************/
2906 static void send_file_readbraw(connection_struct *conn,
2907 struct smb_request *req,
2908 files_struct *fsp,
2909 SMB_OFF_T startpos,
2910 size_t nread,
2911 ssize_t mincount)
2913 struct smbd_server_connection *sconn = req->sconn;
2914 char *outbuf = NULL;
2915 ssize_t ret=0;
2917 #if defined(WITH_SENDFILE)
2919 * We can only use sendfile on a non-chained packet
2920 * but we can use on a non-oplocked file. tridge proved this
2921 * on a train in Germany :-). JRA.
2922 * reply_readbraw has already checked the length.
2925 if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
2926 (fsp->wcp == NULL) &&
2927 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
2928 ssize_t sendfile_read = -1;
2929 char header[4];
2930 DATA_BLOB header_blob;
2932 _smb_setlen(header,nread);
2933 header_blob = data_blob_const(header, 4);
2935 if ((sendfile_read = SMB_VFS_SENDFILE(smbd_server_fd(), fsp,
2936 &header_blob, startpos, nread)) == -1) {
2937 /* Returning ENOSYS means no data at all was sent.
2938 * Do this as a normal read. */
2939 if (errno == ENOSYS) {
2940 goto normal_readbraw;
2944 * Special hack for broken Linux with no working sendfile. If we
2945 * return EINTR we sent the header but not the rest of the data.
2946 * Fake this up by doing read/write calls.
2948 if (errno == EINTR) {
2949 /* Ensure we don't do this again. */
2950 set_use_sendfile(SNUM(conn), False);
2951 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
2953 if (fake_sendfile(fsp, startpos, nread) == -1) {
2954 DEBUG(0,("send_file_readbraw: "
2955 "fake_sendfile failed for "
2956 "file %s (%s).\n",
2957 fsp_str_dbg(fsp),
2958 strerror(errno)));
2959 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
2961 return;
2964 DEBUG(0,("send_file_readbraw: sendfile failed for "
2965 "file %s (%s). Terminating\n",
2966 fsp_str_dbg(fsp), strerror(errno)));
2967 exit_server_cleanly("send_file_readbraw sendfile failed");
2968 } else if (sendfile_read == 0) {
2970 * Some sendfile implementations return 0 to indicate
2971 * that there was a short read, but nothing was
2972 * actually written to the socket. In this case,
2973 * fallback to the normal read path so the header gets
2974 * the correct byte count.
2976 DEBUG(3, ("send_file_readbraw: sendfile sent zero "
2977 "bytes falling back to the normal read: "
2978 "%s\n", fsp_str_dbg(fsp)));
2979 goto normal_readbraw;
2982 /* Deal with possible short send. */
2983 if (sendfile_read != 4+nread) {
2984 sendfile_short_send(fsp, sendfile_read, 4, nread);
2986 return;
2989 normal_readbraw:
2990 #endif
2992 outbuf = TALLOC_ARRAY(NULL, char, nread+4);
2993 if (!outbuf) {
2994 DEBUG(0,("send_file_readbraw: TALLOC_ARRAY failed for size %u.\n",
2995 (unsigned)(nread+4)));
2996 reply_readbraw_error(sconn);
2997 return;
3000 if (nread > 0) {
3001 ret = read_file(fsp,outbuf+4,startpos,nread);
3002 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3003 if (ret < mincount)
3004 ret = 0;
3005 #else
3006 if (ret < nread)
3007 ret = 0;
3008 #endif
3011 _smb_setlen(outbuf,ret);
3012 if (write_data(smbd_server_fd(),outbuf,4+ret) != 4+ret)
3013 fail_readraw();
3015 TALLOC_FREE(outbuf);
3018 /****************************************************************************
3019 Reply to a readbraw (core+ protocol).
3020 ****************************************************************************/
3022 void reply_readbraw(struct smb_request *req)
3024 connection_struct *conn = req->conn;
3025 struct smbd_server_connection *sconn = req->sconn;
3026 ssize_t maxcount,mincount;
3027 size_t nread = 0;
3028 SMB_OFF_T startpos;
3029 files_struct *fsp;
3030 struct lock_struct lock;
3031 SMB_OFF_T size = 0;
3033 START_PROFILE(SMBreadbraw);
3035 if (srv_is_signing_active(sconn) ||
3036 is_encrypted_packet(req->inbuf)) {
3037 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
3038 "raw reads/writes are disallowed.");
3041 if (req->wct < 8) {
3042 reply_readbraw_error(sconn);
3043 END_PROFILE(SMBreadbraw);
3044 return;
3047 if (sconn->smb1.echo_handler.trusted_fde) {
3048 DEBUG(2,("SMBreadbraw rejected with NOT_SUPPORTED because of "
3049 "'async smb echo handler = yes'\n"));
3050 reply_readbraw_error(sconn);
3051 END_PROFILE(SMBreadbraw);
3052 return;
3056 * Special check if an oplock break has been issued
3057 * and the readraw request croses on the wire, we must
3058 * return a zero length response here.
3061 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3064 * We have to do a check_fsp by hand here, as
3065 * we must always return 4 zero bytes on error,
3066 * not a NTSTATUS.
3069 if (!fsp || !conn || conn != fsp->conn ||
3070 req->vuid != fsp->vuid ||
3071 fsp->is_directory || fsp->fh->fd == -1) {
3073 * fsp could be NULL here so use the value from the packet. JRA.
3075 DEBUG(3,("reply_readbraw: fnum %d not valid "
3076 "- cache prime?\n",
3077 (int)SVAL(req->vwv+0, 0)));
3078 reply_readbraw_error(sconn);
3079 END_PROFILE(SMBreadbraw);
3080 return;
3083 /* Do a "by hand" version of CHECK_READ. */
3084 if (!(fsp->can_read ||
3085 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
3086 (fsp->access_mask & FILE_EXECUTE)))) {
3087 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
3088 (int)SVAL(req->vwv+0, 0)));
3089 reply_readbraw_error(sconn);
3090 END_PROFILE(SMBreadbraw);
3091 return;
3094 flush_write_cache(fsp, READRAW_FLUSH);
3096 startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
3097 if(req->wct == 10) {
3099 * This is a large offset (64 bit) read.
3101 #ifdef LARGE_SMB_OFF_T
3103 startpos |= (((SMB_OFF_T)IVAL(req->vwv+8, 0)) << 32);
3105 #else /* !LARGE_SMB_OFF_T */
3108 * Ensure we haven't been sent a >32 bit offset.
3111 if(IVAL(req->vwv+8, 0) != 0) {
3112 DEBUG(0,("reply_readbraw: large offset "
3113 "(%x << 32) used and we don't support "
3114 "64 bit offsets.\n",
3115 (unsigned int)IVAL(req->vwv+8, 0) ));
3116 reply_readbraw_error();
3117 END_PROFILE(SMBreadbraw);
3118 return;
3121 #endif /* LARGE_SMB_OFF_T */
3123 if(startpos < 0) {
3124 DEBUG(0,("reply_readbraw: negative 64 bit "
3125 "readraw offset (%.0f) !\n",
3126 (double)startpos ));
3127 reply_readbraw_error(sconn);
3128 END_PROFILE(SMBreadbraw);
3129 return;
3133 maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
3134 mincount = (SVAL(req->vwv+4, 0) & 0xFFFF);
3136 /* ensure we don't overrun the packet size */
3137 maxcount = MIN(65535,maxcount);
3139 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3140 (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
3141 &lock);
3143 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3144 reply_readbraw_error(sconn);
3145 END_PROFILE(SMBreadbraw);
3146 return;
3149 if (fsp_stat(fsp) == 0) {
3150 size = fsp->fsp_name->st.st_ex_size;
3153 if (startpos >= size) {
3154 nread = 0;
3155 } else {
3156 nread = MIN(maxcount,(size - startpos));
3159 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
3160 if (nread < mincount)
3161 nread = 0;
3162 #endif
3164 DEBUG( 3, ( "reply_readbraw: fnum=%d start=%.0f max=%lu "
3165 "min=%lu nread=%lu\n",
3166 fsp->fnum, (double)startpos,
3167 (unsigned long)maxcount,
3168 (unsigned long)mincount,
3169 (unsigned long)nread ) );
3171 send_file_readbraw(conn, req, fsp, startpos, nread, mincount);
3173 DEBUG(5,("reply_readbraw finished\n"));
3175 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3177 END_PROFILE(SMBreadbraw);
3178 return;
3181 #undef DBGC_CLASS
3182 #define DBGC_CLASS DBGC_LOCKING
3184 /****************************************************************************
3185 Reply to a lockread (core+ protocol).
3186 ****************************************************************************/
3188 void reply_lockread(struct smb_request *req)
3190 connection_struct *conn = req->conn;
3191 ssize_t nread = -1;
3192 char *data;
3193 SMB_OFF_T startpos;
3194 size_t numtoread;
3195 NTSTATUS status;
3196 files_struct *fsp;
3197 struct byte_range_lock *br_lck = NULL;
3198 char *p = NULL;
3199 struct smbd_server_connection *sconn = req->sconn;
3201 START_PROFILE(SMBlockread);
3203 if (req->wct < 5) {
3204 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3205 END_PROFILE(SMBlockread);
3206 return;
3209 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3211 if (!check_fsp(conn, req, fsp)) {
3212 END_PROFILE(SMBlockread);
3213 return;
3216 if (!CHECK_READ(fsp,req)) {
3217 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3218 END_PROFILE(SMBlockread);
3219 return;
3222 numtoread = SVAL(req->vwv+1, 0);
3223 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3225 numtoread = MIN(BUFFER_SIZE - (smb_size + 3*2 + 3), numtoread);
3227 reply_outbuf(req, 5, numtoread + 3);
3229 data = smb_buf(req->outbuf) + 3;
3232 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
3233 * protocol request that predates the read/write lock concept.
3234 * Thus instead of asking for a read lock here we need to ask
3235 * for a write lock. JRA.
3236 * Note that the requested lock size is unaffected by max_recv.
3239 br_lck = do_lock(req->sconn->msg_ctx,
3240 fsp,
3241 (uint64_t)req->smbpid,
3242 (uint64_t)numtoread,
3243 (uint64_t)startpos,
3244 WRITE_LOCK,
3245 WINDOWS_LOCK,
3246 False, /* Non-blocking lock. */
3247 &status,
3248 NULL,
3249 NULL);
3250 TALLOC_FREE(br_lck);
3252 if (NT_STATUS_V(status)) {
3253 reply_nterror(req, status);
3254 END_PROFILE(SMBlockread);
3255 return;
3259 * However the requested READ size IS affected by max_recv. Insanity.... JRA.
3262 if (numtoread > sconn->smb1.negprot.max_recv) {
3263 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \
3264 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3265 (unsigned int)numtoread,
3266 (unsigned int)sconn->smb1.negprot.max_recv));
3267 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3269 nread = read_file(fsp,data,startpos,numtoread);
3271 if (nread < 0) {
3272 reply_nterror(req, map_nt_error_from_unix(errno));
3273 END_PROFILE(SMBlockread);
3274 return;
3277 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3279 SSVAL(req->outbuf,smb_vwv0,nread);
3280 SSVAL(req->outbuf,smb_vwv5,nread+3);
3281 p = smb_buf(req->outbuf);
3282 SCVAL(p,0,0); /* pad byte. */
3283 SSVAL(p,1,nread);
3285 DEBUG(3,("lockread fnum=%d num=%d nread=%d\n",
3286 fsp->fnum, (int)numtoread, (int)nread));
3288 END_PROFILE(SMBlockread);
3289 return;
3292 #undef DBGC_CLASS
3293 #define DBGC_CLASS DBGC_ALL
3295 /****************************************************************************
3296 Reply to a read.
3297 ****************************************************************************/
3299 void reply_read(struct smb_request *req)
3301 connection_struct *conn = req->conn;
3302 size_t numtoread;
3303 ssize_t nread = 0;
3304 char *data;
3305 SMB_OFF_T startpos;
3306 int outsize = 0;
3307 files_struct *fsp;
3308 struct lock_struct lock;
3309 struct smbd_server_connection *sconn = req->sconn;
3311 START_PROFILE(SMBread);
3313 if (req->wct < 3) {
3314 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3315 END_PROFILE(SMBread);
3316 return;
3319 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3321 if (!check_fsp(conn, req, fsp)) {
3322 END_PROFILE(SMBread);
3323 return;
3326 if (!CHECK_READ(fsp,req)) {
3327 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3328 END_PROFILE(SMBread);
3329 return;
3332 numtoread = SVAL(req->vwv+1, 0);
3333 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
3335 numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
3338 * The requested read size cannot be greater than max_recv. JRA.
3340 if (numtoread > sconn->smb1.negprot.max_recv) {
3341 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \
3342 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3343 (unsigned int)numtoread,
3344 (unsigned int)sconn->smb1.negprot.max_recv));
3345 numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv);
3348 reply_outbuf(req, 5, numtoread+3);
3350 data = smb_buf(req->outbuf) + 3;
3352 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3353 (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
3354 &lock);
3356 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3357 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3358 END_PROFILE(SMBread);
3359 return;
3362 if (numtoread > 0)
3363 nread = read_file(fsp,data,startpos,numtoread);
3365 if (nread < 0) {
3366 reply_nterror(req, map_nt_error_from_unix(errno));
3367 goto strict_unlock;
3370 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3372 SSVAL(req->outbuf,smb_vwv0,nread);
3373 SSVAL(req->outbuf,smb_vwv5,nread+3);
3374 SCVAL(smb_buf(req->outbuf),0,1);
3375 SSVAL(smb_buf(req->outbuf),1,nread);
3377 DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
3378 fsp->fnum, (int)numtoread, (int)nread ) );
3380 strict_unlock:
3381 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3383 END_PROFILE(SMBread);
3384 return;
3387 /****************************************************************************
3388 Setup readX header.
3389 ****************************************************************************/
3391 static int setup_readX_header(struct smb_request *req, char *outbuf,
3392 size_t smb_maxcnt)
3394 int outsize;
3395 char *data;
3397 outsize = srv_set_message(outbuf,12,smb_maxcnt,False);
3398 data = smb_buf(outbuf);
3400 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3402 SCVAL(outbuf,smb_vwv0,0xFF);
3403 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3404 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3405 SSVAL(outbuf,smb_vwv6,
3406 req_wct_ofs(req)
3407 + 1 /* the wct field */
3408 + 12 * sizeof(uint16_t) /* vwv */
3409 + 2); /* the buflen field */
3410 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3411 SSVAL(outbuf,smb_vwv11,smb_maxcnt);
3412 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3413 _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
3414 return outsize;
3417 /****************************************************************************
3418 Reply to a read and X - possibly using sendfile.
3419 ****************************************************************************/
3421 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3422 files_struct *fsp, SMB_OFF_T startpos,
3423 size_t smb_maxcnt)
3425 ssize_t nread = -1;
3426 struct lock_struct lock;
3427 int saved_errno = 0;
3429 if(fsp_stat(fsp) == -1) {
3430 reply_nterror(req, map_nt_error_from_unix(errno));
3431 return;
3434 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3435 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
3436 &lock);
3438 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3439 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3440 return;
3443 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
3444 (startpos > fsp->fsp_name->st.st_ex_size)
3445 || (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
3447 * We already know that we would do a short read, so don't
3448 * try the sendfile() path.
3450 goto nosendfile_read;
3453 #if defined(WITH_SENDFILE)
3455 * We can only use sendfile on a non-chained packet
3456 * but we can use on a non-oplocked file. tridge proved this
3457 * on a train in Germany :-). JRA.
3460 if (!req_is_in_chain(req) &&
3461 !is_encrypted_packet(req->inbuf) && (fsp->base_fsp == NULL) &&
3462 (fsp->wcp == NULL) &&
3463 lp_use_sendfile(SNUM(conn), req->sconn->smb1.signing_state) ) {
3464 uint8 headerbuf[smb_size + 12 * 2];
3465 DATA_BLOB header;
3468 * Set up the packet header before send. We
3469 * assume here the sendfile will work (get the
3470 * correct amount of data).
3473 header = data_blob_const(headerbuf, sizeof(headerbuf));
3475 construct_reply_common_req(req, (char *)headerbuf);
3476 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3478 if ((nread = SMB_VFS_SENDFILE(smbd_server_fd(), fsp, &header, startpos, smb_maxcnt)) == -1) {
3479 /* Returning ENOSYS means no data at all was sent.
3480 Do this as a normal read. */
3481 if (errno == ENOSYS) {
3482 goto normal_read;
3486 * Special hack for broken Linux with no working sendfile. If we
3487 * return EINTR we sent the header but not the rest of the data.
3488 * Fake this up by doing read/write calls.
3491 if (errno == EINTR) {
3492 /* Ensure we don't do this again. */
3493 set_use_sendfile(SNUM(conn), False);
3494 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3495 nread = fake_sendfile(fsp, startpos,
3496 smb_maxcnt);
3497 if (nread == -1) {
3498 DEBUG(0,("send_file_readX: "
3499 "fake_sendfile failed for "
3500 "file %s (%s).\n",
3501 fsp_str_dbg(fsp),
3502 strerror(errno)));
3503 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3505 DEBUG( 3, ( "send_file_readX: fake_sendfile fnum=%d max=%d nread=%d\n",
3506 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3507 /* No outbuf here means successful sendfile. */
3508 goto strict_unlock;
3511 DEBUG(0,("send_file_readX: sendfile failed for file "
3512 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3513 strerror(errno)));
3514 exit_server_cleanly("send_file_readX sendfile failed");
3515 } else if (nread == 0) {
3517 * Some sendfile implementations return 0 to indicate
3518 * that there was a short read, but nothing was
3519 * actually written to the socket. In this case,
3520 * fallback to the normal read path so the header gets
3521 * the correct byte count.
3523 DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
3524 "falling back to the normal read: %s\n",
3525 fsp_str_dbg(fsp)));
3526 goto normal_read;
3529 DEBUG( 3, ( "send_file_readX: sendfile fnum=%d max=%d nread=%d\n",
3530 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3532 /* Deal with possible short send. */
3533 if (nread != smb_maxcnt + sizeof(headerbuf)) {
3534 sendfile_short_send(fsp, nread, sizeof(headerbuf), smb_maxcnt);
3536 /* No outbuf here means successful sendfile. */
3537 SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
3538 SMB_PERFCOUNT_END(&req->pcd);
3539 goto strict_unlock;
3542 normal_read:
3544 #endif
3546 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3547 uint8 headerbuf[smb_size + 2*12];
3549 construct_reply_common_req(req, (char *)headerbuf);
3550 setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
3552 /* Send out the header. */
3553 if (write_data(smbd_server_fd(), (char *)headerbuf,
3554 sizeof(headerbuf)) != sizeof(headerbuf)) {
3555 DEBUG(0,("send_file_readX: write_data failed for file "
3556 "%s (%s). Terminating\n", fsp_str_dbg(fsp),
3557 strerror(errno)));
3558 exit_server_cleanly("send_file_readX sendfile failed");
3560 nread = fake_sendfile(fsp, startpos, smb_maxcnt);
3561 if (nread == -1) {
3562 DEBUG(0,("send_file_readX: fake_sendfile failed for "
3563 "file %s (%s).\n", fsp_str_dbg(fsp),
3564 strerror(errno)));
3565 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3567 goto strict_unlock;
3570 nosendfile_read:
3572 reply_outbuf(req, 12, smb_maxcnt);
3574 nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt);
3575 saved_errno = errno;
3577 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3579 if (nread < 0) {
3580 reply_nterror(req, map_nt_error_from_unix(saved_errno));
3581 return;
3584 setup_readX_header(req, (char *)req->outbuf, nread);
3586 DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
3587 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3589 chain_reply(req);
3590 return;
3592 strict_unlock:
3593 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3594 TALLOC_FREE(req->outbuf);
3595 return;
3598 /****************************************************************************
3599 Reply to a read and X.
3600 ****************************************************************************/
3602 void reply_read_and_X(struct smb_request *req)
3604 connection_struct *conn = req->conn;
3605 files_struct *fsp;
3606 SMB_OFF_T startpos;
3607 size_t smb_maxcnt;
3608 bool big_readX = False;
3609 #if 0
3610 size_t smb_mincnt = SVAL(req->vwv+6, 0);
3611 #endif
3613 START_PROFILE(SMBreadX);
3615 if ((req->wct != 10) && (req->wct != 12)) {
3616 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3617 return;
3620 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
3621 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3622 smb_maxcnt = SVAL(req->vwv+5, 0);
3624 /* If it's an IPC, pass off the pipe handler. */
3625 if (IS_IPC(conn)) {
3626 reply_pipe_read_and_X(req);
3627 END_PROFILE(SMBreadX);
3628 return;
3631 if (!check_fsp(conn, req, fsp)) {
3632 END_PROFILE(SMBreadX);
3633 return;
3636 if (!CHECK_READ(fsp,req)) {
3637 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3638 END_PROFILE(SMBreadX);
3639 return;
3642 if (global_client_caps & CAP_LARGE_READX) {
3643 size_t upper_size = SVAL(req->vwv+7, 0);
3644 smb_maxcnt |= (upper_size<<16);
3645 if (upper_size > 1) {
3646 /* Can't do this on a chained packet. */
3647 if ((CVAL(req->vwv+0, 0) != 0xFF)) {
3648 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3649 END_PROFILE(SMBreadX);
3650 return;
3652 /* We currently don't do this on signed or sealed data. */
3653 if (srv_is_signing_active(req->sconn) ||
3654 is_encrypted_packet(req->inbuf)) {
3655 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3656 END_PROFILE(SMBreadX);
3657 return;
3659 /* Is there room in the reply for this data ? */
3660 if (smb_maxcnt > (0xFFFFFF - (smb_size -4 + 12*2))) {
3661 reply_nterror(req,
3662 NT_STATUS_INVALID_PARAMETER);
3663 END_PROFILE(SMBreadX);
3664 return;
3666 big_readX = True;
3670 if (req->wct == 12) {
3671 #ifdef LARGE_SMB_OFF_T
3673 * This is a large offset (64 bit) read.
3675 startpos |= (((SMB_OFF_T)IVAL(req->vwv+10, 0)) << 32);
3677 #else /* !LARGE_SMB_OFF_T */
3680 * Ensure we haven't been sent a >32 bit offset.
3683 if(IVAL(req->vwv+10, 0) != 0) {
3684 DEBUG(0,("reply_read_and_X - large offset (%x << 32) "
3685 "used and we don't support 64 bit offsets.\n",
3686 (unsigned int)IVAL(req->vwv+10, 0) ));
3687 END_PROFILE(SMBreadX);
3688 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3689 return;
3692 #endif /* LARGE_SMB_OFF_T */
3696 if (!big_readX) {
3697 NTSTATUS status = schedule_aio_read_and_X(conn,
3698 req,
3699 fsp,
3700 startpos,
3701 smb_maxcnt);
3702 if (NT_STATUS_IS_OK(status)) {
3703 /* Read scheduled - we're done. */
3704 goto out;
3706 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
3707 /* Real error - report to client. */
3708 END_PROFILE(SMBreadX);
3709 reply_nterror(req, status);
3710 return;
3712 /* NT_STATUS_RETRY - fall back to sync read. */
3715 smbd_lock_socket(req->sconn);
3716 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
3717 smbd_unlock_socket(req->sconn);
3719 out:
3720 END_PROFILE(SMBreadX);
3721 return;
3724 /****************************************************************************
3725 Error replies to writebraw must have smb_wct == 1. Fix this up.
3726 ****************************************************************************/
3728 void error_to_writebrawerr(struct smb_request *req)
3730 uint8 *old_outbuf = req->outbuf;
3732 reply_outbuf(req, 1, 0);
3734 memcpy(req->outbuf, old_outbuf, smb_size);
3735 TALLOC_FREE(old_outbuf);
3738 /****************************************************************************
3739 Reply to a writebraw (core+ or LANMAN1.0 protocol).
3740 ****************************************************************************/
3742 void reply_writebraw(struct smb_request *req)
3744 connection_struct *conn = req->conn;
3745 char *buf = NULL;
3746 ssize_t nwritten=0;
3747 ssize_t total_written=0;
3748 size_t numtowrite=0;
3749 size_t tcount;
3750 SMB_OFF_T startpos;
3751 char *data=NULL;
3752 bool write_through;
3753 files_struct *fsp;
3754 struct lock_struct lock;
3755 NTSTATUS status;
3757 START_PROFILE(SMBwritebraw);
3760 * If we ever reply with an error, it must have the SMB command
3761 * type of SMBwritec, not SMBwriteBraw, as this tells the client
3762 * we're finished.
3764 SCVAL(req->inbuf,smb_com,SMBwritec);
3766 if (srv_is_signing_active(req->sconn)) {
3767 END_PROFILE(SMBwritebraw);
3768 exit_server_cleanly("reply_writebraw: SMB signing is active - "
3769 "raw reads/writes are disallowed.");
3772 if (req->wct < 12) {
3773 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3774 error_to_writebrawerr(req);
3775 END_PROFILE(SMBwritebraw);
3776 return;
3779 if (req->sconn->smb1.echo_handler.trusted_fde) {
3780 DEBUG(2,("SMBwritebraw rejected with NOT_SUPPORTED because of "
3781 "'async smb echo handler = yes'\n"));
3782 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3783 error_to_writebrawerr(req);
3784 END_PROFILE(SMBwritebraw);
3785 return;
3788 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
3789 if (!check_fsp(conn, req, fsp)) {
3790 error_to_writebrawerr(req);
3791 END_PROFILE(SMBwritebraw);
3792 return;
3795 if (!CHECK_WRITE(fsp)) {
3796 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3797 error_to_writebrawerr(req);
3798 END_PROFILE(SMBwritebraw);
3799 return;
3802 tcount = IVAL(req->vwv+1, 0);
3803 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
3804 write_through = BITSETW(req->vwv+7,0);
3806 /* We have to deal with slightly different formats depending
3807 on whether we are using the core+ or lanman1.0 protocol */
3809 if(get_Protocol() <= PROTOCOL_COREPLUS) {
3810 numtowrite = SVAL(smb_buf(req->inbuf),-2);
3811 data = smb_buf(req->inbuf);
3812 } else {
3813 numtowrite = SVAL(req->vwv+10, 0);
3814 data = smb_base(req->inbuf) + SVAL(req->vwv+11, 0);
3817 /* Ensure we don't write bytes past the end of this packet. */
3818 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
3819 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3820 error_to_writebrawerr(req);
3821 END_PROFILE(SMBwritebraw);
3822 return;
3825 if (!fsp->print_file) {
3826 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
3827 (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
3828 &lock);
3830 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
3831 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
3832 error_to_writebrawerr(req);
3833 END_PROFILE(SMBwritebraw);
3834 return;
3838 if (numtowrite>0) {
3839 nwritten = write_file(req,fsp,data,startpos,numtowrite);
3842 DEBUG(3,("reply_writebraw: initial write fnum=%d start=%.0f num=%d "
3843 "wrote=%d sync=%d\n",
3844 fsp->fnum, (double)startpos, (int)numtowrite,
3845 (int)nwritten, (int)write_through));
3847 if (nwritten < (ssize_t)numtowrite) {
3848 reply_nterror(req, NT_STATUS_DISK_FULL);
3849 error_to_writebrawerr(req);
3850 goto strict_unlock;
3853 total_written = nwritten;
3855 /* Allocate a buffer of 64k + length. */
3856 buf = TALLOC_ARRAY(NULL, char, 65540);
3857 if (!buf) {
3858 reply_nterror(req, NT_STATUS_NO_MEMORY);
3859 error_to_writebrawerr(req);
3860 goto strict_unlock;
3863 /* Return a SMBwritebraw message to the redirector to tell
3864 * it to send more bytes */
3866 memcpy(buf, req->inbuf, smb_size);
3867 srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
3868 SCVAL(buf,smb_com,SMBwritebraw);
3869 SSVALS(buf,smb_vwv0,0xFFFF);
3870 show_msg(buf);
3871 if (!srv_send_smb(smbd_server_fd(),
3872 buf,
3873 false, 0, /* no signing */
3874 IS_CONN_ENCRYPTED(conn),
3875 &req->pcd)) {
3876 exit_server_cleanly("reply_writebraw: srv_send_smb "
3877 "failed.");
3880 /* Now read the raw data into the buffer and write it */
3881 status = read_smb_length(smbd_server_fd(), buf, SMB_SECONDARY_WAIT,
3882 &numtowrite);
3883 if (!NT_STATUS_IS_OK(status)) {
3884 exit_server_cleanly("secondary writebraw failed");
3887 /* Set up outbuf to return the correct size */
3888 reply_outbuf(req, 1, 0);
3890 if (numtowrite != 0) {
3892 if (numtowrite > 0xFFFF) {
3893 DEBUG(0,("reply_writebraw: Oversize secondary write "
3894 "raw requested (%u). Terminating\n",
3895 (unsigned int)numtowrite ));
3896 exit_server_cleanly("secondary writebraw failed");
3899 if (tcount > nwritten+numtowrite) {
3900 DEBUG(3,("reply_writebraw: Client overestimated the "
3901 "write %d %d %d\n",
3902 (int)tcount,(int)nwritten,(int)numtowrite));
3905 status = read_data(smbd_server_fd(), buf+4, numtowrite);
3907 if (!NT_STATUS_IS_OK(status)) {
3908 DEBUG(0,("reply_writebraw: Oversize secondary write "
3909 "raw read failed (%s). Terminating\n",
3910 nt_errstr(status)));
3911 exit_server_cleanly("secondary writebraw failed");
3914 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
3915 if (nwritten == -1) {
3916 TALLOC_FREE(buf);
3917 reply_nterror(req, map_nt_error_from_unix(errno));
3918 error_to_writebrawerr(req);
3919 goto strict_unlock;
3922 if (nwritten < (ssize_t)numtowrite) {
3923 SCVAL(req->outbuf,smb_rcls,ERRHRD);
3924 SSVAL(req->outbuf,smb_err,ERRdiskfull);
3927 if (nwritten > 0) {
3928 total_written += nwritten;
3932 TALLOC_FREE(buf);
3933 SSVAL(req->outbuf,smb_vwv0,total_written);
3935 status = sync_file(conn, fsp, write_through);
3936 if (!NT_STATUS_IS_OK(status)) {
3937 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
3938 fsp_str_dbg(fsp), nt_errstr(status)));
3939 reply_nterror(req, status);
3940 error_to_writebrawerr(req);
3941 goto strict_unlock;
3944 DEBUG(3,("reply_writebraw: secondart write fnum=%d start=%.0f num=%d "
3945 "wrote=%d\n",
3946 fsp->fnum, (double)startpos, (int)numtowrite,
3947 (int)total_written));
3949 if (!fsp->print_file) {
3950 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3953 /* We won't return a status if write through is not selected - this
3954 * follows what WfWg does */
3955 END_PROFILE(SMBwritebraw);
3957 if (!write_through && total_written==tcount) {
3959 #if RABBIT_PELLET_FIX
3961 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
3962 * sending a SMBkeepalive. Thanks to DaveCB at Sun for this.
3963 * JRA.
3965 if (!send_keepalive(smbd_server_fd())) {
3966 exit_server_cleanly("reply_writebraw: send of "
3967 "keepalive failed");
3969 #endif
3970 TALLOC_FREE(req->outbuf);
3972 return;
3974 strict_unlock:
3975 if (!fsp->print_file) {
3976 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
3979 END_PROFILE(SMBwritebraw);
3980 return;
3983 #undef DBGC_CLASS
3984 #define DBGC_CLASS DBGC_LOCKING
3986 /****************************************************************************
3987 Reply to a writeunlock (core+).
3988 ****************************************************************************/
3990 void reply_writeunlock(struct smb_request *req)
3992 connection_struct *conn = req->conn;
3993 ssize_t nwritten = -1;
3994 size_t numtowrite;
3995 SMB_OFF_T startpos;
3996 const char *data;
3997 NTSTATUS status = NT_STATUS_OK;
3998 files_struct *fsp;
3999 struct lock_struct lock;
4000 int saved_errno = 0;
4002 START_PROFILE(SMBwriteunlock);
4004 if (req->wct < 5) {
4005 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4006 END_PROFILE(SMBwriteunlock);
4007 return;
4010 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4012 if (!check_fsp(conn, req, fsp)) {
4013 END_PROFILE(SMBwriteunlock);
4014 return;
4017 if (!CHECK_WRITE(fsp)) {
4018 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4019 END_PROFILE(SMBwriteunlock);
4020 return;
4023 numtowrite = SVAL(req->vwv+1, 0);
4024 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4025 data = (const char *)req->buf + 3;
4027 if (!fsp->print_file && numtowrite > 0) {
4028 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4029 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4030 &lock);
4032 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4033 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4034 END_PROFILE(SMBwriteunlock);
4035 return;
4039 /* The special X/Open SMB protocol handling of
4040 zero length writes is *NOT* done for
4041 this call */
4042 if(numtowrite == 0) {
4043 nwritten = 0;
4044 } else {
4045 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4046 saved_errno = errno;
4049 status = sync_file(conn, fsp, False /* write through */);
4050 if (!NT_STATUS_IS_OK(status)) {
4051 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
4052 fsp_str_dbg(fsp), nt_errstr(status)));
4053 reply_nterror(req, status);
4054 goto strict_unlock;
4057 if(nwritten < 0) {
4058 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4059 goto strict_unlock;
4062 if((nwritten < numtowrite) && (numtowrite != 0)) {
4063 reply_nterror(req, NT_STATUS_DISK_FULL);
4064 goto strict_unlock;
4067 if (numtowrite && !fsp->print_file) {
4068 status = do_unlock(req->sconn->msg_ctx,
4069 fsp,
4070 (uint64_t)req->smbpid,
4071 (uint64_t)numtowrite,
4072 (uint64_t)startpos,
4073 WINDOWS_LOCK);
4075 if (NT_STATUS_V(status)) {
4076 reply_nterror(req, status);
4077 goto strict_unlock;
4081 reply_outbuf(req, 1, 0);
4083 SSVAL(req->outbuf,smb_vwv0,nwritten);
4085 DEBUG(3,("writeunlock fnum=%d num=%d wrote=%d\n",
4086 fsp->fnum, (int)numtowrite, (int)nwritten));
4088 strict_unlock:
4089 if (numtowrite && !fsp->print_file) {
4090 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4093 END_PROFILE(SMBwriteunlock);
4094 return;
4097 #undef DBGC_CLASS
4098 #define DBGC_CLASS DBGC_ALL
4100 /****************************************************************************
4101 Reply to a write.
4102 ****************************************************************************/
4104 void reply_write(struct smb_request *req)
4106 connection_struct *conn = req->conn;
4107 size_t numtowrite;
4108 ssize_t nwritten = -1;
4109 SMB_OFF_T startpos;
4110 const char *data;
4111 files_struct *fsp;
4112 struct lock_struct lock;
4113 NTSTATUS status;
4114 int saved_errno = 0;
4116 START_PROFILE(SMBwrite);
4118 if (req->wct < 5) {
4119 END_PROFILE(SMBwrite);
4120 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4121 return;
4124 /* If it's an IPC, pass off the pipe handler. */
4125 if (IS_IPC(conn)) {
4126 reply_pipe_write(req);
4127 END_PROFILE(SMBwrite);
4128 return;
4131 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4133 if (!check_fsp(conn, req, fsp)) {
4134 END_PROFILE(SMBwrite);
4135 return;
4138 if (!CHECK_WRITE(fsp)) {
4139 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4140 END_PROFILE(SMBwrite);
4141 return;
4144 numtowrite = SVAL(req->vwv+1, 0);
4145 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4146 data = (const char *)req->buf + 3;
4148 if (!fsp->print_file) {
4149 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4150 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4151 &lock);
4153 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4154 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4155 END_PROFILE(SMBwrite);
4156 return;
4161 * X/Open SMB protocol says that if smb_vwv1 is
4162 * zero then the file size should be extended or
4163 * truncated to the size given in smb_vwv[2-3].
4166 if(numtowrite == 0) {
4168 * This is actually an allocate call, and set EOF. JRA.
4170 nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos);
4171 if (nwritten < 0) {
4172 reply_nterror(req, NT_STATUS_DISK_FULL);
4173 goto strict_unlock;
4175 nwritten = vfs_set_filelen(fsp, (SMB_OFF_T)startpos);
4176 if (nwritten < 0) {
4177 reply_nterror(req, NT_STATUS_DISK_FULL);
4178 goto strict_unlock;
4180 trigger_write_time_update_immediate(fsp);
4181 } else {
4182 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4185 status = sync_file(conn, fsp, False);
4186 if (!NT_STATUS_IS_OK(status)) {
4187 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
4188 fsp_str_dbg(fsp), nt_errstr(status)));
4189 reply_nterror(req, status);
4190 goto strict_unlock;
4193 if(nwritten < 0) {
4194 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4195 goto strict_unlock;
4198 if((nwritten == 0) && (numtowrite != 0)) {
4199 reply_nterror(req, NT_STATUS_DISK_FULL);
4200 goto strict_unlock;
4203 reply_outbuf(req, 1, 0);
4205 SSVAL(req->outbuf,smb_vwv0,nwritten);
4207 if (nwritten < (ssize_t)numtowrite) {
4208 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4209 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4212 DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten));
4214 strict_unlock:
4215 if (!fsp->print_file) {
4216 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4219 END_PROFILE(SMBwrite);
4220 return;
4223 /****************************************************************************
4224 Ensure a buffer is a valid writeX for recvfile purposes.
4225 ****************************************************************************/
4227 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
4228 (2*14) + /* word count (including bcc) */ \
4229 1 /* pad byte */)
4231 bool is_valid_writeX_buffer(struct smbd_server_connection *sconn,
4232 const uint8_t *inbuf)
4234 size_t numtowrite;
4235 connection_struct *conn = NULL;
4236 unsigned int doff = 0;
4237 size_t len = smb_len_large(inbuf);
4239 if (is_encrypted_packet(inbuf)) {
4240 /* Can't do this on encrypted
4241 * connections. */
4242 return false;
4245 if (CVAL(inbuf,smb_com) != SMBwriteX) {
4246 return false;
4249 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
4250 CVAL(inbuf,smb_wct) != 14) {
4251 DEBUG(10,("is_valid_writeX_buffer: chained or "
4252 "invalid word length.\n"));
4253 return false;
4256 conn = conn_find(sconn, SVAL(inbuf, smb_tid));
4257 if (conn == NULL) {
4258 DEBUG(10,("is_valid_writeX_buffer: bad tid\n"));
4259 return false;
4261 if (IS_IPC(conn)) {
4262 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
4263 return false;
4265 if (IS_PRINT(conn)) {
4266 DEBUG(10,("is_valid_writeX_buffer: printing tid\n"));
4267 return false;
4269 doff = SVAL(inbuf,smb_vwv11);
4271 numtowrite = SVAL(inbuf,smb_vwv10);
4273 if (len > doff && len - doff > 0xFFFF) {
4274 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
4277 if (numtowrite == 0) {
4278 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
4279 return false;
4282 /* Ensure the sizes match up. */
4283 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
4284 /* no pad byte...old smbclient :-( */
4285 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
4286 (unsigned int)doff,
4287 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
4288 return false;
4291 if (len - doff != numtowrite) {
4292 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
4293 "len = %u, doff = %u, numtowrite = %u\n",
4294 (unsigned int)len,
4295 (unsigned int)doff,
4296 (unsigned int)numtowrite ));
4297 return false;
4300 DEBUG(10,("is_valid_writeX_buffer: true "
4301 "len = %u, doff = %u, numtowrite = %u\n",
4302 (unsigned int)len,
4303 (unsigned int)doff,
4304 (unsigned int)numtowrite ));
4306 return true;
4309 /****************************************************************************
4310 Reply to a write and X.
4311 ****************************************************************************/
4313 void reply_write_and_X(struct smb_request *req)
4315 connection_struct *conn = req->conn;
4316 files_struct *fsp;
4317 struct lock_struct lock;
4318 SMB_OFF_T startpos;
4319 size_t numtowrite;
4320 bool write_through;
4321 ssize_t nwritten;
4322 unsigned int smb_doff;
4323 unsigned int smblen;
4324 char *data;
4325 NTSTATUS status;
4326 int saved_errno = 0;
4328 START_PROFILE(SMBwriteX);
4330 if ((req->wct != 12) && (req->wct != 14)) {
4331 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4332 END_PROFILE(SMBwriteX);
4333 return;
4336 numtowrite = SVAL(req->vwv+10, 0);
4337 smb_doff = SVAL(req->vwv+11, 0);
4338 smblen = smb_len(req->inbuf);
4340 if (req->unread_bytes > 0xFFFF ||
4341 (smblen > smb_doff &&
4342 smblen - smb_doff > 0xFFFF)) {
4343 numtowrite |= (((size_t)SVAL(req->vwv+9, 0))<<16);
4346 if (req->unread_bytes) {
4347 /* Can't do a recvfile write on IPC$ */
4348 if (IS_IPC(conn)) {
4349 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4350 END_PROFILE(SMBwriteX);
4351 return;
4353 if (numtowrite != req->unread_bytes) {
4354 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4355 END_PROFILE(SMBwriteX);
4356 return;
4358 } else {
4359 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
4360 smb_doff + numtowrite > smblen) {
4361 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4362 END_PROFILE(SMBwriteX);
4363 return;
4367 /* If it's an IPC, pass off the pipe handler. */
4368 if (IS_IPC(conn)) {
4369 if (req->unread_bytes) {
4370 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4371 END_PROFILE(SMBwriteX);
4372 return;
4374 reply_pipe_write_and_X(req);
4375 END_PROFILE(SMBwriteX);
4376 return;
4379 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
4380 startpos = IVAL_TO_SMB_OFF_T(req->vwv+3, 0);
4381 write_through = BITSETW(req->vwv+7,0);
4383 if (!check_fsp(conn, req, fsp)) {
4384 END_PROFILE(SMBwriteX);
4385 return;
4388 if (!CHECK_WRITE(fsp)) {
4389 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4390 END_PROFILE(SMBwriteX);
4391 return;
4394 data = smb_base(req->inbuf) + smb_doff;
4396 if(req->wct == 14) {
4397 #ifdef LARGE_SMB_OFF_T
4399 * This is a large offset (64 bit) write.
4401 startpos |= (((SMB_OFF_T)IVAL(req->vwv+12, 0)) << 32);
4403 #else /* !LARGE_SMB_OFF_T */
4406 * Ensure we haven't been sent a >32 bit offset.
4409 if(IVAL(req->vwv+12, 0) != 0) {
4410 DEBUG(0,("reply_write_and_X - large offset (%x << 32) "
4411 "used and we don't support 64 bit offsets.\n",
4412 (unsigned int)IVAL(req->vwv+12, 0) ));
4413 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4414 END_PROFILE(SMBwriteX);
4415 return;
4418 #endif /* LARGE_SMB_OFF_T */
4421 /* X/Open SMB protocol says that, unlike SMBwrite
4422 if the length is zero then NO truncation is
4423 done, just a write of zero. To truncate a file,
4424 use SMBwrite. */
4426 if(numtowrite == 0) {
4427 nwritten = 0;
4428 } else {
4429 if (req->unread_bytes == 0) {
4430 status = schedule_aio_write_and_X(conn,
4431 req,
4432 fsp,
4433 data,
4434 startpos,
4435 numtowrite);
4437 if (NT_STATUS_IS_OK(status)) {
4438 /* write scheduled - we're done. */
4439 goto out;
4441 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
4442 /* Real error - report to client. */
4443 reply_nterror(req, status);
4444 goto out;
4446 /* NT_STATUS_RETRY - fall through to sync write. */
4449 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4450 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4451 &lock);
4453 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4454 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4455 goto out;
4458 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4459 saved_errno = errno;
4461 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4464 if(nwritten < 0) {
4465 reply_nterror(req, map_nt_error_from_unix(saved_errno));
4466 goto out;
4469 if((nwritten == 0) && (numtowrite != 0)) {
4470 reply_nterror(req, NT_STATUS_DISK_FULL);
4471 goto out;
4474 reply_outbuf(req, 6, 0);
4475 SSVAL(req->outbuf,smb_vwv2,nwritten);
4476 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4478 if (nwritten < (ssize_t)numtowrite) {
4479 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4480 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4483 DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
4484 fsp->fnum, (int)numtowrite, (int)nwritten));
4486 status = sync_file(conn, fsp, write_through);
4487 if (!NT_STATUS_IS_OK(status)) {
4488 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4489 fsp_str_dbg(fsp), nt_errstr(status)));
4490 reply_nterror(req, status);
4491 goto out;
4494 END_PROFILE(SMBwriteX);
4495 chain_reply(req);
4496 return;
4498 out:
4499 END_PROFILE(SMBwriteX);
4500 return;
4503 /****************************************************************************
4504 Reply to a lseek.
4505 ****************************************************************************/
4507 void reply_lseek(struct smb_request *req)
4509 connection_struct *conn = req->conn;
4510 SMB_OFF_T startpos;
4511 SMB_OFF_T res= -1;
4512 int mode,umode;
4513 files_struct *fsp;
4515 START_PROFILE(SMBlseek);
4517 if (req->wct < 4) {
4518 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4519 END_PROFILE(SMBlseek);
4520 return;
4523 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4525 if (!check_fsp(conn, req, fsp)) {
4526 return;
4529 flush_write_cache(fsp, SEEK_FLUSH);
4531 mode = SVAL(req->vwv+1, 0) & 3;
4532 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4533 startpos = (SMB_OFF_T)IVALS(req->vwv+2, 0);
4535 switch (mode) {
4536 case 0:
4537 umode = SEEK_SET;
4538 res = startpos;
4539 break;
4540 case 1:
4541 umode = SEEK_CUR;
4542 res = fsp->fh->pos + startpos;
4543 break;
4544 case 2:
4545 umode = SEEK_END;
4546 break;
4547 default:
4548 umode = SEEK_SET;
4549 res = startpos;
4550 break;
4553 if (umode == SEEK_END) {
4554 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
4555 if(errno == EINVAL) {
4556 SMB_OFF_T current_pos = startpos;
4558 if(fsp_stat(fsp) == -1) {
4559 reply_nterror(req,
4560 map_nt_error_from_unix(errno));
4561 END_PROFILE(SMBlseek);
4562 return;
4565 current_pos += fsp->fsp_name->st.st_ex_size;
4566 if(current_pos < 0)
4567 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
4571 if(res == -1) {
4572 reply_nterror(req, map_nt_error_from_unix(errno));
4573 END_PROFILE(SMBlseek);
4574 return;
4578 fsp->fh->pos = res;
4580 reply_outbuf(req, 2, 0);
4581 SIVAL(req->outbuf,smb_vwv0,res);
4583 DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
4584 fsp->fnum, (double)startpos, (double)res, mode));
4586 END_PROFILE(SMBlseek);
4587 return;
4590 /****************************************************************************
4591 Reply to a flush.
4592 ****************************************************************************/
4594 void reply_flush(struct smb_request *req)
4596 connection_struct *conn = req->conn;
4597 uint16 fnum;
4598 files_struct *fsp;
4600 START_PROFILE(SMBflush);
4602 if (req->wct < 1) {
4603 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4604 return;
4607 fnum = SVAL(req->vwv+0, 0);
4608 fsp = file_fsp(req, fnum);
4610 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) {
4611 return;
4614 if (!fsp) {
4615 file_sync_all(conn);
4616 } else {
4617 NTSTATUS status = sync_file(conn, fsp, True);
4618 if (!NT_STATUS_IS_OK(status)) {
4619 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
4620 fsp_str_dbg(fsp), nt_errstr(status)));
4621 reply_nterror(req, status);
4622 END_PROFILE(SMBflush);
4623 return;
4627 reply_outbuf(req, 0, 0);
4629 DEBUG(3,("flush\n"));
4630 END_PROFILE(SMBflush);
4631 return;
4634 /****************************************************************************
4635 Reply to a exit.
4636 conn POINTER CAN BE NULL HERE !
4637 ****************************************************************************/
4639 void reply_exit(struct smb_request *req)
4641 START_PROFILE(SMBexit);
4643 file_close_pid(req->smbpid, req->vuid);
4645 reply_outbuf(req, 0, 0);
4647 DEBUG(3,("exit\n"));
4649 END_PROFILE(SMBexit);
4650 return;
4653 /****************************************************************************
4654 Reply to a close - has to deal with closing a directory opened by NT SMB's.
4655 ****************************************************************************/
4657 void reply_close(struct smb_request *req)
4659 connection_struct *conn = req->conn;
4660 NTSTATUS status = NT_STATUS_OK;
4661 files_struct *fsp = NULL;
4662 START_PROFILE(SMBclose);
4664 if (req->wct < 3) {
4665 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4666 END_PROFILE(SMBclose);
4667 return;
4670 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4673 * We can only use check_fsp if we know it's not a directory.
4676 if(!fsp || (fsp->conn != conn) || (fsp->vuid != req->vuid)) {
4677 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
4678 END_PROFILE(SMBclose);
4679 return;
4682 if(fsp->is_directory) {
4684 * Special case - close NT SMB directory handle.
4686 DEBUG(3,("close directory fnum=%d\n", fsp->fnum));
4687 status = close_file(req, fsp, NORMAL_CLOSE);
4688 } else {
4689 time_t t;
4691 * Close ordinary file.
4694 DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
4695 fsp->fh->fd, fsp->fnum,
4696 conn->num_files_open));
4699 * Take care of any time sent in the close.
4702 t = srv_make_unix_date3(req->vwv+1);
4703 set_close_write_time(fsp, convert_time_t_to_timespec(t));
4706 * close_file() returns the unix errno if an error
4707 * was detected on close - normally this is due to
4708 * a disk full error. If not then it was probably an I/O error.
4711 status = close_file(req, fsp, NORMAL_CLOSE);
4714 if (!NT_STATUS_IS_OK(status)) {
4715 reply_nterror(req, status);
4716 END_PROFILE(SMBclose);
4717 return;
4720 reply_outbuf(req, 0, 0);
4721 END_PROFILE(SMBclose);
4722 return;
4725 /****************************************************************************
4726 Reply to a writeclose (Core+ protocol).
4727 ****************************************************************************/
4729 void reply_writeclose(struct smb_request *req)
4731 connection_struct *conn = req->conn;
4732 size_t numtowrite;
4733 ssize_t nwritten = -1;
4734 NTSTATUS close_status = NT_STATUS_OK;
4735 SMB_OFF_T startpos;
4736 const char *data;
4737 struct timespec mtime;
4738 files_struct *fsp;
4739 struct lock_struct lock;
4741 START_PROFILE(SMBwriteclose);
4743 if (req->wct < 6) {
4744 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4745 END_PROFILE(SMBwriteclose);
4746 return;
4749 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4751 if (!check_fsp(conn, req, fsp)) {
4752 END_PROFILE(SMBwriteclose);
4753 return;
4755 if (!CHECK_WRITE(fsp)) {
4756 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4757 END_PROFILE(SMBwriteclose);
4758 return;
4761 numtowrite = SVAL(req->vwv+1, 0);
4762 startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
4763 mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
4764 data = (const char *)req->buf + 1;
4766 if (!fsp->print_file) {
4767 init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
4768 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
4769 &lock);
4771 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
4772 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
4773 END_PROFILE(SMBwriteclose);
4774 return;
4778 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4780 set_close_write_time(fsp, mtime);
4783 * More insanity. W2K only closes the file if writelen > 0.
4784 * JRA.
4787 if (numtowrite) {
4788 DEBUG(3,("reply_writeclose: zero length write doesn't close "
4789 "file %s\n", fsp_str_dbg(fsp)));
4790 close_status = close_file(req, fsp, NORMAL_CLOSE);
4793 DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
4794 fsp->fnum, (int)numtowrite, (int)nwritten,
4795 conn->num_files_open));
4797 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
4798 reply_nterror(req, NT_STATUS_DISK_FULL);
4799 goto strict_unlock;
4802 if(!NT_STATUS_IS_OK(close_status)) {
4803 reply_nterror(req, close_status);
4804 goto strict_unlock;
4807 reply_outbuf(req, 1, 0);
4809 SSVAL(req->outbuf,smb_vwv0,nwritten);
4811 strict_unlock:
4812 if (numtowrite && !fsp->print_file) {
4813 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
4816 END_PROFILE(SMBwriteclose);
4817 return;
4820 #undef DBGC_CLASS
4821 #define DBGC_CLASS DBGC_LOCKING
4823 /****************************************************************************
4824 Reply to a lock.
4825 ****************************************************************************/
4827 void reply_lock(struct smb_request *req)
4829 connection_struct *conn = req->conn;
4830 uint64_t count,offset;
4831 NTSTATUS status;
4832 files_struct *fsp;
4833 struct byte_range_lock *br_lck = NULL;
4835 START_PROFILE(SMBlock);
4837 if (req->wct < 5) {
4838 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4839 END_PROFILE(SMBlock);
4840 return;
4843 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4845 if (!check_fsp(conn, req, fsp)) {
4846 END_PROFILE(SMBlock);
4847 return;
4850 count = (uint64_t)IVAL(req->vwv+1, 0);
4851 offset = (uint64_t)IVAL(req->vwv+3, 0);
4853 DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
4854 fsp->fh->fd, fsp->fnum, (double)offset, (double)count));
4856 br_lck = do_lock(req->sconn->msg_ctx,
4857 fsp,
4858 (uint64_t)req->smbpid,
4859 count,
4860 offset,
4861 WRITE_LOCK,
4862 WINDOWS_LOCK,
4863 False, /* Non-blocking lock. */
4864 &status,
4865 NULL,
4866 NULL);
4868 TALLOC_FREE(br_lck);
4870 if (NT_STATUS_V(status)) {
4871 reply_nterror(req, status);
4872 END_PROFILE(SMBlock);
4873 return;
4876 reply_outbuf(req, 0, 0);
4878 END_PROFILE(SMBlock);
4879 return;
4882 /****************************************************************************
4883 Reply to a unlock.
4884 ****************************************************************************/
4886 void reply_unlock(struct smb_request *req)
4888 connection_struct *conn = req->conn;
4889 uint64_t count,offset;
4890 NTSTATUS status;
4891 files_struct *fsp;
4893 START_PROFILE(SMBunlock);
4895 if (req->wct < 5) {
4896 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4897 END_PROFILE(SMBunlock);
4898 return;
4901 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
4903 if (!check_fsp(conn, req, fsp)) {
4904 END_PROFILE(SMBunlock);
4905 return;
4908 count = (uint64_t)IVAL(req->vwv+1, 0);
4909 offset = (uint64_t)IVAL(req->vwv+3, 0);
4911 status = do_unlock(req->sconn->msg_ctx,
4912 fsp,
4913 (uint64_t)req->smbpid,
4914 count,
4915 offset,
4916 WINDOWS_LOCK);
4918 if (NT_STATUS_V(status)) {
4919 reply_nterror(req, status);
4920 END_PROFILE(SMBunlock);
4921 return;
4924 DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
4925 fsp->fh->fd, fsp->fnum, (double)offset, (double)count ) );
4927 reply_outbuf(req, 0, 0);
4929 END_PROFILE(SMBunlock);
4930 return;
4933 #undef DBGC_CLASS
4934 #define DBGC_CLASS DBGC_ALL
4936 /****************************************************************************
4937 Reply to a tdis.
4938 conn POINTER CAN BE NULL HERE !
4939 ****************************************************************************/
4941 void reply_tdis(struct smb_request *req)
4943 connection_struct *conn = req->conn;
4944 START_PROFILE(SMBtdis);
4946 if (!conn) {
4947 DEBUG(4,("Invalid connection in tdis\n"));
4948 reply_nterror(req, NT_STATUS_NETWORK_NAME_DELETED);
4949 END_PROFILE(SMBtdis);
4950 return;
4953 conn->used = False;
4955 close_cnum(conn,req->vuid);
4956 req->conn = NULL;
4958 reply_outbuf(req, 0, 0);
4959 END_PROFILE(SMBtdis);
4960 return;
4963 /****************************************************************************
4964 Reply to a echo.
4965 conn POINTER CAN BE NULL HERE !
4966 ****************************************************************************/
4968 void reply_echo(struct smb_request *req)
4970 connection_struct *conn = req->conn;
4971 struct smb_perfcount_data local_pcd;
4972 struct smb_perfcount_data *cur_pcd;
4973 int smb_reverb;
4974 int seq_num;
4976 START_PROFILE(SMBecho);
4978 smb_init_perfcount_data(&local_pcd);
4980 if (req->wct < 1) {
4981 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4982 END_PROFILE(SMBecho);
4983 return;
4986 smb_reverb = SVAL(req->vwv+0, 0);
4988 reply_outbuf(req, 1, req->buflen);
4990 /* copy any incoming data back out */
4991 if (req->buflen > 0) {
4992 memcpy(smb_buf(req->outbuf), req->buf, req->buflen);
4995 if (smb_reverb > 100) {
4996 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
4997 smb_reverb = 100;
5000 for (seq_num = 1 ; seq_num <= smb_reverb ; seq_num++) {
5002 /* this makes sure we catch the request pcd */
5003 if (seq_num == smb_reverb) {
5004 cur_pcd = &req->pcd;
5005 } else {
5006 SMB_PERFCOUNT_COPY_CONTEXT(&req->pcd, &local_pcd);
5007 cur_pcd = &local_pcd;
5010 SSVAL(req->outbuf,smb_vwv0,seq_num);
5012 show_msg((char *)req->outbuf);
5013 if (!srv_send_smb(smbd_server_fd(),
5014 (char *)req->outbuf,
5015 true, req->seqnum+1,
5016 IS_CONN_ENCRYPTED(conn)||req->encrypted,
5017 cur_pcd))
5018 exit_server_cleanly("reply_echo: srv_send_smb failed.");
5021 DEBUG(3,("echo %d times\n", smb_reverb));
5023 TALLOC_FREE(req->outbuf);
5025 END_PROFILE(SMBecho);
5026 return;
5029 /****************************************************************************
5030 Reply to a printopen.
5031 ****************************************************************************/
5033 void reply_printopen(struct smb_request *req)
5035 connection_struct *conn = req->conn;
5036 files_struct *fsp;
5037 NTSTATUS status;
5039 START_PROFILE(SMBsplopen);
5041 if (req->wct < 2) {
5042 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5043 END_PROFILE(SMBsplopen);
5044 return;
5047 if (!CAN_PRINT(conn)) {
5048 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5049 END_PROFILE(SMBsplopen);
5050 return;
5053 status = file_new(req, conn, &fsp);
5054 if(!NT_STATUS_IS_OK(status)) {
5055 reply_nterror(req, status);
5056 END_PROFILE(SMBsplopen);
5057 return;
5060 /* Open for exclusive use, write only. */
5061 status = print_spool_open(fsp, NULL, req->vuid);
5063 if (!NT_STATUS_IS_OK(status)) {
5064 file_free(req, fsp);
5065 reply_nterror(req, status);
5066 END_PROFILE(SMBsplopen);
5067 return;
5070 reply_outbuf(req, 1, 0);
5071 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
5073 DEBUG(3,("openprint fd=%d fnum=%d\n",
5074 fsp->fh->fd, fsp->fnum));
5076 END_PROFILE(SMBsplopen);
5077 return;
5080 /****************************************************************************
5081 Reply to a printclose.
5082 ****************************************************************************/
5084 void reply_printclose(struct smb_request *req)
5086 connection_struct *conn = req->conn;
5087 files_struct *fsp;
5088 NTSTATUS status;
5090 START_PROFILE(SMBsplclose);
5092 if (req->wct < 1) {
5093 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5094 END_PROFILE(SMBsplclose);
5095 return;
5098 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5100 if (!check_fsp(conn, req, fsp)) {
5101 END_PROFILE(SMBsplclose);
5102 return;
5105 if (!CAN_PRINT(conn)) {
5106 reply_force_doserror(req, ERRSRV, ERRerror);
5107 END_PROFILE(SMBsplclose);
5108 return;
5111 DEBUG(3,("printclose fd=%d fnum=%d\n",
5112 fsp->fh->fd,fsp->fnum));
5114 status = close_file(req, fsp, NORMAL_CLOSE);
5116 if(!NT_STATUS_IS_OK(status)) {
5117 reply_nterror(req, status);
5118 END_PROFILE(SMBsplclose);
5119 return;
5122 reply_outbuf(req, 0, 0);
5124 END_PROFILE(SMBsplclose);
5125 return;
5128 /****************************************************************************
5129 Reply to a printqueue.
5130 ****************************************************************************/
5132 void reply_printqueue(struct smb_request *req)
5134 connection_struct *conn = req->conn;
5135 int max_count;
5136 int start_index;
5138 START_PROFILE(SMBsplretq);
5140 if (req->wct < 2) {
5141 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5142 END_PROFILE(SMBsplretq);
5143 return;
5146 max_count = SVAL(req->vwv+0, 0);
5147 start_index = SVAL(req->vwv+1, 0);
5149 /* we used to allow the client to get the cnum wrong, but that
5150 is really quite gross and only worked when there was only
5151 one printer - I think we should now only accept it if they
5152 get it right (tridge) */
5153 if (!CAN_PRINT(conn)) {
5154 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5155 END_PROFILE(SMBsplretq);
5156 return;
5159 reply_outbuf(req, 2, 3);
5160 SSVAL(req->outbuf,smb_vwv0,0);
5161 SSVAL(req->outbuf,smb_vwv1,0);
5162 SCVAL(smb_buf(req->outbuf),0,1);
5163 SSVAL(smb_buf(req->outbuf),1,0);
5165 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
5166 start_index, max_count));
5169 TALLOC_CTX *mem_ctx = talloc_tos();
5170 NTSTATUS status;
5171 WERROR werr;
5172 const char *sharename = lp_servicename(SNUM(conn));
5173 struct rpc_pipe_client *cli = NULL;
5174 struct policy_handle handle;
5175 struct spoolss_DevmodeContainer devmode_ctr;
5176 union spoolss_JobInfo *info;
5177 uint32_t count;
5178 uint32_t num_to_get;
5179 uint32_t first;
5180 uint32_t i;
5182 ZERO_STRUCT(handle);
5184 status = rpc_connect_spoolss_pipe(conn, &cli);
5185 if (!NT_STATUS_IS_OK(status)) {
5186 DEBUG(0, ("reply_printqueue: "
5187 "could not connect to spoolss: %s\n",
5188 nt_errstr(status)));
5189 reply_nterror(req, status);
5190 goto out;
5193 ZERO_STRUCT(devmode_ctr);
5195 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
5196 sharename,
5197 NULL, devmode_ctr,
5198 SEC_FLAG_MAXIMUM_ALLOWED,
5199 &handle,
5200 &werr);
5201 if (!NT_STATUS_IS_OK(status)) {
5202 reply_nterror(req, status);
5203 goto out;
5205 if (!W_ERROR_IS_OK(werr)) {
5206 reply_nterror(req, werror_to_ntstatus(werr));
5207 goto out;
5210 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5211 &handle,
5212 0, /* firstjob */
5213 0xff, /* numjobs */
5214 2, /* level */
5215 0, /* offered */
5216 &count,
5217 &info);
5218 if (!W_ERROR_IS_OK(werr)) {
5219 reply_nterror(req, werror_to_ntstatus(werr));
5220 goto out;
5223 if (max_count > 0) {
5224 first = start_index;
5225 } else {
5226 first = start_index + max_count + 1;
5229 if (first >= count) {
5230 num_to_get = first;
5231 } else {
5232 num_to_get = first + MIN(ABS(max_count), count - first);
5235 for (i = first; i < num_to_get; i++) {
5236 char blob[28];
5237 char *p = blob;
5238 time_t qtime = spoolss_Time_to_time_t(&info[i].info2.submitted);
5239 int qstatus;
5240 uint16_t qrapjobid = pjobid_to_rap(sharename,
5241 info[i].info2.job_id);
5243 if (info[i].info2.status == JOB_STATUS_PRINTING) {
5244 qstatus = 2;
5245 } else {
5246 qstatus = 3;
5249 srv_put_dos_date2(p, 0, qtime);
5250 SCVAL(p, 4, qstatus);
5251 SSVAL(p, 5, qrapjobid);
5252 SIVAL(p, 7, info[i].info2.size);
5253 SCVAL(p, 11, 0);
5254 srvstr_push(blob, req->flags2, p+12,
5255 info[i].info2.notify_name, 16, STR_ASCII);
5257 if (message_push_blob(
5258 &req->outbuf,
5259 data_blob_const(
5260 blob, sizeof(blob))) == -1) {
5261 reply_nterror(req, NT_STATUS_NO_MEMORY);
5262 goto out;
5266 if (count > 0) {
5267 SSVAL(req->outbuf,smb_vwv0,count);
5268 SSVAL(req->outbuf,smb_vwv1,
5269 (max_count>0?first+count:first-1));
5270 SCVAL(smb_buf(req->outbuf),0,1);
5271 SSVAL(smb_buf(req->outbuf),1,28*count);
5275 DEBUG(3, ("%u entries returned in queue\n",
5276 (unsigned)count));
5278 out:
5279 if (cli && is_valid_policy_hnd(&handle)) {
5280 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
5285 END_PROFILE(SMBsplretq);
5286 return;
5289 /****************************************************************************
5290 Reply to a printwrite.
5291 ****************************************************************************/
5293 void reply_printwrite(struct smb_request *req)
5295 connection_struct *conn = req->conn;
5296 int numtowrite;
5297 const char *data;
5298 files_struct *fsp;
5300 START_PROFILE(SMBsplwr);
5302 if (req->wct < 1) {
5303 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5304 END_PROFILE(SMBsplwr);
5305 return;
5308 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
5310 if (!check_fsp(conn, req, fsp)) {
5311 END_PROFILE(SMBsplwr);
5312 return;
5315 if (!fsp->print_file) {
5316 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5317 END_PROFILE(SMBsplwr);
5318 return;
5321 if (!CHECK_WRITE(fsp)) {
5322 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5323 END_PROFILE(SMBsplwr);
5324 return;
5327 numtowrite = SVAL(req->buf, 1);
5329 if (req->buflen < numtowrite + 3) {
5330 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5331 END_PROFILE(SMBsplwr);
5332 return;
5335 data = (const char *)req->buf + 3;
5337 if (write_file(req,fsp,data,(SMB_OFF_T)-1,numtowrite) != numtowrite) {
5338 reply_nterror(req, map_nt_error_from_unix(errno));
5339 END_PROFILE(SMBsplwr);
5340 return;
5343 DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
5345 END_PROFILE(SMBsplwr);
5346 return;
5349 /****************************************************************************
5350 Reply to a mkdir.
5351 ****************************************************************************/
5353 void reply_mkdir(struct smb_request *req)
5355 connection_struct *conn = req->conn;
5356 struct smb_filename *smb_dname = NULL;
5357 char *directory = NULL;
5358 NTSTATUS status;
5359 TALLOC_CTX *ctx = talloc_tos();
5361 START_PROFILE(SMBmkdir);
5363 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5364 STR_TERMINATE, &status);
5365 if (!NT_STATUS_IS_OK(status)) {
5366 reply_nterror(req, status);
5367 goto out;
5370 status = filename_convert(ctx, conn,
5371 req->flags2 & FLAGS2_DFS_PATHNAMES,
5372 directory,
5374 NULL,
5375 &smb_dname);
5376 if (!NT_STATUS_IS_OK(status)) {
5377 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5378 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5379 ERRSRV, ERRbadpath);
5380 goto out;
5382 reply_nterror(req, status);
5383 goto out;
5386 status = create_directory(conn, req, smb_dname);
5388 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
5390 if (!NT_STATUS_IS_OK(status)) {
5392 if (!use_nt_status()
5393 && NT_STATUS_EQUAL(status,
5394 NT_STATUS_OBJECT_NAME_COLLISION)) {
5396 * Yes, in the DOS error code case we get a
5397 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
5398 * samba4 torture test.
5400 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
5403 reply_nterror(req, status);
5404 goto out;
5407 reply_outbuf(req, 0, 0);
5409 DEBUG(3, ("mkdir %s\n", smb_dname->base_name));
5410 out:
5411 TALLOC_FREE(smb_dname);
5412 END_PROFILE(SMBmkdir);
5413 return;
5416 /****************************************************************************
5417 Reply to a rmdir.
5418 ****************************************************************************/
5420 void reply_rmdir(struct smb_request *req)
5422 connection_struct *conn = req->conn;
5423 struct smb_filename *smb_dname = NULL;
5424 char *directory = NULL;
5425 NTSTATUS status;
5426 TALLOC_CTX *ctx = talloc_tos();
5427 files_struct *fsp = NULL;
5428 int info = 0;
5429 struct smbd_server_connection *sconn = req->sconn;
5431 START_PROFILE(SMBrmdir);
5433 srvstr_get_path_req(ctx, req, &directory, (const char *)req->buf + 1,
5434 STR_TERMINATE, &status);
5435 if (!NT_STATUS_IS_OK(status)) {
5436 reply_nterror(req, status);
5437 goto out;
5440 status = filename_convert(ctx, conn,
5441 req->flags2 & FLAGS2_DFS_PATHNAMES,
5442 directory,
5444 NULL,
5445 &smb_dname);
5446 if (!NT_STATUS_IS_OK(status)) {
5447 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5448 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5449 ERRSRV, ERRbadpath);
5450 goto out;
5452 reply_nterror(req, status);
5453 goto out;
5456 if (is_ntfs_stream_smb_fname(smb_dname)) {
5457 reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY);
5458 goto out;
5461 status = SMB_VFS_CREATE_FILE(
5462 conn, /* conn */
5463 req, /* req */
5464 0, /* root_dir_fid */
5465 smb_dname, /* fname */
5466 DELETE_ACCESS, /* access_mask */
5467 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5468 FILE_SHARE_DELETE),
5469 FILE_OPEN, /* create_disposition*/
5470 FILE_DIRECTORY_FILE, /* create_options */
5471 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
5472 0, /* oplock_request */
5473 0, /* allocation_size */
5474 0, /* private_flags */
5475 NULL, /* sd */
5476 NULL, /* ea_list */
5477 &fsp, /* result */
5478 &info); /* pinfo */
5480 if (!NT_STATUS_IS_OK(status)) {
5481 if (open_was_deferred(req->mid)) {
5482 /* We have re-scheduled this call. */
5483 goto out;
5485 reply_nterror(req, status);
5486 goto out;
5489 status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
5490 if (!NT_STATUS_IS_OK(status)) {
5491 close_file(req, fsp, ERROR_CLOSE);
5492 reply_nterror(req, status);
5493 goto out;
5496 if (!set_delete_on_close(fsp, true, &conn->server_info->utok)) {
5497 close_file(req, fsp, ERROR_CLOSE);
5498 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5499 goto out;
5502 status = close_file(req, fsp, NORMAL_CLOSE);
5503 if (!NT_STATUS_IS_OK(status)) {
5504 reply_nterror(req, status);
5505 } else {
5506 reply_outbuf(req, 0, 0);
5509 dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
5511 DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
5512 out:
5513 TALLOC_FREE(smb_dname);
5514 END_PROFILE(SMBrmdir);
5515 return;
5518 /*******************************************************************
5519 Resolve wildcards in a filename rename.
5520 ********************************************************************/
5522 static bool resolve_wildcards(TALLOC_CTX *ctx,
5523 const char *name1,
5524 const char *name2,
5525 char **pp_newname)
5527 char *name2_copy = NULL;
5528 char *root1 = NULL;
5529 char *root2 = NULL;
5530 char *ext1 = NULL;
5531 char *ext2 = NULL;
5532 char *p,*p2, *pname1, *pname2;
5534 name2_copy = talloc_strdup(ctx, name2);
5535 if (!name2_copy) {
5536 return False;
5539 pname1 = strrchr_m(name1,'/');
5540 pname2 = strrchr_m(name2_copy,'/');
5542 if (!pname1 || !pname2) {
5543 return False;
5546 /* Truncate the copy of name2 at the last '/' */
5547 *pname2 = '\0';
5549 /* Now go past the '/' */
5550 pname1++;
5551 pname2++;
5553 root1 = talloc_strdup(ctx, pname1);
5554 root2 = talloc_strdup(ctx, pname2);
5556 if (!root1 || !root2) {
5557 return False;
5560 p = strrchr_m(root1,'.');
5561 if (p) {
5562 *p = 0;
5563 ext1 = talloc_strdup(ctx, p+1);
5564 } else {
5565 ext1 = talloc_strdup(ctx, "");
5567 p = strrchr_m(root2,'.');
5568 if (p) {
5569 *p = 0;
5570 ext2 = talloc_strdup(ctx, p+1);
5571 } else {
5572 ext2 = talloc_strdup(ctx, "");
5575 if (!ext1 || !ext2) {
5576 return False;
5579 p = root1;
5580 p2 = root2;
5581 while (*p2) {
5582 if (*p2 == '?') {
5583 /* Hmmm. Should this be mb-aware ? */
5584 *p2 = *p;
5585 p2++;
5586 } else if (*p2 == '*') {
5587 *p2 = '\0';
5588 root2 = talloc_asprintf(ctx, "%s%s",
5589 root2,
5591 if (!root2) {
5592 return False;
5594 break;
5595 } else {
5596 p2++;
5598 if (*p) {
5599 p++;
5603 p = ext1;
5604 p2 = ext2;
5605 while (*p2) {
5606 if (*p2 == '?') {
5607 /* Hmmm. Should this be mb-aware ? */
5608 *p2 = *p;
5609 p2++;
5610 } else if (*p2 == '*') {
5611 *p2 = '\0';
5612 ext2 = talloc_asprintf(ctx, "%s%s",
5613 ext2,
5615 if (!ext2) {
5616 return False;
5618 break;
5619 } else {
5620 p2++;
5622 if (*p) {
5623 p++;
5627 if (*ext2) {
5628 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
5629 name2_copy,
5630 root2,
5631 ext2);
5632 } else {
5633 *pp_newname = talloc_asprintf(ctx, "%s/%s",
5634 name2_copy,
5635 root2);
5638 if (!*pp_newname) {
5639 return False;
5642 return True;
5645 /****************************************************************************
5646 Ensure open files have their names updated. Updated to notify other smbd's
5647 asynchronously.
5648 ****************************************************************************/
5650 static void rename_open_files(connection_struct *conn,
5651 struct share_mode_lock *lck,
5652 const struct smb_filename *smb_fname_dst)
5654 files_struct *fsp;
5655 bool did_rename = False;
5656 NTSTATUS status;
5658 for(fsp = file_find_di_first(lck->id); fsp;
5659 fsp = file_find_di_next(fsp)) {
5660 /* fsp_name is a relative path under the fsp. To change this for other
5661 sharepaths we need to manipulate relative paths. */
5662 /* TODO - create the absolute path and manipulate the newname
5663 relative to the sharepath. */
5664 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
5665 continue;
5667 DEBUG(10, ("rename_open_files: renaming file fnum %d "
5668 "(file_id %s) from %s -> %s\n", fsp->fnum,
5669 file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp),
5670 smb_fname_str_dbg(smb_fname_dst)));
5672 status = fsp_set_smb_fname(fsp, smb_fname_dst);
5673 if (NT_STATUS_IS_OK(status)) {
5674 did_rename = True;
5678 if (!did_rename) {
5679 DEBUG(10, ("rename_open_files: no open files on file_id %s "
5680 "for %s\n", file_id_string_tos(&lck->id),
5681 smb_fname_str_dbg(smb_fname_dst)));
5684 /* Send messages to all smbd's (not ourself) that the name has changed. */
5685 rename_share_filename(conn->sconn->msg_ctx, lck, conn->connectpath,
5686 smb_fname_dst);
5690 /****************************************************************************
5691 We need to check if the source path is a parent directory of the destination
5692 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
5693 refuse the rename with a sharing violation. Under UNIX the above call can
5694 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
5695 probably need to check that the client is a Windows one before disallowing
5696 this as a UNIX client (one with UNIX extensions) can know the source is a
5697 symlink and make this decision intelligently. Found by an excellent bug
5698 report from <AndyLiebman@aol.com>.
5699 ****************************************************************************/
5701 static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
5702 const struct smb_filename *smb_fname_dst)
5704 const char *psrc = smb_fname_src->base_name;
5705 const char *pdst = smb_fname_dst->base_name;
5706 size_t slen;
5708 if (psrc[0] == '.' && psrc[1] == '/') {
5709 psrc += 2;
5711 if (pdst[0] == '.' && pdst[1] == '/') {
5712 pdst += 2;
5714 if ((slen = strlen(psrc)) > strlen(pdst)) {
5715 return False;
5717 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
5721 * Do the notify calls from a rename
5724 static void notify_rename(connection_struct *conn, bool is_dir,
5725 const struct smb_filename *smb_fname_src,
5726 const struct smb_filename *smb_fname_dst)
5728 char *parent_dir_src = NULL;
5729 char *parent_dir_dst = NULL;
5730 uint32 mask;
5732 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
5733 : FILE_NOTIFY_CHANGE_FILE_NAME;
5735 if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
5736 &parent_dir_src, NULL) ||
5737 !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
5738 &parent_dir_dst, NULL)) {
5739 goto out;
5742 if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
5743 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
5744 smb_fname_src->base_name);
5745 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
5746 smb_fname_dst->base_name);
5748 else {
5749 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
5750 smb_fname_src->base_name);
5751 notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
5752 smb_fname_dst->base_name);
5755 /* this is a strange one. w2k3 gives an additional event for
5756 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
5757 files, but not directories */
5758 if (!is_dir) {
5759 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
5760 FILE_NOTIFY_CHANGE_ATTRIBUTES
5761 |FILE_NOTIFY_CHANGE_CREATION,
5762 smb_fname_dst->base_name);
5764 out:
5765 TALLOC_FREE(parent_dir_src);
5766 TALLOC_FREE(parent_dir_dst);
5769 /****************************************************************************
5770 Rename an open file - given an fsp.
5771 ****************************************************************************/
5773 NTSTATUS rename_internals_fsp(connection_struct *conn,
5774 files_struct *fsp,
5775 const struct smb_filename *smb_fname_dst_in,
5776 uint32 attrs,
5777 bool replace_if_exists)
5779 TALLOC_CTX *ctx = talloc_tos();
5780 struct smb_filename *smb_fname_dst = NULL;
5781 NTSTATUS status = NT_STATUS_OK;
5782 struct share_mode_lock *lck = NULL;
5783 bool dst_exists, old_is_stream, new_is_stream;
5785 status = check_name(conn, smb_fname_dst_in->base_name);
5786 if (!NT_STATUS_IS_OK(status)) {
5787 return status;
5790 /* Make a copy of the dst smb_fname structs */
5792 status = copy_smb_filename(ctx, smb_fname_dst_in, &smb_fname_dst);
5793 if (!NT_STATUS_IS_OK(status)) {
5794 goto out;
5797 /* Ensure the dst smb_fname contains a '/' */
5798 if(strrchr_m(smb_fname_dst->base_name,'/') == 0) {
5799 char * tmp;
5800 tmp = talloc_asprintf(smb_fname_dst, "./%s",
5801 smb_fname_dst->base_name);
5802 if (!tmp) {
5803 status = NT_STATUS_NO_MEMORY;
5804 goto out;
5806 TALLOC_FREE(smb_fname_dst->base_name);
5807 smb_fname_dst->base_name = tmp;
5811 * Check for special case with case preserving and not
5812 * case sensitive. If the old last component differs from the original
5813 * last component only by case, then we should allow
5814 * the rename (user is trying to change the case of the
5815 * filename).
5817 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
5818 strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
5819 strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
5820 char *last_slash;
5821 char *fname_dst_lcomp_base_mod = NULL;
5822 struct smb_filename *smb_fname_orig_lcomp = NULL;
5825 * Get the last component of the destination name. Note that
5826 * we guarantee that destination name contains a '/' character
5827 * above.
5829 last_slash = strrchr_m(smb_fname_dst->base_name, '/');
5830 fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1);
5831 if (!fname_dst_lcomp_base_mod) {
5832 status = NT_STATUS_NO_MEMORY;
5833 goto out;
5837 * Create an smb_filename struct using the original last
5838 * component of the destination.
5840 status = create_synthetic_smb_fname_split(ctx,
5841 smb_fname_dst->original_lcomp, NULL,
5842 &smb_fname_orig_lcomp);
5843 if (!NT_STATUS_IS_OK(status)) {
5844 TALLOC_FREE(fname_dst_lcomp_base_mod);
5845 goto out;
5848 /* If the base names only differ by case, use original. */
5849 if(!strcsequal(fname_dst_lcomp_base_mod,
5850 smb_fname_orig_lcomp->base_name)) {
5851 char *tmp;
5853 * Replace the modified last component with the
5854 * original.
5856 *last_slash = '\0'; /* Truncate at the '/' */
5857 tmp = talloc_asprintf(smb_fname_dst,
5858 "%s/%s",
5859 smb_fname_dst->base_name,
5860 smb_fname_orig_lcomp->base_name);
5861 if (tmp == NULL) {
5862 status = NT_STATUS_NO_MEMORY;
5863 TALLOC_FREE(fname_dst_lcomp_base_mod);
5864 TALLOC_FREE(smb_fname_orig_lcomp);
5865 goto out;
5867 TALLOC_FREE(smb_fname_dst->base_name);
5868 smb_fname_dst->base_name = tmp;
5871 /* If the stream_names only differ by case, use original. */
5872 if(!strcsequal(smb_fname_dst->stream_name,
5873 smb_fname_orig_lcomp->stream_name)) {
5874 char *tmp = NULL;
5875 /* Use the original stream. */
5876 tmp = talloc_strdup(smb_fname_dst,
5877 smb_fname_orig_lcomp->stream_name);
5878 if (tmp == NULL) {
5879 status = NT_STATUS_NO_MEMORY;
5880 TALLOC_FREE(fname_dst_lcomp_base_mod);
5881 TALLOC_FREE(smb_fname_orig_lcomp);
5882 goto out;
5884 TALLOC_FREE(smb_fname_dst->stream_name);
5885 smb_fname_dst->stream_name = tmp;
5887 TALLOC_FREE(fname_dst_lcomp_base_mod);
5888 TALLOC_FREE(smb_fname_orig_lcomp);
5892 * If the src and dest names are identical - including case,
5893 * don't do the rename, just return success.
5896 if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
5897 strcsequal(fsp->fsp_name->stream_name,
5898 smb_fname_dst->stream_name)) {
5899 DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
5900 "- returning success\n",
5901 smb_fname_str_dbg(smb_fname_dst)));
5902 status = NT_STATUS_OK;
5903 goto out;
5906 old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
5907 new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
5909 /* Return the correct error code if both names aren't streams. */
5910 if (!old_is_stream && new_is_stream) {
5911 status = NT_STATUS_OBJECT_NAME_INVALID;
5912 goto out;
5915 if (old_is_stream && !new_is_stream) {
5916 status = NT_STATUS_INVALID_PARAMETER;
5917 goto out;
5920 dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0;
5922 if(!replace_if_exists && dst_exists) {
5923 DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
5924 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
5925 smb_fname_str_dbg(smb_fname_dst)));
5926 status = NT_STATUS_OBJECT_NAME_COLLISION;
5927 goto out;
5930 if (dst_exists) {
5931 struct file_id fileid = vfs_file_id_from_sbuf(conn,
5932 &smb_fname_dst->st);
5933 files_struct *dst_fsp = file_find_di_first(fileid);
5934 /* The file can be open when renaming a stream */
5935 if (dst_fsp && !new_is_stream) {
5936 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
5937 status = NT_STATUS_ACCESS_DENIED;
5938 goto out;
5942 /* Ensure we have a valid stat struct for the source. */
5943 status = vfs_stat_fsp(fsp);
5944 if (!NT_STATUS_IS_OK(status)) {
5945 goto out;
5948 status = can_rename(conn, fsp, attrs);
5950 if (!NT_STATUS_IS_OK(status)) {
5951 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
5952 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
5953 smb_fname_str_dbg(smb_fname_dst)));
5954 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
5955 status = NT_STATUS_ACCESS_DENIED;
5956 goto out;
5959 if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
5960 status = NT_STATUS_ACCESS_DENIED;
5963 lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
5964 NULL);
5967 * We have the file open ourselves, so not being able to get the
5968 * corresponding share mode lock is a fatal error.
5971 SMB_ASSERT(lck != NULL);
5973 if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
5974 uint32 create_options = fsp->fh->private_options;
5976 DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
5977 "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
5978 smb_fname_str_dbg(smb_fname_dst)));
5980 if (lp_map_archive(SNUM(conn)) ||
5981 lp_store_dos_attributes(SNUM(conn))) {
5982 /* We must set the archive bit on the newly
5983 renamed file. */
5984 if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
5985 uint32_t old_dosmode = dos_mode(conn,
5986 smb_fname_dst);
5987 file_set_dosmode(conn,
5988 smb_fname_dst,
5989 old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
5990 NULL,
5991 true);
5995 notify_rename(conn, fsp->is_directory, fsp->fsp_name,
5996 smb_fname_dst);
5998 rename_open_files(conn, lck, smb_fname_dst);
6001 * A rename acts as a new file create w.r.t. allowing an initial delete
6002 * on close, probably because in Windows there is a new handle to the
6003 * new file. If initial delete on close was requested but not
6004 * originally set, we need to set it here. This is probably not 100% correct,
6005 * but will work for the CIFSFS client which in non-posix mode
6006 * depends on these semantics. JRA.
6009 if (create_options & FILE_DELETE_ON_CLOSE) {
6010 status = can_set_delete_on_close(fsp, 0);
6012 if (NT_STATUS_IS_OK(status)) {
6013 /* Note that here we set the *inital* delete on close flag,
6014 * not the regular one. The magic gets handled in close. */
6015 fsp->initial_delete_on_close = True;
6018 TALLOC_FREE(lck);
6019 status = NT_STATUS_OK;
6020 goto out;
6023 TALLOC_FREE(lck);
6025 if (errno == ENOTDIR || errno == EISDIR) {
6026 status = NT_STATUS_OBJECT_NAME_COLLISION;
6027 } else {
6028 status = map_nt_error_from_unix(errno);
6031 DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
6032 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
6033 smb_fname_str_dbg(smb_fname_dst)));
6035 out:
6036 TALLOC_FREE(smb_fname_dst);
6038 return status;
6041 /****************************************************************************
6042 The guts of the rename command, split out so it may be called by the NT SMB
6043 code.
6044 ****************************************************************************/
6046 NTSTATUS rename_internals(TALLOC_CTX *ctx,
6047 connection_struct *conn,
6048 struct smb_request *req,
6049 struct smb_filename *smb_fname_src,
6050 struct smb_filename *smb_fname_dst,
6051 uint32 attrs,
6052 bool replace_if_exists,
6053 bool src_has_wild,
6054 bool dest_has_wild,
6055 uint32_t access_mask)
6057 char *fname_src_dir = NULL;
6058 char *fname_src_mask = NULL;
6059 int count=0;
6060 NTSTATUS status = NT_STATUS_OK;
6061 struct smb_Dir *dir_hnd = NULL;
6062 const char *dname = NULL;
6063 char *talloced = NULL;
6064 long offset = 0;
6065 int create_options = 0;
6066 bool posix_pathnames = lp_posix_pathnames();
6069 * Split the old name into directory and last component
6070 * strings. Note that unix_convert may have stripped off a
6071 * leading ./ from both name and newname if the rename is
6072 * at the root of the share. We need to make sure either both
6073 * name and newname contain a / character or neither of them do
6074 * as this is checked in resolve_wildcards().
6077 /* Split up the directory from the filename/mask. */
6078 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6079 &fname_src_dir, &fname_src_mask);
6080 if (!NT_STATUS_IS_OK(status)) {
6081 status = NT_STATUS_NO_MEMORY;
6082 goto out;
6086 * We should only check the mangled cache
6087 * here if unix_convert failed. This means
6088 * that the path in 'mask' doesn't exist
6089 * on the file system and so we need to look
6090 * for a possible mangle. This patch from
6091 * Tine Smukavec <valentin.smukavec@hermes.si>.
6094 if (!VALID_STAT(smb_fname_src->st) &&
6095 mangle_is_mangled(fname_src_mask, conn->params)) {
6096 char *new_mask = NULL;
6097 mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask,
6098 conn->params);
6099 if (new_mask) {
6100 TALLOC_FREE(fname_src_mask);
6101 fname_src_mask = new_mask;
6105 if (!src_has_wild) {
6106 files_struct *fsp;
6109 * Only one file needs to be renamed. Append the mask back
6110 * onto the directory.
6112 TALLOC_FREE(smb_fname_src->base_name);
6113 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6114 "%s/%s",
6115 fname_src_dir,
6116 fname_src_mask);
6117 if (!smb_fname_src->base_name) {
6118 status = NT_STATUS_NO_MEMORY;
6119 goto out;
6122 /* Ensure dst fname contains a '/' also */
6123 if(strrchr_m(smb_fname_dst->base_name, '/') == 0) {
6124 char *tmp;
6125 tmp = talloc_asprintf(smb_fname_dst, "./%s",
6126 smb_fname_dst->base_name);
6127 if (!tmp) {
6128 status = NT_STATUS_NO_MEMORY;
6129 goto out;
6131 TALLOC_FREE(smb_fname_dst->base_name);
6132 smb_fname_dst->base_name = tmp;
6135 DEBUG(3, ("rename_internals: case_sensitive = %d, "
6136 "case_preserve = %d, short case preserve = %d, "
6137 "directory = %s, newname = %s, "
6138 "last_component_dest = %s\n",
6139 conn->case_sensitive, conn->case_preserve,
6140 conn->short_case_preserve,
6141 smb_fname_str_dbg(smb_fname_src),
6142 smb_fname_str_dbg(smb_fname_dst),
6143 smb_fname_dst->original_lcomp));
6145 /* The dest name still may have wildcards. */
6146 if (dest_has_wild) {
6147 char *fname_dst_mod = NULL;
6148 if (!resolve_wildcards(smb_fname_dst,
6149 smb_fname_src->base_name,
6150 smb_fname_dst->base_name,
6151 &fname_dst_mod)) {
6152 DEBUG(6, ("rename_internals: resolve_wildcards "
6153 "%s %s failed\n",
6154 smb_fname_src->base_name,
6155 smb_fname_dst->base_name));
6156 status = NT_STATUS_NO_MEMORY;
6157 goto out;
6159 TALLOC_FREE(smb_fname_dst->base_name);
6160 smb_fname_dst->base_name = fname_dst_mod;
6163 ZERO_STRUCT(smb_fname_src->st);
6164 if (posix_pathnames) {
6165 SMB_VFS_LSTAT(conn, smb_fname_src);
6166 } else {
6167 SMB_VFS_STAT(conn, smb_fname_src);
6170 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6171 create_options |= FILE_DIRECTORY_FILE;
6174 status = SMB_VFS_CREATE_FILE(
6175 conn, /* conn */
6176 req, /* req */
6177 0, /* root_dir_fid */
6178 smb_fname_src, /* fname */
6179 access_mask, /* access_mask */
6180 (FILE_SHARE_READ | /* share_access */
6181 FILE_SHARE_WRITE),
6182 FILE_OPEN, /* create_disposition*/
6183 create_options, /* create_options */
6184 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6185 0, /* oplock_request */
6186 0, /* allocation_size */
6187 0, /* private_flags */
6188 NULL, /* sd */
6189 NULL, /* ea_list */
6190 &fsp, /* result */
6191 NULL); /* pinfo */
6193 if (!NT_STATUS_IS_OK(status)) {
6194 DEBUG(3, ("Could not open rename source %s: %s\n",
6195 smb_fname_str_dbg(smb_fname_src),
6196 nt_errstr(status)));
6197 goto out;
6200 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6201 attrs, replace_if_exists);
6203 close_file(req, fsp, NORMAL_CLOSE);
6205 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
6206 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
6207 smb_fname_str_dbg(smb_fname_dst)));
6209 goto out;
6213 * Wildcards - process each file that matches.
6215 if (strequal(fname_src_mask, "????????.???")) {
6216 TALLOC_FREE(fname_src_mask);
6217 fname_src_mask = talloc_strdup(ctx, "*");
6218 if (!fname_src_mask) {
6219 status = NT_STATUS_NO_MEMORY;
6220 goto out;
6224 status = check_name(conn, fname_src_dir);
6225 if (!NT_STATUS_IS_OK(status)) {
6226 goto out;
6229 dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask,
6230 attrs);
6231 if (dir_hnd == NULL) {
6232 status = map_nt_error_from_unix(errno);
6233 goto out;
6236 status = NT_STATUS_NO_SUCH_FILE;
6238 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
6239 * - gentest fix. JRA
6242 while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
6243 &talloced))) {
6244 files_struct *fsp = NULL;
6245 char *destname = NULL;
6246 bool sysdir_entry = False;
6248 /* Quick check for "." and ".." */
6249 if (ISDOT(dname) || ISDOTDOT(dname)) {
6250 if (attrs & aDIR) {
6251 sysdir_entry = True;
6252 } else {
6253 TALLOC_FREE(talloced);
6254 continue;
6258 if (!is_visible_file(conn, fname_src_dir, dname,
6259 &smb_fname_src->st, false)) {
6260 TALLOC_FREE(talloced);
6261 continue;
6264 if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
6265 TALLOC_FREE(talloced);
6266 continue;
6269 if (sysdir_entry) {
6270 status = NT_STATUS_OBJECT_NAME_INVALID;
6271 break;
6274 TALLOC_FREE(smb_fname_src->base_name);
6275 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6276 "%s/%s",
6277 fname_src_dir,
6278 dname);
6279 if (!smb_fname_src->base_name) {
6280 status = NT_STATUS_NO_MEMORY;
6281 goto out;
6284 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6285 smb_fname_dst->base_name,
6286 &destname)) {
6287 DEBUG(6, ("resolve_wildcards %s %s failed\n",
6288 smb_fname_src->base_name, destname));
6289 TALLOC_FREE(talloced);
6290 continue;
6292 if (!destname) {
6293 status = NT_STATUS_NO_MEMORY;
6294 goto out;
6297 TALLOC_FREE(smb_fname_dst->base_name);
6298 smb_fname_dst->base_name = destname;
6300 ZERO_STRUCT(smb_fname_src->st);
6301 if (posix_pathnames) {
6302 SMB_VFS_LSTAT(conn, smb_fname_src);
6303 } else {
6304 SMB_VFS_STAT(conn, smb_fname_src);
6307 create_options = 0;
6309 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
6310 create_options |= FILE_DIRECTORY_FILE;
6313 status = SMB_VFS_CREATE_FILE(
6314 conn, /* conn */
6315 req, /* req */
6316 0, /* root_dir_fid */
6317 smb_fname_src, /* fname */
6318 access_mask, /* access_mask */
6319 (FILE_SHARE_READ | /* share_access */
6320 FILE_SHARE_WRITE),
6321 FILE_OPEN, /* create_disposition*/
6322 create_options, /* create_options */
6323 posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
6324 0, /* oplock_request */
6325 0, /* allocation_size */
6326 0, /* private_flags */
6327 NULL, /* sd */
6328 NULL, /* ea_list */
6329 &fsp, /* result */
6330 NULL); /* pinfo */
6332 if (!NT_STATUS_IS_OK(status)) {
6333 DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
6334 "returned %s rename %s -> %s\n",
6335 nt_errstr(status),
6336 smb_fname_str_dbg(smb_fname_src),
6337 smb_fname_str_dbg(smb_fname_dst)));
6338 break;
6341 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6342 dname);
6343 if (!smb_fname_dst->original_lcomp) {
6344 status = NT_STATUS_NO_MEMORY;
6345 goto out;
6348 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6349 attrs, replace_if_exists);
6351 close_file(req, fsp, NORMAL_CLOSE);
6353 if (!NT_STATUS_IS_OK(status)) {
6354 DEBUG(3, ("rename_internals_fsp returned %s for "
6355 "rename %s -> %s\n", nt_errstr(status),
6356 smb_fname_str_dbg(smb_fname_src),
6357 smb_fname_str_dbg(smb_fname_dst)));
6358 break;
6361 count++;
6363 DEBUG(3,("rename_internals: doing rename on %s -> "
6364 "%s\n", smb_fname_str_dbg(smb_fname_src),
6365 smb_fname_str_dbg(smb_fname_src)));
6366 TALLOC_FREE(talloced);
6368 TALLOC_FREE(dir_hnd);
6370 if (count == 0 && NT_STATUS_IS_OK(status) && errno != 0) {
6371 status = map_nt_error_from_unix(errno);
6374 out:
6375 TALLOC_FREE(talloced);
6376 TALLOC_FREE(fname_src_dir);
6377 TALLOC_FREE(fname_src_mask);
6378 return status;
6381 /****************************************************************************
6382 Reply to a mv.
6383 ****************************************************************************/
6385 void reply_mv(struct smb_request *req)
6387 connection_struct *conn = req->conn;
6388 char *name = NULL;
6389 char *newname = NULL;
6390 const char *p;
6391 uint32 attrs;
6392 NTSTATUS status;
6393 bool src_has_wcard = False;
6394 bool dest_has_wcard = False;
6395 TALLOC_CTX *ctx = talloc_tos();
6396 struct smb_filename *smb_fname_src = NULL;
6397 struct smb_filename *smb_fname_dst = NULL;
6399 START_PROFILE(SMBmv);
6401 if (req->wct < 1) {
6402 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6403 goto out;
6406 attrs = SVAL(req->vwv+0, 0);
6408 p = (const char *)req->buf + 1;
6409 p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE,
6410 &status, &src_has_wcard);
6411 if (!NT_STATUS_IS_OK(status)) {
6412 reply_nterror(req, status);
6413 goto out;
6415 p++;
6416 p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
6417 &status, &dest_has_wcard);
6418 if (!NT_STATUS_IS_OK(status)) {
6419 reply_nterror(req, status);
6420 goto out;
6423 status = filename_convert(ctx,
6424 conn,
6425 req->flags2 & FLAGS2_DFS_PATHNAMES,
6426 name,
6427 UCF_COND_ALLOW_WCARD_LCOMP,
6428 &src_has_wcard,
6429 &smb_fname_src);
6431 if (!NT_STATUS_IS_OK(status)) {
6432 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6433 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6434 ERRSRV, ERRbadpath);
6435 goto out;
6437 reply_nterror(req, status);
6438 goto out;
6441 status = filename_convert(ctx,
6442 conn,
6443 req->flags2 & FLAGS2_DFS_PATHNAMES,
6444 newname,
6445 UCF_COND_ALLOW_WCARD_LCOMP | UCF_SAVE_LCOMP,
6446 &dest_has_wcard,
6447 &smb_fname_dst);
6449 if (!NT_STATUS_IS_OK(status)) {
6450 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6451 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6452 ERRSRV, ERRbadpath);
6453 goto out;
6455 reply_nterror(req, status);
6456 goto out;
6459 DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src),
6460 smb_fname_str_dbg(smb_fname_dst)));
6462 status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst,
6463 attrs, False, src_has_wcard, dest_has_wcard,
6464 DELETE_ACCESS);
6465 if (!NT_STATUS_IS_OK(status)) {
6466 if (open_was_deferred(req->mid)) {
6467 /* We have re-scheduled this call. */
6468 goto out;
6470 reply_nterror(req, status);
6471 goto out;
6474 reply_outbuf(req, 0, 0);
6475 out:
6476 TALLOC_FREE(smb_fname_src);
6477 TALLOC_FREE(smb_fname_dst);
6478 END_PROFILE(SMBmv);
6479 return;
6482 /*******************************************************************
6483 Copy a file as part of a reply_copy.
6484 ******************************************************************/
6487 * TODO: check error codes on all callers
6490 NTSTATUS copy_file(TALLOC_CTX *ctx,
6491 connection_struct *conn,
6492 struct smb_filename *smb_fname_src,
6493 struct smb_filename *smb_fname_dst,
6494 int ofun,
6495 int count,
6496 bool target_is_directory)
6498 struct smb_filename *smb_fname_dst_tmp = NULL;
6499 SMB_OFF_T ret=-1;
6500 files_struct *fsp1,*fsp2;
6501 uint32 dosattrs;
6502 uint32 new_create_disposition;
6503 NTSTATUS status;
6506 status = copy_smb_filename(ctx, smb_fname_dst, &smb_fname_dst_tmp);
6507 if (!NT_STATUS_IS_OK(status)) {
6508 return status;
6512 * If the target is a directory, extract the last component from the
6513 * src filename and append it to the dst filename
6515 if (target_is_directory) {
6516 const char *p;
6518 /* dest/target can't be a stream if it's a directory. */
6519 SMB_ASSERT(smb_fname_dst->stream_name == NULL);
6521 p = strrchr_m(smb_fname_src->base_name,'/');
6522 if (p) {
6523 p++;
6524 } else {
6525 p = smb_fname_src->base_name;
6527 smb_fname_dst_tmp->base_name =
6528 talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
6530 if (!smb_fname_dst_tmp->base_name) {
6531 status = NT_STATUS_NO_MEMORY;
6532 goto out;
6536 status = vfs_file_exist(conn, smb_fname_src);
6537 if (!NT_STATUS_IS_OK(status)) {
6538 goto out;
6541 if (!target_is_directory && count) {
6542 new_create_disposition = FILE_OPEN;
6543 } else {
6544 if (!map_open_params_to_ntcreate(smb_fname_dst_tmp, 0, ofun,
6545 NULL, NULL,
6546 &new_create_disposition,
6547 NULL,
6548 NULL)) {
6549 status = NT_STATUS_INVALID_PARAMETER;
6550 goto out;
6554 /* Open the src file for reading. */
6555 status = SMB_VFS_CREATE_FILE(
6556 conn, /* conn */
6557 NULL, /* req */
6558 0, /* root_dir_fid */
6559 smb_fname_src, /* fname */
6560 FILE_GENERIC_READ, /* access_mask */
6561 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6562 FILE_OPEN, /* create_disposition*/
6563 0, /* create_options */
6564 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
6565 INTERNAL_OPEN_ONLY, /* oplock_request */
6566 0, /* allocation_size */
6567 0, /* private_flags */
6568 NULL, /* sd */
6569 NULL, /* ea_list */
6570 &fsp1, /* result */
6571 NULL); /* psbuf */
6573 if (!NT_STATUS_IS_OK(status)) {
6574 goto out;
6577 dosattrs = dos_mode(conn, smb_fname_src);
6579 if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
6580 ZERO_STRUCTP(&smb_fname_dst_tmp->st);
6583 /* Open the dst file for writing. */
6584 status = SMB_VFS_CREATE_FILE(
6585 conn, /* conn */
6586 NULL, /* req */
6587 0, /* root_dir_fid */
6588 smb_fname_dst, /* fname */
6589 FILE_GENERIC_WRITE, /* access_mask */
6590 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
6591 new_create_disposition, /* create_disposition*/
6592 0, /* create_options */
6593 dosattrs, /* file_attributes */
6594 INTERNAL_OPEN_ONLY, /* oplock_request */
6595 0, /* allocation_size */
6596 0, /* private_flags */
6597 NULL, /* sd */
6598 NULL, /* ea_list */
6599 &fsp2, /* result */
6600 NULL); /* psbuf */
6602 if (!NT_STATUS_IS_OK(status)) {
6603 close_file(NULL, fsp1, ERROR_CLOSE);
6604 goto out;
6607 if ((ofun&3) == 1) {
6608 if(SMB_VFS_LSEEK(fsp2,0,SEEK_END) == -1) {
6609 DEBUG(0,("copy_file: error - vfs lseek returned error %s\n", strerror(errno) ));
6611 * Stop the copy from occurring.
6613 ret = -1;
6614 smb_fname_src->st.st_ex_size = 0;
6618 /* Do the actual copy. */
6619 if (smb_fname_src->st.st_ex_size) {
6620 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
6623 close_file(NULL, fsp1, NORMAL_CLOSE);
6625 /* Ensure the modtime is set correctly on the destination file. */
6626 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
6629 * As we are opening fsp1 read-only we only expect
6630 * an error on close on fsp2 if we are out of space.
6631 * Thus we don't look at the error return from the
6632 * close of fsp1.
6634 status = close_file(NULL, fsp2, NORMAL_CLOSE);
6636 if (!NT_STATUS_IS_OK(status)) {
6637 goto out;
6640 if (ret != (SMB_OFF_T)smb_fname_src->st.st_ex_size) {
6641 status = NT_STATUS_DISK_FULL;
6642 goto out;
6645 status = NT_STATUS_OK;
6647 out:
6648 TALLOC_FREE(smb_fname_dst_tmp);
6649 return status;
6652 /****************************************************************************
6653 Reply to a file copy.
6654 ****************************************************************************/
6656 void reply_copy(struct smb_request *req)
6658 connection_struct *conn = req->conn;
6659 struct smb_filename *smb_fname_src = NULL;
6660 struct smb_filename *smb_fname_dst = NULL;
6661 char *fname_src = NULL;
6662 char *fname_dst = NULL;
6663 char *fname_src_mask = NULL;
6664 char *fname_src_dir = NULL;
6665 const char *p;
6666 int count=0;
6667 int error = ERRnoaccess;
6668 int tid2;
6669 int ofun;
6670 int flags;
6671 bool target_is_directory=False;
6672 bool source_has_wild = False;
6673 bool dest_has_wild = False;
6674 NTSTATUS status;
6675 TALLOC_CTX *ctx = talloc_tos();
6677 START_PROFILE(SMBcopy);
6679 if (req->wct < 3) {
6680 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6681 goto out;
6684 tid2 = SVAL(req->vwv+0, 0);
6685 ofun = SVAL(req->vwv+1, 0);
6686 flags = SVAL(req->vwv+2, 0);
6688 p = (const char *)req->buf;
6689 p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE,
6690 &status, &source_has_wild);
6691 if (!NT_STATUS_IS_OK(status)) {
6692 reply_nterror(req, status);
6693 goto out;
6695 p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE,
6696 &status, &dest_has_wild);
6697 if (!NT_STATUS_IS_OK(status)) {
6698 reply_nterror(req, status);
6699 goto out;
6702 DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst));
6704 if (tid2 != conn->cnum) {
6705 /* can't currently handle inter share copies XXXX */
6706 DEBUG(3,("Rejecting inter-share copy\n"));
6707 reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
6708 goto out;
6711 status = filename_convert(ctx, conn,
6712 req->flags2 & FLAGS2_DFS_PATHNAMES,
6713 fname_src,
6714 UCF_COND_ALLOW_WCARD_LCOMP,
6715 &source_has_wild,
6716 &smb_fname_src);
6717 if (!NT_STATUS_IS_OK(status)) {
6718 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6719 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6720 ERRSRV, ERRbadpath);
6721 goto out;
6723 reply_nterror(req, status);
6724 goto out;
6727 status = filename_convert(ctx, conn,
6728 req->flags2 & FLAGS2_DFS_PATHNAMES,
6729 fname_dst,
6730 UCF_COND_ALLOW_WCARD_LCOMP,
6731 &dest_has_wild,
6732 &smb_fname_dst);
6733 if (!NT_STATUS_IS_OK(status)) {
6734 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6735 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6736 ERRSRV, ERRbadpath);
6737 goto out;
6739 reply_nterror(req, status);
6740 goto out;
6743 target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
6745 if ((flags&1) && target_is_directory) {
6746 reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
6747 goto out;
6750 if ((flags&2) && !target_is_directory) {
6751 reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
6752 goto out;
6755 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
6756 /* wants a tree copy! XXXX */
6757 DEBUG(3,("Rejecting tree copy\n"));
6758 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6759 goto out;
6762 /* Split up the directory from the filename/mask. */
6763 status = split_fname_dir_mask(ctx, smb_fname_src->base_name,
6764 &fname_src_dir, &fname_src_mask);
6765 if (!NT_STATUS_IS_OK(status)) {
6766 reply_nterror(req, NT_STATUS_NO_MEMORY);
6767 goto out;
6771 * We should only check the mangled cache
6772 * here if unix_convert failed. This means
6773 * that the path in 'mask' doesn't exist
6774 * on the file system and so we need to look
6775 * for a possible mangle. This patch from
6776 * Tine Smukavec <valentin.smukavec@hermes.si>.
6778 if (!VALID_STAT(smb_fname_src->st) &&
6779 mangle_is_mangled(fname_src_mask, conn->params)) {
6780 char *new_mask = NULL;
6781 mangle_lookup_name_from_8_3(ctx, fname_src_mask,
6782 &new_mask, conn->params);
6784 /* Use demangled name if one was successfully found. */
6785 if (new_mask) {
6786 TALLOC_FREE(fname_src_mask);
6787 fname_src_mask = new_mask;
6791 if (!source_has_wild) {
6794 * Only one file needs to be copied. Append the mask back onto
6795 * the directory.
6797 TALLOC_FREE(smb_fname_src->base_name);
6798 smb_fname_src->base_name = talloc_asprintf(smb_fname_src,
6799 "%s/%s",
6800 fname_src_dir,
6801 fname_src_mask);
6802 if (!smb_fname_src->base_name) {
6803 reply_nterror(req, NT_STATUS_NO_MEMORY);
6804 goto out;
6807 if (dest_has_wild) {
6808 char *fname_dst_mod = NULL;
6809 if (!resolve_wildcards(smb_fname_dst,
6810 smb_fname_src->base_name,
6811 smb_fname_dst->base_name,
6812 &fname_dst_mod)) {
6813 reply_nterror(req, NT_STATUS_NO_MEMORY);
6814 goto out;
6816 TALLOC_FREE(smb_fname_dst->base_name);
6817 smb_fname_dst->base_name = fname_dst_mod;
6820 status = check_name(conn, smb_fname_src->base_name);
6821 if (!NT_STATUS_IS_OK(status)) {
6822 reply_nterror(req, status);
6823 goto out;
6826 status = check_name(conn, smb_fname_dst->base_name);
6827 if (!NT_STATUS_IS_OK(status)) {
6828 reply_nterror(req, status);
6829 goto out;
6832 status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst,
6833 ofun, count, target_is_directory);
6835 if(!NT_STATUS_IS_OK(status)) {
6836 reply_nterror(req, status);
6837 goto out;
6838 } else {
6839 count++;
6841 } else {
6842 struct smb_Dir *dir_hnd = NULL;
6843 const char *dname = NULL;
6844 char *talloced = NULL;
6845 long offset = 0;
6848 * There is a wildcard that requires us to actually read the
6849 * src dir and copy each file matching the mask to the dst.
6850 * Right now streams won't be copied, but this could
6851 * presumably be added with a nested loop for reach dir entry.
6853 SMB_ASSERT(!smb_fname_src->stream_name);
6854 SMB_ASSERT(!smb_fname_dst->stream_name);
6856 smb_fname_src->stream_name = NULL;
6857 smb_fname_dst->stream_name = NULL;
6859 if (strequal(fname_src_mask,"????????.???")) {
6860 TALLOC_FREE(fname_src_mask);
6861 fname_src_mask = talloc_strdup(ctx, "*");
6862 if (!fname_src_mask) {
6863 reply_nterror(req, NT_STATUS_NO_MEMORY);
6864 goto out;
6868 status = check_name(conn, fname_src_dir);
6869 if (!NT_STATUS_IS_OK(status)) {
6870 reply_nterror(req, status);
6871 goto out;
6874 dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0);
6875 if (dir_hnd == NULL) {
6876 status = map_nt_error_from_unix(errno);
6877 reply_nterror(req, status);
6878 goto out;
6881 error = ERRbadfile;
6883 /* Iterate over the src dir copying each entry to the dst. */
6884 while ((dname = ReadDirName(dir_hnd, &offset,
6885 &smb_fname_src->st, &talloced))) {
6886 char *destname = NULL;
6888 if (ISDOT(dname) || ISDOTDOT(dname)) {
6889 TALLOC_FREE(talloced);
6890 continue;
6893 if (!is_visible_file(conn, fname_src_dir, dname,
6894 &smb_fname_src->st, false)) {
6895 TALLOC_FREE(talloced);
6896 continue;
6899 if(!mask_match(dname, fname_src_mask,
6900 conn->case_sensitive)) {
6901 TALLOC_FREE(talloced);
6902 continue;
6905 error = ERRnoaccess;
6907 /* Get the src smb_fname struct setup. */
6908 TALLOC_FREE(smb_fname_src->base_name);
6909 smb_fname_src->base_name =
6910 talloc_asprintf(smb_fname_src, "%s/%s",
6911 fname_src_dir, dname);
6913 if (!smb_fname_src->base_name) {
6914 TALLOC_FREE(dir_hnd);
6915 TALLOC_FREE(talloced);
6916 reply_nterror(req, NT_STATUS_NO_MEMORY);
6917 goto out;
6920 if (!resolve_wildcards(ctx, smb_fname_src->base_name,
6921 smb_fname_dst->base_name,
6922 &destname)) {
6923 TALLOC_FREE(talloced);
6924 continue;
6926 if (!destname) {
6927 TALLOC_FREE(dir_hnd);
6928 TALLOC_FREE(talloced);
6929 reply_nterror(req, NT_STATUS_NO_MEMORY);
6930 goto out;
6933 TALLOC_FREE(smb_fname_dst->base_name);
6934 smb_fname_dst->base_name = destname;
6936 status = check_name(conn, smb_fname_src->base_name);
6937 if (!NT_STATUS_IS_OK(status)) {
6938 TALLOC_FREE(dir_hnd);
6939 TALLOC_FREE(talloced);
6940 reply_nterror(req, status);
6941 goto out;
6944 status = check_name(conn, smb_fname_dst->base_name);
6945 if (!NT_STATUS_IS_OK(status)) {
6946 TALLOC_FREE(dir_hnd);
6947 TALLOC_FREE(talloced);
6948 reply_nterror(req, status);
6949 goto out;
6952 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",
6953 smb_fname_src->base_name,
6954 smb_fname_dst->base_name));
6956 status = copy_file(ctx, conn, smb_fname_src,
6957 smb_fname_dst, ofun, count,
6958 target_is_directory);
6959 if (NT_STATUS_IS_OK(status)) {
6960 count++;
6963 TALLOC_FREE(talloced);
6965 TALLOC_FREE(dir_hnd);
6968 if (count == 0) {
6969 reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
6970 goto out;
6973 reply_outbuf(req, 1, 0);
6974 SSVAL(req->outbuf,smb_vwv0,count);
6975 out:
6976 TALLOC_FREE(smb_fname_src);
6977 TALLOC_FREE(smb_fname_dst);
6978 TALLOC_FREE(fname_src);
6979 TALLOC_FREE(fname_dst);
6980 TALLOC_FREE(fname_src_mask);
6981 TALLOC_FREE(fname_src_dir);
6983 END_PROFILE(SMBcopy);
6984 return;
6987 #undef DBGC_CLASS
6988 #define DBGC_CLASS DBGC_LOCKING
6990 /****************************************************************************
6991 Get a lock pid, dealing with large count requests.
6992 ****************************************************************************/
6994 uint64_t get_lock_pid(const uint8_t *data, int data_offset,
6995 bool large_file_format)
6997 if(!large_file_format)
6998 return (uint64_t)SVAL(data,SMB_LPID_OFFSET(data_offset));
6999 else
7000 return (uint64_t)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
7003 /****************************************************************************
7004 Get a lock count, dealing with large count requests.
7005 ****************************************************************************/
7007 uint64_t get_lock_count(const uint8_t *data, int data_offset,
7008 bool large_file_format)
7010 uint64_t count = 0;
7012 if(!large_file_format) {
7013 count = (uint64_t)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
7014 } else {
7016 #if defined(HAVE_LONGLONG)
7017 count = (((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
7018 ((uint64_t) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
7019 #else /* HAVE_LONGLONG */
7022 * NT4.x seems to be broken in that it sends large file (64 bit)
7023 * lockingX calls even if the CAP_LARGE_FILES was *not*
7024 * negotiated. For boxes without large unsigned ints truncate the
7025 * lock count by dropping the top 32 bits.
7028 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
7029 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
7030 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
7031 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
7032 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
7035 count = (uint64_t)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
7036 #endif /* HAVE_LONGLONG */
7039 return count;
7042 #if !defined(HAVE_LONGLONG)
7043 /****************************************************************************
7044 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
7045 ****************************************************************************/
7047 static uint32 map_lock_offset(uint32 high, uint32 low)
7049 unsigned int i;
7050 uint32 mask = 0;
7051 uint32 highcopy = high;
7054 * Try and find out how many significant bits there are in high.
7057 for(i = 0; highcopy; i++)
7058 highcopy >>= 1;
7061 * We use 31 bits not 32 here as POSIX
7062 * lock offsets may not be negative.
7065 mask = (~0) << (31 - i);
7067 if(low & mask)
7068 return 0; /* Fail. */
7070 high <<= (31 - i);
7072 return (high|low);
7074 #endif /* !defined(HAVE_LONGLONG) */
7076 /****************************************************************************
7077 Get a lock offset, dealing with large offset requests.
7078 ****************************************************************************/
7080 uint64_t get_lock_offset(const uint8_t *data, int data_offset,
7081 bool large_file_format, bool *err)
7083 uint64_t offset = 0;
7085 *err = False;
7087 if(!large_file_format) {
7088 offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
7089 } else {
7091 #if defined(HAVE_LONGLONG)
7092 offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
7093 ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
7094 #else /* HAVE_LONGLONG */
7097 * NT4.x seems to be broken in that it sends large file (64 bit)
7098 * lockingX calls even if the CAP_LARGE_FILES was *not*
7099 * negotiated. For boxes without large unsigned ints mangle the
7100 * lock offset by mapping the top 32 bits onto the lower 32.
7103 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
7104 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7105 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
7106 uint32 new_low = 0;
7108 if((new_low = map_lock_offset(high, low)) == 0) {
7109 *err = True;
7110 return (uint64_t)-1;
7113 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
7114 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
7115 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
7116 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
7119 offset = (uint64_t)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
7120 #endif /* HAVE_LONGLONG */
7123 return offset;
7126 NTSTATUS smbd_do_locking(struct smb_request *req,
7127 files_struct *fsp,
7128 uint8_t type,
7129 int32_t timeout,
7130 uint16_t num_ulocks,
7131 struct smbd_lock_element *ulocks,
7132 uint16_t num_locks,
7133 struct smbd_lock_element *locks,
7134 bool *async)
7136 connection_struct *conn = req->conn;
7137 int i;
7138 NTSTATUS status = NT_STATUS_OK;
7140 *async = false;
7142 /* Data now points at the beginning of the list
7143 of smb_unlkrng structs */
7144 for(i = 0; i < (int)num_ulocks; i++) {
7145 struct smbd_lock_element *e = &ulocks[i];
7147 DEBUG(10,("smbd_do_locking: unlock start=%.0f, len=%.0f for "
7148 "pid %u, file %s\n",
7149 (double)e->offset,
7150 (double)e->count,
7151 (unsigned int)e->smblctx,
7152 fsp_str_dbg(fsp)));
7154 if (e->brltype != UNLOCK_LOCK) {
7155 /* this can only happen with SMB2 */
7156 return NT_STATUS_INVALID_PARAMETER;
7159 status = do_unlock(req->sconn->msg_ctx,
7160 fsp,
7161 e->smblctx,
7162 e->count,
7163 e->offset,
7164 WINDOWS_LOCK);
7166 DEBUG(10, ("smbd_do_locking: unlock returned %s\n",
7167 nt_errstr(status)));
7169 if (!NT_STATUS_IS_OK(status)) {
7170 return status;
7174 /* Setup the timeout in seconds. */
7176 if (!lp_blocking_locks(SNUM(conn))) {
7177 timeout = 0;
7180 /* Data now points at the beginning of the list
7181 of smb_lkrng structs */
7183 for(i = 0; i < (int)num_locks; i++) {
7184 struct smbd_lock_element *e = &locks[i];
7186 DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for smblctx "
7187 "%llu, file %s timeout = %d\n",
7188 (double)e->offset,
7189 (double)e->count,
7190 (unsigned long long)e->smblctx,
7191 fsp_str_dbg(fsp),
7192 (int)timeout));
7194 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7195 struct blocking_lock_record *blr = NULL;
7197 if (num_locks > 1) {
7199 * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
7200 * if the lock vector contains one entry. When given mutliple cancel
7201 * requests in a single PDU we expect the server to return an
7202 * error. Windows servers seem to accept the request but only
7203 * cancel the first lock.
7204 * JRA - Do what Windows does (tm) :-).
7207 #if 0
7208 /* MS-CIFS (2.2.4.32.1) behavior. */
7209 return NT_STATUS_DOS(ERRDOS,
7210 ERRcancelviolation);
7211 #else
7212 /* Windows behavior. */
7213 if (i != 0) {
7214 DEBUG(10,("smbd_do_locking: ignoring subsequent "
7215 "cancel request\n"));
7216 continue;
7218 #endif
7221 if (lp_blocking_locks(SNUM(conn))) {
7223 /* Schedule a message to ourselves to
7224 remove the blocking lock record and
7225 return the right error. */
7227 blr = blocking_lock_cancel_smb1(fsp,
7228 e->smblctx,
7229 e->offset,
7230 e->count,
7231 WINDOWS_LOCK,
7232 type,
7233 NT_STATUS_FILE_LOCK_CONFLICT);
7234 if (blr == NULL) {
7235 return NT_STATUS_DOS(
7236 ERRDOS,
7237 ERRcancelviolation);
7240 /* Remove a matching pending lock. */
7241 status = do_lock_cancel(fsp,
7242 e->smblctx,
7243 e->count,
7244 e->offset,
7245 WINDOWS_LOCK,
7246 blr);
7247 } else {
7248 bool blocking_lock = timeout ? true : false;
7249 bool defer_lock = false;
7250 struct byte_range_lock *br_lck;
7251 uint64_t block_smblctx;
7253 br_lck = do_lock(req->sconn->msg_ctx,
7254 fsp,
7255 e->smblctx,
7256 e->count,
7257 e->offset,
7258 e->brltype,
7259 WINDOWS_LOCK,
7260 blocking_lock,
7261 &status,
7262 &block_smblctx,
7263 NULL);
7265 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
7266 /* Windows internal resolution for blocking locks seems
7267 to be about 200ms... Don't wait for less than that. JRA. */
7268 if (timeout != -1 && timeout < lp_lock_spin_time()) {
7269 timeout = lp_lock_spin_time();
7271 defer_lock = true;
7274 /* If a lock sent with timeout of zero would fail, and
7275 * this lock has been requested multiple times,
7276 * according to brl_lock_failed() we convert this
7277 * request to a blocking lock with a timeout of between
7278 * 150 - 300 milliseconds.
7280 * If lp_lock_spin_time() has been set to 0, we skip
7281 * this blocking retry and fail immediately.
7283 * Replacement for do_lock_spin(). JRA. */
7285 if (!req->sconn->using_smb2 &&
7286 br_lck && lp_blocking_locks(SNUM(conn)) &&
7287 lp_lock_spin_time() && !blocking_lock &&
7288 NT_STATUS_EQUAL((status),
7289 NT_STATUS_FILE_LOCK_CONFLICT))
7291 defer_lock = true;
7292 timeout = lp_lock_spin_time();
7295 if (br_lck && defer_lock) {
7297 * A blocking lock was requested. Package up
7298 * this smb into a queued request and push it
7299 * onto the blocking lock queue.
7301 if(push_blocking_lock_request(br_lck,
7302 req,
7303 fsp,
7304 timeout,
7306 e->smblctx,
7307 e->brltype,
7308 WINDOWS_LOCK,
7309 e->offset,
7310 e->count,
7311 block_smblctx)) {
7312 TALLOC_FREE(br_lck);
7313 *async = true;
7314 return NT_STATUS_OK;
7318 TALLOC_FREE(br_lck);
7321 if (!NT_STATUS_IS_OK(status)) {
7322 break;
7326 /* If any of the above locks failed, then we must unlock
7327 all of the previous locks (X/Open spec). */
7329 if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
7331 if (type & LOCKING_ANDX_CANCEL_LOCK) {
7332 i = -1; /* we want to skip the for loop */
7336 * Ensure we don't do a remove on the lock that just failed,
7337 * as under POSIX rules, if we have a lock already there, we
7338 * will delete it (and we shouldn't) .....
7340 for(i--; i >= 0; i--) {
7341 struct smbd_lock_element *e = &locks[i];
7343 do_unlock(req->sconn->msg_ctx,
7344 fsp,
7345 e->smblctx,
7346 e->count,
7347 e->offset,
7348 WINDOWS_LOCK);
7350 return status;
7353 DEBUG(3, ("smbd_do_locking: fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
7354 fsp->fnum, (unsigned int)type, num_locks, num_ulocks));
7356 return NT_STATUS_OK;
7359 /****************************************************************************
7360 Reply to a lockingX request.
7361 ****************************************************************************/
7363 void reply_lockingX(struct smb_request *req)
7365 connection_struct *conn = req->conn;
7366 files_struct *fsp;
7367 unsigned char locktype;
7368 unsigned char oplocklevel;
7369 uint16 num_ulocks;
7370 uint16 num_locks;
7371 int32 lock_timeout;
7372 int i;
7373 const uint8_t *data;
7374 bool large_file_format;
7375 bool err;
7376 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
7377 struct smbd_lock_element *ulocks;
7378 struct smbd_lock_element *locks;
7379 bool async = false;
7381 START_PROFILE(SMBlockingX);
7383 if (req->wct < 8) {
7384 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7385 END_PROFILE(SMBlockingX);
7386 return;
7389 fsp = file_fsp(req, SVAL(req->vwv+2, 0));
7390 locktype = CVAL(req->vwv+3, 0);
7391 oplocklevel = CVAL(req->vwv+3, 1);
7392 num_ulocks = SVAL(req->vwv+6, 0);
7393 num_locks = SVAL(req->vwv+7, 0);
7394 lock_timeout = IVAL(req->vwv+4, 0);
7395 large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
7397 if (!check_fsp(conn, req, fsp)) {
7398 END_PROFILE(SMBlockingX);
7399 return;
7402 data = req->buf;
7404 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
7405 /* we don't support these - and CANCEL_LOCK makes w2k
7406 and XP reboot so I don't really want to be
7407 compatible! (tridge) */
7408 reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
7409 END_PROFILE(SMBlockingX);
7410 return;
7413 /* Check if this is an oplock break on a file
7414 we have granted an oplock on.
7416 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
7417 /* Client can insist on breaking to none. */
7418 bool break_to_none = (oplocklevel == 0);
7419 bool result;
7421 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
7422 "for fnum = %d\n", (unsigned int)oplocklevel,
7423 fsp->fnum ));
7426 * Make sure we have granted an exclusive or batch oplock on
7427 * this file.
7430 if (fsp->oplock_type == 0) {
7432 /* The Samba4 nbench simulator doesn't understand
7433 the difference between break to level2 and break
7434 to none from level2 - it sends oplock break
7435 replies in both cases. Don't keep logging an error
7436 message here - just ignore it. JRA. */
7438 DEBUG(5,("reply_lockingX: Error : oplock break from "
7439 "client for fnum = %d (oplock=%d) and no "
7440 "oplock granted on this file (%s).\n",
7441 fsp->fnum, fsp->oplock_type,
7442 fsp_str_dbg(fsp)));
7444 /* if this is a pure oplock break request then don't
7445 * send a reply */
7446 if (num_locks == 0 && num_ulocks == 0) {
7447 END_PROFILE(SMBlockingX);
7448 return;
7449 } else {
7450 END_PROFILE(SMBlockingX);
7451 reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
7452 return;
7456 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
7457 (break_to_none)) {
7458 result = remove_oplock(fsp);
7459 } else {
7460 result = downgrade_oplock(fsp);
7463 if (!result) {
7464 DEBUG(0, ("reply_lockingX: error in removing "
7465 "oplock on file %s\n", fsp_str_dbg(fsp)));
7466 /* Hmmm. Is this panic justified? */
7467 smb_panic("internal tdb error");
7470 reply_to_oplock_break_requests(fsp);
7472 /* if this is a pure oplock break request then don't send a
7473 * reply */
7474 if (num_locks == 0 && num_ulocks == 0) {
7475 /* Sanity check - ensure a pure oplock break is not a
7476 chained request. */
7477 if(CVAL(req->vwv+0, 0) != 0xff)
7478 DEBUG(0,("reply_lockingX: Error : pure oplock "
7479 "break is a chained %d request !\n",
7480 (unsigned int)CVAL(req->vwv+0, 0)));
7481 END_PROFILE(SMBlockingX);
7482 return;
7486 if (req->buflen <
7487 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
7488 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7489 END_PROFILE(SMBlockingX);
7490 return;
7493 ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
7494 if (ulocks == NULL) {
7495 reply_nterror(req, NT_STATUS_NO_MEMORY);
7496 END_PROFILE(SMBlockingX);
7497 return;
7500 locks = talloc_array(req, struct smbd_lock_element, num_locks);
7501 if (locks == NULL) {
7502 reply_nterror(req, NT_STATUS_NO_MEMORY);
7503 END_PROFILE(SMBlockingX);
7504 return;
7507 /* Data now points at the beginning of the list
7508 of smb_unlkrng structs */
7509 for(i = 0; i < (int)num_ulocks; i++) {
7510 ulocks[i].smblctx = get_lock_pid(data, i, large_file_format);
7511 ulocks[i].count = get_lock_count(data, i, large_file_format);
7512 ulocks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7513 ulocks[i].brltype = UNLOCK_LOCK;
7516 * There is no error code marked "stupid client bug".... :-).
7518 if(err) {
7519 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7520 END_PROFILE(SMBlockingX);
7521 return;
7525 /* Now do any requested locks */
7526 data += ((large_file_format ? 20 : 10)*num_ulocks);
7528 /* Data now points at the beginning of the list
7529 of smb_lkrng structs */
7531 for(i = 0; i < (int)num_locks; i++) {
7532 locks[i].smblctx = get_lock_pid(data, i, large_file_format);
7533 locks[i].count = get_lock_count(data, i, large_file_format);
7534 locks[i].offset = get_lock_offset(data, i, large_file_format, &err);
7536 if (locktype & LOCKING_ANDX_SHARED_LOCK) {
7537 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7538 locks[i].brltype = PENDING_READ_LOCK;
7539 } else {
7540 locks[i].brltype = READ_LOCK;
7542 } else {
7543 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
7544 locks[i].brltype = PENDING_WRITE_LOCK;
7545 } else {
7546 locks[i].brltype = WRITE_LOCK;
7551 * There is no error code marked "stupid client bug".... :-).
7553 if(err) {
7554 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
7555 END_PROFILE(SMBlockingX);
7556 return;
7560 status = smbd_do_locking(req, fsp,
7561 locktype, lock_timeout,
7562 num_ulocks, ulocks,
7563 num_locks, locks,
7564 &async);
7565 if (!NT_STATUS_IS_OK(status)) {
7566 END_PROFILE(SMBlockingX);
7567 reply_nterror(req, status);
7568 return;
7570 if (async) {
7571 END_PROFILE(SMBlockingX);
7572 return;
7575 reply_outbuf(req, 2, 0);
7577 DEBUG(3, ("lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
7578 fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks));
7580 END_PROFILE(SMBlockingX);
7581 chain_reply(req);
7584 #undef DBGC_CLASS
7585 #define DBGC_CLASS DBGC_ALL
7587 /****************************************************************************
7588 Reply to a SMBreadbmpx (read block multiplex) request.
7589 Always reply with an error, if someone has a platform really needs this,
7590 please contact vl@samba.org
7591 ****************************************************************************/
7593 void reply_readbmpx(struct smb_request *req)
7595 START_PROFILE(SMBreadBmpx);
7596 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7597 END_PROFILE(SMBreadBmpx);
7598 return;
7601 /****************************************************************************
7602 Reply to a SMBreadbs (read block multiplex secondary) request.
7603 Always reply with an error, if someone has a platform really needs this,
7604 please contact vl@samba.org
7605 ****************************************************************************/
7607 void reply_readbs(struct smb_request *req)
7609 START_PROFILE(SMBreadBs);
7610 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7611 END_PROFILE(SMBreadBs);
7612 return;
7615 /****************************************************************************
7616 Reply to a SMBsetattrE.
7617 ****************************************************************************/
7619 void reply_setattrE(struct smb_request *req)
7621 connection_struct *conn = req->conn;
7622 struct smb_file_time ft;
7623 files_struct *fsp;
7624 NTSTATUS status;
7626 START_PROFILE(SMBsetattrE);
7627 ZERO_STRUCT(ft);
7629 if (req->wct < 7) {
7630 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7631 goto out;
7634 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
7636 if(!fsp || (fsp->conn != conn)) {
7637 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
7638 goto out;
7642 * Convert the DOS times into unix times.
7645 ft.atime = convert_time_t_to_timespec(
7646 srv_make_unix_date2(req->vwv+3));
7647 ft.mtime = convert_time_t_to_timespec(
7648 srv_make_unix_date2(req->vwv+5));
7649 ft.create_time = convert_time_t_to_timespec(
7650 srv_make_unix_date2(req->vwv+1));
7652 reply_outbuf(req, 0, 0);
7655 * Patch from Ray Frush <frush@engr.colostate.edu>
7656 * Sometimes times are sent as zero - ignore them.
7659 /* Ensure we have a valid stat struct for the source. */
7660 status = vfs_stat_fsp(fsp);
7661 if (!NT_STATUS_IS_OK(status)) {
7662 reply_nterror(req, status);
7663 goto out;
7666 status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
7667 if (!NT_STATUS_IS_OK(status)) {
7668 reply_nterror(req, status);
7669 goto out;
7672 DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u "
7673 " createtime=%u\n",
7674 fsp->fnum,
7675 (unsigned int)ft.atime.tv_sec,
7676 (unsigned int)ft.mtime.tv_sec,
7677 (unsigned int)ft.create_time.tv_sec
7679 out:
7680 END_PROFILE(SMBsetattrE);
7681 return;
7685 /* Back from the dead for OS/2..... JRA. */
7687 /****************************************************************************
7688 Reply to a SMBwritebmpx (write block multiplex primary) request.
7689 Always reply with an error, if someone has a platform really needs this,
7690 please contact vl@samba.org
7691 ****************************************************************************/
7693 void reply_writebmpx(struct smb_request *req)
7695 START_PROFILE(SMBwriteBmpx);
7696 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7697 END_PROFILE(SMBwriteBmpx);
7698 return;
7701 /****************************************************************************
7702 Reply to a SMBwritebs (write block multiplex secondary) request.
7703 Always reply with an error, if someone has a platform really needs this,
7704 please contact vl@samba.org
7705 ****************************************************************************/
7707 void reply_writebs(struct smb_request *req)
7709 START_PROFILE(SMBwriteBs);
7710 reply_force_doserror(req, ERRSRV, ERRuseSTD);
7711 END_PROFILE(SMBwriteBs);
7712 return;
7715 /****************************************************************************
7716 Reply to a SMBgetattrE.
7717 ****************************************************************************/
7719 void reply_getattrE(struct smb_request *req)
7721 connection_struct *conn = req->conn;
7722 int mode;
7723 files_struct *fsp;
7724 struct timespec create_ts;
7726 START_PROFILE(SMBgetattrE);
7728 if (req->wct < 1) {
7729 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7730 END_PROFILE(SMBgetattrE);
7731 return;
7734 fsp = file_fsp(req, SVAL(req->vwv+0, 0));
7736 if(!fsp || (fsp->conn != conn)) {
7737 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
7738 END_PROFILE(SMBgetattrE);
7739 return;
7742 /* Do an fstat on this file */
7743 if(fsp_stat(fsp)) {
7744 reply_nterror(req, map_nt_error_from_unix(errno));
7745 END_PROFILE(SMBgetattrE);
7746 return;
7749 mode = dos_mode(conn, fsp->fsp_name);
7752 * Convert the times into dos times. Set create
7753 * date to be last modify date as UNIX doesn't save
7754 * this.
7757 reply_outbuf(req, 11, 0);
7759 create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
7760 srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
7761 srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
7762 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
7763 /* Should we check pending modtime here ? JRA */
7764 srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
7765 convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
7767 if (mode & aDIR) {
7768 SIVAL(req->outbuf, smb_vwv6, 0);
7769 SIVAL(req->outbuf, smb_vwv8, 0);
7770 } else {
7771 uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
7772 SIVAL(req->outbuf, smb_vwv6, (uint32)fsp->fsp_name->st.st_ex_size);
7773 SIVAL(req->outbuf, smb_vwv8, allocation_size);
7775 SSVAL(req->outbuf,smb_vwv10, mode);
7777 DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
7779 END_PROFILE(SMBgetattrE);
7780 return;