Line data Source code
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
8 :
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.
13 :
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.
18 :
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/>.
21 : */
22 : /*
23 : This file handles most of the reply_ calls that the server
24 : makes to handle specific protocols
25 : */
26 :
27 : #include "includes.h"
28 : #include "libsmb/namequery.h"
29 : #include "system/filesys.h"
30 : #include "printing.h"
31 : #include "locking/share_mode_lock.h"
32 : #include "smbd/smbd.h"
33 : #include "smbd/globals.h"
34 : #include "smbd/smbXsrv_open.h"
35 : #include "fake_file.h"
36 : #include "rpc_client/rpc_client.h"
37 : #include "../librpc/gen_ndr/ndr_spoolss_c.h"
38 : #include "rpc_client/cli_spoolss.h"
39 : #include "rpc_client/init_spoolss.h"
40 : #include "rpc_server/rpc_ncacn_np.h"
41 : #include "libcli/security/security.h"
42 : #include "libsmb/nmblib.h"
43 : #include "auth.h"
44 : #include "smbprofile.h"
45 : #include "../lib/tsocket/tsocket.h"
46 : #include "lib/util/tevent_ntstatus.h"
47 : #include "libcli/smb/smb_signing.h"
48 : #include "lib/util/sys_rw_data.h"
49 : #include "librpc/gen_ndr/open_files.h"
50 : #include "libcli/smb/smb2_posix.h"
51 : #include "lib/util/string_wrappers.h"
52 : #include "source3/printing/rap_jobid.h"
53 : #include "source3/lib/substitute.h"
54 : #include "source3/smbd/dir.h"
55 :
56 : /****************************************************************************
57 : Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
58 : path or anything including wildcards.
59 : We're assuming here that '/' is not the second byte in any multibyte char
60 : set (a safe assumption). '\\' *may* be the second byte in a multibyte char
61 : set.
62 : ****************************************************************************/
63 :
64 : /* Custom version for processing POSIX paths. */
65 : #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
66 :
67 640701 : NTSTATUS check_path_syntax(char *path, bool posix_path)
68 : {
69 640701 : char *d = path;
70 640701 : const char *s = path;
71 640701 : NTSTATUS ret = NT_STATUS_OK;
72 640701 : bool start_of_name_component = True;
73 640701 : bool stream_started = false;
74 640701 : bool last_component_contains_wcard = false;
75 :
76 15739850 : while (*s) {
77 15099793 : if (stream_started) {
78 95941 : switch (*s) {
79 24 : case '/':
80 : case '\\':
81 74 : return NT_STATUS_OBJECT_NAME_INVALID;
82 4944 : case ':':
83 4944 : if (s[1] == '\0') {
84 36 : return NT_STATUS_OBJECT_NAME_INVALID;
85 : }
86 4908 : if (strchr_m(&s[1], ':')) {
87 14 : return NT_STATUS_OBJECT_NAME_INVALID;
88 : }
89 4893 : break;
90 : }
91 : }
92 :
93 15099719 : if ((*s == ':') && !posix_path && !stream_started) {
94 6607 : if (last_component_contains_wcard) {
95 12 : return NT_STATUS_OBJECT_NAME_INVALID;
96 : }
97 : /* Stream names allow more characters than file names.
98 : We're overloading posix_path here to allow a wider
99 : range of characters. If stream_started is true this
100 : is still a Windows path even if posix_path is true.
101 : JRA.
102 : */
103 6595 : stream_started = true;
104 6595 : start_of_name_component = false;
105 6595 : posix_path = true;
106 :
107 6595 : if (s[1] == '\0') {
108 0 : return NT_STATUS_OBJECT_NAME_INVALID;
109 : }
110 : }
111 :
112 15099707 : if (!stream_started && IS_PATH_SEP(*s,posix_path)) {
113 : /*
114 : * Safe to assume is not the second part of a mb char
115 : * as this is handled below.
116 : */
117 : /* Eat multiple '/' or '\\' */
118 2076526 : while (IS_PATH_SEP(*s,posix_path)) {
119 1038319 : s++;
120 : }
121 1038207 : if ((d != path) && (*s != '\0')) {
122 : /* We only care about non-leading or trailing '/' or '\\' */
123 890165 : *d++ = '/';
124 : }
125 :
126 1038207 : start_of_name_component = True;
127 : /* New component. */
128 1038207 : last_component_contains_wcard = false;
129 1038207 : continue;
130 : }
131 :
132 14061500 : if (start_of_name_component) {
133 1487885 : if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
134 : /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
135 :
136 : /*
137 : * No mb char starts with '.' so we're safe checking the directory separator here.
138 : */
139 :
140 : /* If we just added a '/' - delete it */
141 69 : if ((d > path) && (*(d-1) == '/')) {
142 24 : *(d-1) = '\0';
143 24 : d--;
144 : }
145 :
146 : /* Are we at the start ? Can't go back further if so. */
147 69 : if (d <= path) {
148 44 : ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
149 44 : break;
150 : }
151 : /* Go back one level... */
152 : /* We know this is safe as '/' cannot be part of a mb sequence. */
153 : /* NOTE - if this assumption is invalid we are not in good shape... */
154 : /* Decrement d first as d points to the *next* char to write into. */
155 144 : for (d--; d > path; d--) {
156 136 : if (*d == '/')
157 16 : break;
158 : }
159 24 : s += 2; /* Else go past the .. */
160 : /* We're still at the start of a name component, just the previous one. */
161 24 : continue;
162 :
163 1487816 : } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
164 36 : if (posix_path) {
165 : /* Eat the '.' */
166 4 : s++;
167 4 : continue;
168 : }
169 : }
170 :
171 : }
172 :
173 14061427 : if (!(*s & 0x80)) {
174 13930201 : if (!posix_path) {
175 13760752 : if (*s <= 0x1f || *s == '|') {
176 513 : return NT_STATUS_OBJECT_NAME_INVALID;
177 : }
178 13760239 : switch (*s) {
179 12638 : case '*':
180 : case '?':
181 : case '<':
182 : case '>':
183 : case '"':
184 12638 : last_component_contains_wcard = true;
185 12638 : break;
186 13545992 : default:
187 13545992 : break;
188 : }
189 : }
190 13929688 : *d++ = *s++;
191 : } else {
192 0 : size_t ch_size;
193 : /* Get the size of the next MB character. */
194 131226 : next_codepoint(s,&ch_size);
195 131226 : switch(ch_size) {
196 0 : case 5:
197 0 : *d++ = *s++;
198 0 : FALL_THROUGH;
199 0 : case 4:
200 0 : *d++ = *s++;
201 0 : FALL_THROUGH;
202 131166 : case 3:
203 131166 : *d++ = *s++;
204 0 : FALL_THROUGH;
205 131226 : case 2:
206 131226 : *d++ = *s++;
207 0 : FALL_THROUGH;
208 131226 : case 1:
209 131226 : *d++ = *s++;
210 131226 : break;
211 0 : default:
212 0 : DBG_ERR("character length assumptions invalid !\n");
213 0 : *d = '\0';
214 0 : return NT_STATUS_INVALID_PARAMETER;
215 : }
216 : }
217 13859195 : start_of_name_component = False;
218 : }
219 :
220 640102 : *d = '\0';
221 :
222 640102 : return ret;
223 : }
224 :
225 : /****************************************************************************
226 : SMB2-only code to strip an MSDFS prefix from an incoming pathname.
227 : ****************************************************************************/
228 :
229 12668 : NTSTATUS smb2_strip_dfs_path(const char *in_path, const char **out_path)
230 : {
231 12668 : const char *path = in_path;
232 :
233 : /* Match the Windows 2022 behavior for an empty DFS pathname. */
234 12668 : if (*path == '\0') {
235 2 : return NT_STATUS_INVALID_PARAMETER;
236 : }
237 : /* Strip any leading '\\' characters - MacOSX client behavior. */
238 12682 : while (*path == '\\') {
239 16 : path++;
240 : }
241 : /* We should now be pointing at the server name. Go past it. */
242 0 : for (;;) {
243 167721 : if (*path == '\0') {
244 : /* End of complete path. Exit OK. */
245 6 : goto out;
246 : }
247 167715 : if (*path == '\\') {
248 : /* End of server name. Go past and break. */
249 12660 : path++;
250 12660 : break;
251 : }
252 155055 : path++; /* Continue looking for end of server name or string. */
253 : }
254 :
255 : /* We should now be pointing at the share name. Go past it. */
256 0 : for (;;) {
257 179064 : if (*path == '\0') {
258 : /* End of complete path. Exit OK. */
259 424 : goto out;
260 : }
261 178640 : if (*path == '\\') {
262 : /* End of share name. Go past and break. */
263 12234 : path++;
264 12234 : break;
265 : }
266 166406 : if (*path == ':') {
267 : /* Only invalid character in sharename. */
268 2 : return NT_STATUS_OBJECT_NAME_INVALID;
269 : }
270 166404 : path++; /* Continue looking for end of share name or string. */
271 : }
272 :
273 : /* path now points at the start of the real filename (if any). */
274 :
275 12664 : out:
276 : /* We have stripped the DFS path prefix (if any). */
277 12664 : *out_path = path;
278 12664 : return NT_STATUS_OK;
279 : }
280 :
281 : /****************************************************************************
282 : Pull a string and check the path allowing a wildcard - provide for error return.
283 : Passes in posix flag.
284 : ****************************************************************************/
285 :
286 158973 : static size_t srvstr_get_path_internal(TALLOC_CTX *ctx,
287 : const char *base_ptr,
288 : uint16_t smb_flags2,
289 : char **pp_dest,
290 : const char *src,
291 : size_t src_len,
292 : int flags,
293 : bool posix_pathnames,
294 : NTSTATUS *err)
295 : {
296 10176 : size_t ret;
297 158973 : char *dst = NULL;
298 :
299 158973 : *pp_dest = NULL;
300 :
301 158973 : ret = srvstr_pull_talloc(ctx, base_ptr, smb_flags2, pp_dest, src,
302 : src_len, flags);
303 :
304 158973 : if (!*pp_dest) {
305 0 : *err = NT_STATUS_INVALID_PARAMETER;
306 0 : return ret;
307 : }
308 :
309 158973 : dst = *pp_dest;
310 :
311 158973 : if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
312 : /*
313 : * A valid DFS path looks either like
314 : * /server/share
315 : * \server\share
316 : * (there may be more components after).
317 : * Either way it must have at least two separators.
318 : *
319 : * Ensure we end up as /server/share
320 : * so we don't need to special case
321 : * separator characters elsewhere in
322 : * the code.
323 : */
324 1626 : char *server = NULL;
325 1626 : char *share = NULL;
326 1626 : char *remaining_path = NULL;
327 1626 : char path_sep = 0;
328 1626 : char *p = NULL;
329 :
330 1626 : if (posix_pathnames && (dst[0] == '/')) {
331 0 : path_sep = dst[0];
332 1626 : } else if (dst[0] == '\\') {
333 1572 : path_sep = dst[0];
334 : }
335 :
336 1626 : if (path_sep == 0) {
337 54 : goto local_path;
338 : }
339 : /*
340 : * May be a DFS path.
341 : * We need some heuristics here,
342 : * as clients differ on what constitutes
343 : * a well-formed DFS path. If the path
344 : * appears malformed, just fall back to
345 : * processing as a local path.
346 : */
347 1572 : server = dst;
348 :
349 : /*
350 : * Cosmetic fix for Linux-only DFS clients.
351 : * The Linux kernel SMB1 client has a bug - it sends
352 : * DFS pathnames as:
353 : *
354 : * \\server\share\path
355 : *
356 : * Causing us to mis-parse server,share,remaining_path here
357 : * and jump into 'goto local_path' at 'share\path' instead
358 : * of 'path'.
359 : *
360 : * This doesn't cause an error as the limits on share names
361 : * are similar to those on pathnames.
362 : *
363 : * parse_dfs_path() which we call before filename parsing
364 : * copes with this by calling trim_char on the leading '\'
365 : * characters before processing.
366 : * Do the same here so logging of pathnames looks better.
367 : */
368 1572 : if (server[1] == path_sep) {
369 18 : trim_char(&server[1], path_sep, '\0');
370 : }
371 :
372 : /*
373 : * Look to see if we also have /share following.
374 : */
375 1572 : share = strchr(server+1, path_sep);
376 1572 : if (share == NULL) {
377 22 : goto local_path;
378 : }
379 : /*
380 : * Ensure the server name does not contain
381 : * any possible path components by converting
382 : * them to _'s.
383 : */
384 27700 : for (p = server + 1; p < share; p++) {
385 26150 : if (*p == '/' || *p == '\\') {
386 4 : *p = '_';
387 : }
388 : }
389 : /*
390 : * It's a well formed DFS path with
391 : * at least server and share components.
392 : * Replace the slashes with '/' and
393 : * pass the remainder to local_path.
394 : */
395 1550 : *server = '/';
396 1550 : *share = '/';
397 : /*
398 : * Skip past share so we don't pass the
399 : * sharename into check_path_syntax().
400 : */
401 1550 : remaining_path = strchr(share+1, path_sep);
402 1550 : if (remaining_path == NULL) {
403 : /*
404 : * Ensure the share name does not contain
405 : * any possible path components by converting
406 : * them to _'s.
407 : */
408 322 : for (p = share + 1; *p; p++) {
409 290 : if (*p == '/' || *p == '\\') {
410 2 : *p = '_';
411 : }
412 : }
413 : /*
414 : * If no remaining path this was
415 : * a bare /server/share path. Just return.
416 : */
417 32 : *err = NT_STATUS_OK;
418 32 : return ret;
419 : }
420 : /*
421 : * Ensure the share name does not contain
422 : * any possible path components by converting
423 : * them to _'s.
424 : */
425 18304 : for (p = share + 1; p < remaining_path; p++) {
426 16786 : if (*p == '/' || *p == '\\') {
427 0 : *p = '_';
428 : }
429 : }
430 1518 : *remaining_path = '/';
431 1518 : dst = remaining_path + 1;
432 : /* dst now points at any following components. */
433 : }
434 :
435 157347 : local_path:
436 :
437 158941 : *err = check_path_syntax(dst, posix_pathnames);
438 :
439 158941 : return ret;
440 : }
441 :
442 : /****************************************************************************
443 : Pull a string and check the path - provide for error return.
444 : ****************************************************************************/
445 :
446 21351 : size_t srvstr_get_path(TALLOC_CTX *ctx,
447 : const char *base_ptr,
448 : uint16_t smb_flags2,
449 : char **pp_dest,
450 : const char *src,
451 : size_t src_len,
452 : int flags,
453 : NTSTATUS *err)
454 : {
455 21351 : return srvstr_get_path_internal(ctx,
456 : base_ptr,
457 : smb_flags2,
458 : pp_dest,
459 : src,
460 : src_len,
461 : flags,
462 : false,
463 : err);
464 : }
465 :
466 : /****************************************************************************
467 : Pull a string and check the path - provide for error return.
468 : posix_pathnames version.
469 : ****************************************************************************/
470 :
471 1866 : size_t srvstr_get_path_posix(TALLOC_CTX *ctx,
472 : const char *base_ptr,
473 : uint16_t smb_flags2,
474 : char **pp_dest,
475 : const char *src,
476 : size_t src_len,
477 : int flags,
478 : NTSTATUS *err)
479 : {
480 1866 : return srvstr_get_path_internal(ctx,
481 : base_ptr,
482 : smb_flags2,
483 : pp_dest,
484 : src,
485 : src_len,
486 : flags,
487 : true,
488 : err);
489 : }
490 :
491 :
492 135756 : size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
493 : char **pp_dest, const char *src, int flags,
494 : NTSTATUS *err)
495 : {
496 135756 : ssize_t bufrem = smbreq_bufrem(req, src);
497 :
498 135756 : if (bufrem == 0) {
499 0 : *err = NT_STATUS_INVALID_PARAMETER;
500 0 : return 0;
501 : }
502 :
503 135756 : if (req->posix_pathnames) {
504 411 : return srvstr_get_path_internal(mem_ctx,
505 411 : (const char *)req->inbuf,
506 411 : req->flags2,
507 : pp_dest,
508 : src,
509 : bufrem,
510 : flags,
511 : true,
512 : err);
513 : } else {
514 135345 : return srvstr_get_path_internal(mem_ctx,
515 135345 : (const char *)req->inbuf,
516 135345 : req->flags2,
517 : pp_dest,
518 : src,
519 : bufrem,
520 : flags,
521 : false,
522 : err);
523 : }
524 : }
525 :
526 : /**
527 : * pull a string from the smb_buf part of a packet. In this case the
528 : * string can either be null terminated or it can be terminated by the
529 : * end of the smbbuf area
530 : */
531 51297 : size_t srvstr_pull_req_talloc(TALLOC_CTX *ctx, struct smb_request *req,
532 : char **dest, const uint8_t *src, int flags)
533 : {
534 51297 : ssize_t bufrem = smbreq_bufrem(req, src);
535 :
536 51297 : if (bufrem == 0) {
537 7526 : *dest = NULL;
538 7526 : return 0;
539 : }
540 :
541 43771 : return pull_string_talloc(ctx, req->inbuf, req->flags2, dest, src,
542 : bufrem, flags);
543 : }
544 :
545 : /****************************************************************************
546 : Check if we have a correct fsp pointing to a quota fake file. Replacement for
547 : the CHECK_NTQUOTA_HANDLE_OK macro.
548 : ****************************************************************************/
549 :
550 24 : bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req,
551 : files_struct *fsp)
552 : {
553 24 : if ((fsp == NULL) || (conn == NULL)) {
554 0 : return false;
555 : }
556 :
557 24 : if ((conn != fsp->conn) || (req->vuid != fsp->vuid)) {
558 0 : return false;
559 : }
560 :
561 24 : if (fsp->fsp_flags.is_directory) {
562 4 : return false;
563 : }
564 :
565 20 : if (fsp->fake_file_handle == NULL) {
566 0 : return false;
567 : }
568 :
569 20 : if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) {
570 0 : return false;
571 : }
572 :
573 20 : if (fsp->fake_file_handle->private_data == NULL) {
574 0 : return false;
575 : }
576 :
577 20 : return true;
578 : }
579 :
580 : /****************************************************************************
581 : Return the port number we've bound to on a socket.
582 : ****************************************************************************/
583 :
584 1038 : static int get_socket_port(int fd)
585 : {
586 1038 : struct samba_sockaddr saddr = {
587 : .sa_socklen = sizeof(struct sockaddr_storage),
588 : };
589 :
590 1038 : if (fd == -1) {
591 0 : return -1;
592 : }
593 :
594 1038 : if (getsockname(fd, &saddr.u.sa, &saddr.sa_socklen) < 0) {
595 0 : int level = (errno == ENOTCONN) ? 2 : 0;
596 0 : DEBUG(level, ("getsockname failed. Error was %s\n",
597 : strerror(errno)));
598 0 : return -1;
599 : }
600 :
601 : #if defined(HAVE_IPV6)
602 1038 : if (saddr.u.sa.sa_family == AF_INET6) {
603 25 : return ntohs(saddr.u.in6.sin6_port);
604 : }
605 : #endif
606 1013 : if (saddr.u.sa.sa_family == AF_INET) {
607 1013 : return ntohs(saddr.u.in.sin_port);
608 : }
609 0 : return -1;
610 : }
611 :
612 1038 : static bool netbios_session_retarget(struct smbXsrv_connection *xconn,
613 : const char *name, int name_type)
614 : {
615 0 : char *trim_name;
616 0 : char *trim_name_type;
617 0 : const char *retarget_parm;
618 0 : char *retarget;
619 0 : char *p;
620 1038 : int retarget_type = 0x20;
621 1038 : int retarget_port = NBT_SMB_PORT;
622 0 : struct sockaddr_storage retarget_addr;
623 0 : struct sockaddr_in *in_addr;
624 1038 : bool ret = false;
625 0 : uint8_t outbuf[10];
626 :
627 1038 : if (get_socket_port(xconn->transport.sock) != NBT_SMB_PORT) {
628 0 : return false;
629 : }
630 :
631 1038 : trim_name = talloc_strdup(talloc_tos(), name);
632 1038 : if (trim_name == NULL) {
633 0 : goto fail;
634 : }
635 1038 : trim_char(trim_name, ' ', ' ');
636 :
637 1038 : trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name,
638 : name_type);
639 1038 : if (trim_name_type == NULL) {
640 0 : goto fail;
641 : }
642 :
643 1038 : retarget_parm = lp_parm_const_string(-1, "netbios retarget",
644 : trim_name_type, NULL);
645 1038 : if (retarget_parm == NULL) {
646 1038 : retarget_parm = lp_parm_const_string(-1, "netbios retarget",
647 : trim_name, NULL);
648 : }
649 1038 : if (retarget_parm == NULL) {
650 1038 : goto fail;
651 : }
652 :
653 0 : retarget = talloc_strdup(trim_name, retarget_parm);
654 0 : if (retarget == NULL) {
655 0 : goto fail;
656 : }
657 :
658 0 : DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget));
659 :
660 0 : p = strchr(retarget, ':');
661 0 : if (p != NULL) {
662 0 : *p++ = '\0';
663 0 : retarget_port = atoi(p);
664 : }
665 :
666 0 : p = strchr_m(retarget, '#');
667 0 : if (p != NULL) {
668 0 : *p++ = '\0';
669 0 : if (sscanf(p, "%x", &retarget_type) != 1) {
670 0 : goto fail;
671 : }
672 : }
673 :
674 0 : ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
675 0 : if (!ret) {
676 0 : DEBUG(10, ("could not resolve %s\n", retarget));
677 0 : goto fail;
678 : }
679 :
680 0 : if (retarget_addr.ss_family != AF_INET) {
681 0 : DEBUG(10, ("Retarget target not an IPv4 addr\n"));
682 0 : goto fail;
683 : }
684 :
685 0 : in_addr = (struct sockaddr_in *)(void *)&retarget_addr;
686 :
687 0 : _smb_setlen(outbuf, 6);
688 0 : SCVAL(outbuf, 0, 0x84);
689 0 : *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr;
690 0 : *(uint16_t *)(outbuf+8) = htons(retarget_port);
691 :
692 0 : if (!smb1_srv_send(xconn, (char *)outbuf, false, 0, false)) {
693 0 : exit_server_cleanly("netbios_session_retarget: smb1_srv_send "
694 : "failed.");
695 : }
696 :
697 0 : ret = true;
698 1038 : fail:
699 1038 : TALLOC_FREE(trim_name);
700 1038 : return ret;
701 : }
702 :
703 4 : static void reply_called_name_not_present(char *outbuf)
704 : {
705 4 : smb_setlen(outbuf, 1);
706 4 : SCVAL(outbuf, 0, 0x83);
707 4 : SCVAL(outbuf, 4, 0x82);
708 4 : }
709 :
710 : /****************************************************************************
711 : Reply to a (netbios-level) special message.
712 : ****************************************************************************/
713 :
714 1042 : void reply_special(struct smbXsrv_connection *xconn, char *inbuf, size_t inbuf_size)
715 : {
716 1042 : struct smbd_server_connection *sconn = xconn->client->sconn;
717 1042 : int msg_type = CVAL(inbuf,0);
718 1042 : int msg_flags = CVAL(inbuf,1);
719 : /*
720 : * We only really use 4 bytes of the outbuf, but for the smb_setlen
721 : * calculation & friends (smb1_srv_send uses that) we need the full smb
722 : * header.
723 : */
724 0 : char outbuf[smb_size];
725 :
726 1042 : memset(outbuf, '\0', sizeof(outbuf));
727 :
728 1042 : smb_setlen(outbuf,0);
729 :
730 1042 : switch (msg_type) {
731 1042 : case NBSSrequest: /* session request */
732 : {
733 : /* inbuf_size is guaranteed to be at least 4. */
734 0 : fstring name1,name2;
735 0 : int name_type1, name_type2;
736 0 : int name_len1, name_len2;
737 :
738 1042 : *name1 = *name2 = 0;
739 :
740 1042 : if (xconn->transport.nbt.got_session) {
741 0 : exit_server_cleanly("multiple session request not permitted");
742 : }
743 :
744 1042 : SCVAL(outbuf,0,NBSSpositive);
745 1042 : SCVAL(outbuf,3,0);
746 :
747 : /* inbuf_size is guaranteed to be at least 4. */
748 1042 : name_len1 = name_len((unsigned char *)(inbuf+4),inbuf_size - 4);
749 1042 : if (name_len1 <= 0 || name_len1 > inbuf_size - 4) {
750 0 : DEBUG(0,("Invalid name length in session request\n"));
751 0 : reply_called_name_not_present(outbuf);
752 0 : break;
753 : }
754 1042 : name_len2 = name_len((unsigned char *)(inbuf+4+name_len1),inbuf_size - 4 - name_len1);
755 1042 : if (name_len2 <= 0 || name_len2 > inbuf_size - 4 - name_len1) {
756 4 : DEBUG(0,("Invalid name length in session request\n"));
757 4 : reply_called_name_not_present(outbuf);
758 4 : break;
759 : }
760 :
761 1038 : name_type1 = name_extract((unsigned char *)inbuf,
762 : inbuf_size,(unsigned int)4,name1);
763 1038 : name_type2 = name_extract((unsigned char *)inbuf,
764 1038 : inbuf_size,(unsigned int)(4 + name_len1),name2);
765 :
766 1038 : if (name_type1 == -1 || name_type2 == -1) {
767 0 : DEBUG(0,("Invalid name type in session request\n"));
768 0 : reply_called_name_not_present(outbuf);
769 0 : break;
770 : }
771 :
772 1038 : DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n",
773 : name1, name_type1, name2, name_type2));
774 :
775 1038 : if (netbios_session_retarget(xconn, name1, name_type1)) {
776 0 : exit_server_cleanly("retargeted client");
777 : }
778 :
779 : /*
780 : * Windows NT/2k uses "*SMBSERVER" and XP uses
781 : * "*SMBSERV" arrggg!!!
782 : */
783 1038 : if (strequal(name1, "*SMBSERVER ")
784 1038 : || strequal(name1, "*SMBSERV ")) {
785 0 : char *raddr;
786 :
787 0 : raddr = tsocket_address_inet_addr_string(sconn->remote_address,
788 : talloc_tos());
789 0 : if (raddr == NULL) {
790 0 : exit_server_cleanly("could not allocate raddr");
791 : }
792 :
793 0 : fstrcpy(name1, raddr);
794 : }
795 :
796 1038 : set_local_machine_name(name1, True);
797 1038 : set_remote_machine_name(name2, True);
798 :
799 1038 : if (is_ipaddress(sconn->remote_hostname)) {
800 1038 : char *p = discard_const_p(char, sconn->remote_hostname);
801 :
802 1038 : talloc_free(p);
803 :
804 1038 : sconn->remote_hostname = talloc_strdup(sconn,
805 : get_remote_machine_name());
806 1038 : if (sconn->remote_hostname == NULL) {
807 0 : exit_server_cleanly("could not copy remote name");
808 : }
809 1038 : xconn->remote_hostname = sconn->remote_hostname;
810 : }
811 :
812 1038 : DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
813 : get_local_machine_name(), get_remote_machine_name(),
814 : name_type2));
815 :
816 1038 : if (name_type2 == 'R') {
817 : /* We are being asked for a pathworks session ---
818 : no thanks! */
819 0 : reply_called_name_not_present(outbuf);
820 0 : break;
821 : }
822 :
823 1038 : reload_services(sconn, conn_snum_used, true);
824 1038 : reopen_logs();
825 :
826 1038 : xconn->transport.nbt.got_session = true;
827 1038 : break;
828 : }
829 :
830 0 : case 0x89: /* session keepalive request
831 : (some old clients produce this?) */
832 0 : SCVAL(outbuf,0,NBSSkeepalive);
833 0 : SCVAL(outbuf,3,0);
834 0 : break;
835 :
836 0 : case NBSSpositive: /* positive session response */
837 : case NBSSnegative: /* negative session response */
838 : case NBSSretarget: /* retarget session response */
839 0 : DEBUG(0,("Unexpected session response\n"));
840 0 : break;
841 :
842 0 : case NBSSkeepalive: /* session keepalive */
843 : default:
844 0 : return;
845 : }
846 :
847 1042 : DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
848 : msg_type, msg_flags));
849 :
850 1042 : if (!smb1_srv_send(xconn, outbuf, false, 0, false)) {
851 3 : exit_server_cleanly("reply_special: smb1_srv_send failed.");
852 : }
853 :
854 1039 : if (CVAL(outbuf, 0) != 0x82) {
855 4 : exit_server_cleanly("invalid netbios session");
856 : }
857 1035 : return;
858 : }
859 :
860 : /*******************************************************************
861 : * unlink a file with all relevant access checks
862 : *******************************************************************/
863 :
864 26909 : NTSTATUS unlink_internals(connection_struct *conn,
865 : struct smb_request *req,
866 : uint32_t dirtype,
867 : struct files_struct *dirfsp,
868 : struct smb_filename *smb_fname)
869 : {
870 381 : uint32_t fattr;
871 381 : files_struct *fsp;
872 26909 : uint32_t dirtype_orig = dirtype;
873 381 : NTSTATUS status;
874 381 : int ret;
875 26909 : struct smb2_create_blobs *posx = NULL;
876 :
877 26909 : if (dirtype == 0) {
878 88 : dirtype = FILE_ATTRIBUTE_NORMAL;
879 : }
880 :
881 26909 : DBG_DEBUG("%s, dirtype = %d\n",
882 : smb_fname_str_dbg(smb_fname),
883 : dirtype);
884 :
885 26909 : if (!CAN_WRITE(conn)) {
886 0 : return NT_STATUS_MEDIA_WRITE_PROTECTED;
887 : }
888 :
889 26909 : ret = vfs_stat(conn, smb_fname);
890 26909 : if (ret != 0) {
891 2621 : return map_nt_error_from_unix(errno);
892 : }
893 :
894 24288 : fattr = fdos_mode(smb_fname->fsp);
895 :
896 24288 : if (dirtype & FILE_ATTRIBUTE_NORMAL) {
897 72 : dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
898 : }
899 :
900 24288 : dirtype &= (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
901 24288 : if (!dirtype) {
902 0 : return NT_STATUS_NO_SUCH_FILE;
903 : }
904 :
905 24288 : if (!dir_check_ftype(fattr, dirtype)) {
906 24 : if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
907 20 : return NT_STATUS_FILE_IS_A_DIRECTORY;
908 : }
909 4 : return NT_STATUS_NO_SUCH_FILE;
910 : }
911 :
912 24264 : if (dirtype_orig & 0x8000) {
913 : /* These will never be set for POSIX. */
914 0 : return NT_STATUS_NO_SUCH_FILE;
915 : }
916 :
917 : #if 0
918 : if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
919 : return NT_STATUS_FILE_IS_A_DIRECTORY;
920 : }
921 :
922 : if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
923 : return NT_STATUS_NO_SUCH_FILE;
924 : }
925 :
926 : if (dirtype & 0xFF00) {
927 : /* These will never be set for POSIX. */
928 : return NT_STATUS_NO_SUCH_FILE;
929 : }
930 :
931 : dirtype &= 0xFF;
932 : if (!dirtype) {
933 : return NT_STATUS_NO_SUCH_FILE;
934 : }
935 :
936 : /* Can't delete a directory. */
937 : if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
938 : return NT_STATUS_FILE_IS_A_DIRECTORY;
939 : }
940 : #endif
941 :
942 : #if 0 /* JRATEST */
943 : else if (dirtype & FILE_ATTRIBUTE_DIRECTORY) /* Asked for a directory and it isn't. */
944 : return NT_STATUS_OBJECT_NAME_INVALID;
945 : #endif /* JRATEST */
946 :
947 24264 : if (smb_fname->flags & SMB_FILENAME_POSIX_PATH) {
948 26 : status = make_smb2_posix_create_ctx(
949 : talloc_tos(), &posx, 0777);
950 26 : if (!NT_STATUS_IS_OK(status)) {
951 0 : DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
952 : nt_errstr(status));
953 0 : return status;
954 : }
955 : }
956 :
957 : /* On open checks the open itself will check the share mode, so
958 : don't do it here as we'll get it wrong. */
959 :
960 24264 : status = SMB_VFS_CREATE_FILE
961 : (conn, /* conn */
962 : req, /* req */
963 : dirfsp, /* dirfsp */
964 : smb_fname, /* fname */
965 : DELETE_ACCESS, /* access_mask */
966 : FILE_SHARE_NONE, /* share_access */
967 : FILE_OPEN, /* create_disposition*/
968 : FILE_NON_DIRECTORY_FILE |
969 : FILE_OPEN_REPARSE_POINT, /* create_options */
970 : FILE_ATTRIBUTE_NORMAL, /* file_attributes */
971 : 0, /* oplock_request */
972 : NULL, /* lease */
973 : 0, /* allocation_size */
974 : 0, /* private_flags */
975 : NULL, /* sd */
976 : NULL, /* ea_list */
977 : &fsp, /* result */
978 : NULL, /* pinfo */
979 : posx, /* in_context_blobs */
980 : NULL); /* out_context_blobs */
981 :
982 24264 : TALLOC_FREE(posx);
983 :
984 24264 : if (!NT_STATUS_IS_OK(status)) {
985 1041 : DBG_DEBUG("SMB_VFS_CREATEFILE failed: %s\n",
986 : nt_errstr(status));
987 1041 : return status;
988 : }
989 :
990 23223 : status = can_set_delete_on_close(fsp, fattr);
991 23223 : if (!NT_STATUS_IS_OK(status)) {
992 8 : DBG_DEBUG("can_set_delete_on_close for file %s - "
993 : "(%s)\n",
994 : smb_fname_str_dbg(smb_fname),
995 : nt_errstr(status));
996 8 : close_file_free(req, &fsp, NORMAL_CLOSE);
997 8 : return status;
998 : }
999 :
1000 : /* The set is across all open files on this dev/inode pair. */
1001 23215 : if (!set_delete_on_close(fsp, True,
1002 23215 : conn->session_info->security_token,
1003 23215 : conn->session_info->unix_token)) {
1004 0 : close_file_free(req, &fsp, NORMAL_CLOSE);
1005 0 : return NT_STATUS_ACCESS_DENIED;
1006 : }
1007 :
1008 23215 : return close_file_free(req, &fsp, NORMAL_CLOSE);
1009 : }
1010 :
1011 : /****************************************************************************
1012 : Fake (read/write) sendfile. Returns -1 on read or write fail.
1013 : ****************************************************************************/
1014 :
1015 12 : ssize_t fake_sendfile(struct smbXsrv_connection *xconn, files_struct *fsp,
1016 : off_t startpos, size_t nread)
1017 : {
1018 0 : size_t bufsize;
1019 12 : size_t tosend = nread;
1020 0 : char *buf;
1021 :
1022 12 : if (nread == 0) {
1023 0 : return 0;
1024 : }
1025 :
1026 12 : bufsize = MIN(nread, 65536);
1027 :
1028 12 : if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
1029 0 : return -1;
1030 : }
1031 :
1032 1716 : while (tosend > 0) {
1033 0 : ssize_t ret;
1034 0 : size_t cur_read;
1035 :
1036 1704 : cur_read = MIN(tosend, bufsize);
1037 1704 : ret = read_file(fsp,buf,startpos,cur_read);
1038 1704 : if (ret == -1) {
1039 0 : SAFE_FREE(buf);
1040 0 : return -1;
1041 : }
1042 :
1043 : /* If we had a short read, fill with zeros. */
1044 1704 : if (ret < cur_read) {
1045 0 : memset(buf + ret, '\0', cur_read - ret);
1046 : }
1047 :
1048 1704 : ret = write_data(xconn->transport.sock, buf, cur_read);
1049 1704 : if (ret != cur_read) {
1050 0 : int saved_errno = errno;
1051 : /*
1052 : * Try and give an error message saying what
1053 : * client failed.
1054 : */
1055 0 : DEBUG(0, ("write_data failed for client %s. "
1056 : "Error %s\n",
1057 : smbXsrv_connection_dbg(xconn),
1058 : strerror(saved_errno)));
1059 0 : SAFE_FREE(buf);
1060 0 : errno = saved_errno;
1061 0 : return -1;
1062 : }
1063 1704 : tosend -= cur_read;
1064 1704 : startpos += cur_read;
1065 : }
1066 :
1067 12 : SAFE_FREE(buf);
1068 12 : return (ssize_t)nread;
1069 : }
1070 :
1071 : /****************************************************************************
1072 : Deal with the case of sendfile reading less bytes from the file than
1073 : requested. Fill with zeros (all we can do). Returns 0 on success
1074 : ****************************************************************************/
1075 :
1076 0 : ssize_t sendfile_short_send(struct smbXsrv_connection *xconn,
1077 : files_struct *fsp,
1078 : ssize_t nread,
1079 : size_t headersize,
1080 : size_t smb_maxcnt)
1081 : {
1082 : #define SHORT_SEND_BUFSIZE 1024
1083 0 : if (nread < headersize) {
1084 0 : DEBUG(0,("sendfile_short_send: sendfile failed to send "
1085 : "header for file %s (%s). Terminating\n",
1086 : fsp_str_dbg(fsp), strerror(errno)));
1087 0 : return -1;
1088 : }
1089 :
1090 0 : nread -= headersize;
1091 :
1092 0 : if (nread < smb_maxcnt) {
1093 0 : char buf[SHORT_SEND_BUFSIZE] = { 0 };
1094 :
1095 0 : DEBUG(0,("sendfile_short_send: filling truncated file %s "
1096 : "with zeros !\n", fsp_str_dbg(fsp)));
1097 :
1098 0 : while (nread < smb_maxcnt) {
1099 : /*
1100 : * We asked for the real file size and told sendfile
1101 : * to not go beyond the end of the file. But it can
1102 : * happen that in between our fstat call and the
1103 : * sendfile call the file was truncated. This is very
1104 : * bad because we have already announced the larger
1105 : * number of bytes to the client.
1106 : *
1107 : * The best we can do now is to send 0-bytes, just as
1108 : * a read from a hole in a sparse file would do.
1109 : *
1110 : * This should happen rarely enough that I don't care
1111 : * about efficiency here :-)
1112 : */
1113 0 : size_t to_write;
1114 0 : ssize_t ret;
1115 :
1116 0 : to_write = MIN(SHORT_SEND_BUFSIZE, smb_maxcnt - nread);
1117 0 : ret = write_data(xconn->transport.sock, buf, to_write);
1118 0 : if (ret != to_write) {
1119 0 : int saved_errno = errno;
1120 : /*
1121 : * Try and give an error message saying what
1122 : * client failed.
1123 : */
1124 0 : DEBUG(0, ("write_data failed for client %s. "
1125 : "Error %s\n",
1126 : smbXsrv_connection_dbg(xconn),
1127 : strerror(saved_errno)));
1128 0 : errno = saved_errno;
1129 0 : return -1;
1130 : }
1131 0 : nread += to_write;
1132 : }
1133 : }
1134 :
1135 0 : return 0;
1136 : }
1137 :
1138 : /*******************************************************************
1139 : Check if a user is allowed to rename a file.
1140 : ********************************************************************/
1141 :
1142 991 : static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
1143 : uint16_t dirtype)
1144 : {
1145 18 : NTSTATUS status;
1146 :
1147 991 : if (fsp->fsp_name->twrp != 0) {
1148 : /* Get the error right, this is what Windows returns. */
1149 1 : return NT_STATUS_NOT_SAME_DEVICE;
1150 : }
1151 :
1152 990 : if (!CAN_WRITE(conn)) {
1153 0 : return NT_STATUS_MEDIA_WRITE_PROTECTED;
1154 : }
1155 :
1156 990 : if ((dirtype & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) !=
1157 : (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
1158 : /* Only bother to read the DOS attribute if we might deny the
1159 : rename on the grounds of attribute mismatch. */
1160 161 : uint32_t fmode = fdos_mode(fsp);
1161 161 : if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
1162 5 : return NT_STATUS_NO_SUCH_FILE;
1163 : }
1164 : }
1165 :
1166 985 : if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
1167 207 : if (fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) {
1168 8 : return NT_STATUS_OK;
1169 : }
1170 :
1171 : /* If no pathnames are open below this
1172 : directory, allow the rename. */
1173 :
1174 199 : if (lp_strict_rename(SNUM(conn))) {
1175 : /*
1176 : * Strict rename, check open file db.
1177 : */
1178 180 : if (have_file_open_below(fsp->conn, fsp->fsp_name)) {
1179 12 : return NT_STATUS_ACCESS_DENIED;
1180 : }
1181 19 : } else if (file_find_subpath(fsp)) {
1182 : /*
1183 : * No strict rename, just look in local process.
1184 : */
1185 3 : return NT_STATUS_ACCESS_DENIED;
1186 : }
1187 184 : return NT_STATUS_OK;
1188 : }
1189 :
1190 778 : status = check_any_access_fsp(fsp, DELETE_ACCESS | FILE_WRITE_ATTRIBUTES);
1191 778 : if (!NT_STATUS_IS_OK(status)) {
1192 0 : return status;
1193 : }
1194 778 : return NT_STATUS_OK;
1195 : }
1196 :
1197 : /****************************************************************************
1198 : Ensure open files have their names updated. Updated to notify other smbd's
1199 : asynchronously.
1200 : ****************************************************************************/
1201 :
1202 960 : static void rename_open_files(connection_struct *conn,
1203 : struct share_mode_lock *lck,
1204 : struct file_id id,
1205 : uint32_t orig_name_hash,
1206 : const struct smb_filename *smb_fname_dst)
1207 : {
1208 16 : files_struct *fsp;
1209 960 : bool did_rename = False;
1210 16 : NTSTATUS status;
1211 960 : uint32_t new_name_hash = 0;
1212 :
1213 1979 : for(fsp = file_find_di_first(conn->sconn, id, false); fsp;
1214 1019 : fsp = file_find_di_next(fsp, false)) {
1215 21 : SMB_STRUCT_STAT fsp_orig_sbuf;
1216 21 : struct file_id_buf idbuf;
1217 : /* fsp_name is a relative path under the fsp. To change this for other
1218 : sharepaths we need to manipulate relative paths. */
1219 : /* TODO - create the absolute path and manipulate the newname
1220 : relative to the sharepath. */
1221 1019 : if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
1222 0 : continue;
1223 : }
1224 1019 : if (fsp->name_hash != orig_name_hash) {
1225 0 : continue;
1226 : }
1227 1019 : DBG_DEBUG("renaming file %s "
1228 : "(file_id %s) from %s -> %s\n",
1229 : fsp_fnum_dbg(fsp),
1230 : file_id_str_buf(fsp->file_id, &idbuf),
1231 : fsp_str_dbg(fsp),
1232 : smb_fname_str_dbg(smb_fname_dst));
1233 :
1234 : /*
1235 : * The incoming smb_fname_dst here has an
1236 : * invalid stat struct (it must not have
1237 : * existed for the rename to succeed).
1238 : * Preserve the existing stat from the
1239 : * open fsp after fsp_set_smb_fname()
1240 : * overwrites with the invalid stat.
1241 : *
1242 : * We will do an fstat before returning
1243 : * any of this metadata to the client anyway.
1244 : */
1245 1019 : fsp_orig_sbuf = fsp->fsp_name->st;
1246 1019 : status = fsp_set_smb_fname(fsp, smb_fname_dst);
1247 1019 : if (NT_STATUS_IS_OK(status)) {
1248 1019 : did_rename = True;
1249 1019 : new_name_hash = fsp->name_hash;
1250 : /* Restore existing stat. */
1251 1019 : fsp->fsp_name->st = fsp_orig_sbuf;
1252 : }
1253 : }
1254 :
1255 960 : if (!did_rename) {
1256 0 : struct file_id_buf idbuf;
1257 0 : DBG_DEBUG("no open files on file_id %s "
1258 : "for %s\n",
1259 : file_id_str_buf(id, &idbuf),
1260 : smb_fname_str_dbg(smb_fname_dst));
1261 : }
1262 :
1263 : /* Send messages to all smbd's (not ourself) that the name has changed. */
1264 960 : rename_share_filename(conn->sconn->msg_ctx, lck, id, conn->connectpath,
1265 : orig_name_hash, new_name_hash,
1266 : smb_fname_dst);
1267 :
1268 960 : }
1269 :
1270 : /****************************************************************************
1271 : We need to check if the source path is a parent directory of the destination
1272 : (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
1273 : refuse the rename with a sharing violation. Under UNIX the above call can
1274 : *succeed* if /foo/bar/baz is a symlink to another area in the share. We
1275 : probably need to check that the client is a Windows one before disallowing
1276 : this as a UNIX client (one with UNIX extensions) can know the source is a
1277 : symlink and make this decision intelligently. Found by an excellent bug
1278 : report from <AndyLiebman@aol.com>.
1279 : ****************************************************************************/
1280 :
1281 970 : static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src,
1282 : const struct smb_filename *smb_fname_dst)
1283 : {
1284 970 : const char *psrc = smb_fname_src->base_name;
1285 970 : const char *pdst = smb_fname_dst->base_name;
1286 16 : size_t slen;
1287 :
1288 970 : if (psrc[0] == '.' && psrc[1] == '/') {
1289 0 : psrc += 2;
1290 : }
1291 970 : if (pdst[0] == '.' && pdst[1] == '/') {
1292 0 : pdst += 2;
1293 : }
1294 970 : if ((slen = strlen(psrc)) > strlen(pdst)) {
1295 66 : return False;
1296 : }
1297 912 : return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
1298 : }
1299 :
1300 : /*
1301 : * Do the notify calls from a rename
1302 : */
1303 :
1304 960 : static void notify_rename(connection_struct *conn, bool is_dir,
1305 : const struct smb_filename *smb_fname_src,
1306 : const struct smb_filename *smb_fname_dst)
1307 : {
1308 960 : char *parent_dir_src = NULL;
1309 960 : char *parent_dir_dst = NULL;
1310 16 : uint32_t mask;
1311 :
1312 976 : mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
1313 960 : : FILE_NOTIFY_CHANGE_FILE_NAME;
1314 :
1315 960 : if (!parent_dirname(talloc_tos(), smb_fname_src->base_name,
1316 960 : &parent_dir_src, NULL) ||
1317 960 : !parent_dirname(talloc_tos(), smb_fname_dst->base_name,
1318 : &parent_dir_dst, NULL)) {
1319 0 : goto out;
1320 : }
1321 :
1322 960 : if (strcmp(parent_dir_src, parent_dir_dst) == 0) {
1323 932 : notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask,
1324 932 : smb_fname_src->base_name);
1325 932 : notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask,
1326 932 : smb_fname_dst->base_name);
1327 : }
1328 : else {
1329 28 : notify_fname(conn, NOTIFY_ACTION_REMOVED, mask,
1330 28 : smb_fname_src->base_name);
1331 28 : notify_fname(conn, NOTIFY_ACTION_ADDED, mask,
1332 28 : smb_fname_dst->base_name);
1333 : }
1334 :
1335 : /* this is a strange one. w2k3 gives an additional event for
1336 : CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
1337 : files, but not directories */
1338 960 : if (!is_dir) {
1339 772 : notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1340 : FILE_NOTIFY_CHANGE_ATTRIBUTES
1341 : |FILE_NOTIFY_CHANGE_CREATION,
1342 772 : smb_fname_dst->base_name);
1343 : }
1344 188 : out:
1345 960 : TALLOC_FREE(parent_dir_src);
1346 960 : TALLOC_FREE(parent_dir_dst);
1347 960 : }
1348 :
1349 : /****************************************************************************
1350 : Returns an error if the parent directory for a filename is open in an
1351 : incompatible way.
1352 : ****************************************************************************/
1353 :
1354 1120 : static NTSTATUS parent_dirname_compatible_open(connection_struct *conn,
1355 : const struct smb_filename *smb_fname_dst_in)
1356 : {
1357 1120 : struct smb_filename *smb_fname_parent = NULL;
1358 20 : struct file_id id;
1359 1120 : files_struct *fsp = NULL;
1360 20 : int ret;
1361 20 : NTSTATUS status;
1362 :
1363 1120 : status = SMB_VFS_PARENT_PATHNAME(conn,
1364 : talloc_tos(),
1365 : smb_fname_dst_in,
1366 : &smb_fname_parent,
1367 : NULL);
1368 1120 : if (!NT_STATUS_IS_OK(status)) {
1369 0 : return status;
1370 : }
1371 :
1372 1120 : ret = vfs_stat(conn, smb_fname_parent);
1373 1120 : if (ret == -1) {
1374 0 : return map_nt_error_from_unix(errno);
1375 : }
1376 :
1377 : /*
1378 : * We're only checking on this smbd here, mostly good
1379 : * enough.. and will pass tests.
1380 : */
1381 :
1382 1120 : id = vfs_file_id_from_sbuf(conn, &smb_fname_parent->st);
1383 1534 : for (fsp = file_find_di_first(conn->sconn, id, true); fsp;
1384 414 : fsp = file_find_di_next(fsp, true)) {
1385 440 : if (fsp->access_mask & DELETE_ACCESS) {
1386 26 : return NT_STATUS_SHARING_VIOLATION;
1387 : }
1388 : }
1389 1094 : return NT_STATUS_OK;
1390 : }
1391 :
1392 : /****************************************************************************
1393 : Rename an open file - given an fsp.
1394 : ****************************************************************************/
1395 :
1396 1120 : NTSTATUS rename_internals_fsp(connection_struct *conn,
1397 : files_struct *fsp,
1398 : struct smb_filename *smb_fname_dst_in,
1399 : const char *dst_original_lcomp,
1400 : uint32_t attrs,
1401 : bool replace_if_exists)
1402 : {
1403 1120 : TALLOC_CTX *ctx = talloc_tos();
1404 1120 : struct smb_filename *parent_dir_fname_dst = NULL;
1405 1120 : struct smb_filename *parent_dir_fname_dst_atname = NULL;
1406 1120 : struct smb_filename *parent_dir_fname_src = NULL;
1407 1120 : struct smb_filename *parent_dir_fname_src_atname = NULL;
1408 1120 : struct smb_filename *smb_fname_dst = NULL;
1409 1120 : NTSTATUS status = NT_STATUS_OK;
1410 1120 : struct share_mode_lock *lck = NULL;
1411 1120 : uint32_t access_mask = SEC_DIR_ADD_FILE;
1412 20 : bool dst_exists, old_is_stream, new_is_stream;
1413 20 : int ret;
1414 2240 : bool case_sensitive = (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) ?
1415 1120 : true : conn->case_sensitive;
1416 2240 : bool case_preserve = (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) ?
1417 1120 : true : conn->case_preserve;
1418 :
1419 1120 : status = parent_dirname_compatible_open(conn, smb_fname_dst_in);
1420 1120 : if (!NT_STATUS_IS_OK(status)) {
1421 26 : return status;
1422 : }
1423 :
1424 1094 : if (file_has_open_streams(fsp)) {
1425 16 : return NT_STATUS_ACCESS_DENIED;
1426 : }
1427 :
1428 : /* Make a copy of the dst smb_fname structs */
1429 :
1430 1078 : smb_fname_dst = cp_smb_filename(ctx, smb_fname_dst_in);
1431 1078 : if (smb_fname_dst == NULL) {
1432 0 : status = NT_STATUS_NO_MEMORY;
1433 0 : goto out;
1434 : }
1435 :
1436 : /*
1437 : * Check for special case with case preserving and not
1438 : * case sensitive. If the new last component differs from the original
1439 : * last component only by case, then we should allow
1440 : * the rename (user is trying to change the case of the
1441 : * filename).
1442 : */
1443 2126 : if (!case_sensitive && case_preserve &&
1444 1116 : strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
1445 68 : strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
1446 28 : char *fname_dst_parent = NULL;
1447 28 : const char *fname_dst_lcomp = NULL;
1448 28 : char *orig_lcomp_path = NULL;
1449 28 : char *orig_lcomp_stream = NULL;
1450 28 : bool ok = true;
1451 :
1452 : /*
1453 : * Split off the last component of the processed
1454 : * destination name. We will compare this to
1455 : * the split components of dst_original_lcomp.
1456 : */
1457 28 : if (!parent_dirname(ctx,
1458 28 : smb_fname_dst->base_name,
1459 : &fname_dst_parent,
1460 : &fname_dst_lcomp)) {
1461 0 : status = NT_STATUS_NO_MEMORY;
1462 0 : goto out;
1463 : }
1464 :
1465 : /*
1466 : * The dst_original_lcomp component contains
1467 : * the last_component of the path + stream
1468 : * name (if a stream exists).
1469 : *
1470 : * Split off the stream name so we
1471 : * can check them separately.
1472 : */
1473 :
1474 28 : if (fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) {
1475 : /* POSIX - no stream component. */
1476 0 : orig_lcomp_path = talloc_strdup(ctx,
1477 : dst_original_lcomp);
1478 0 : if (orig_lcomp_path == NULL) {
1479 0 : ok = false;
1480 : }
1481 : } else {
1482 28 : ok = split_stream_filename(ctx,
1483 : dst_original_lcomp,
1484 : &orig_lcomp_path,
1485 : &orig_lcomp_stream);
1486 : }
1487 :
1488 28 : if (!ok) {
1489 0 : TALLOC_FREE(fname_dst_parent);
1490 0 : status = NT_STATUS_NO_MEMORY;
1491 0 : goto out;
1492 : }
1493 :
1494 : /* If the base names only differ by case, use original. */
1495 28 : if(!strcsequal(fname_dst_lcomp, orig_lcomp_path)) {
1496 2 : char *tmp;
1497 : /*
1498 : * Replace the modified last component with the
1499 : * original.
1500 : */
1501 10 : if (!ISDOT(fname_dst_parent)) {
1502 10 : tmp = talloc_asprintf(smb_fname_dst,
1503 : "%s/%s",
1504 : fname_dst_parent,
1505 : orig_lcomp_path);
1506 : } else {
1507 0 : tmp = talloc_strdup(smb_fname_dst,
1508 : orig_lcomp_path);
1509 : }
1510 10 : if (tmp == NULL) {
1511 0 : status = NT_STATUS_NO_MEMORY;
1512 0 : TALLOC_FREE(fname_dst_parent);
1513 0 : TALLOC_FREE(orig_lcomp_path);
1514 0 : TALLOC_FREE(orig_lcomp_stream);
1515 0 : goto out;
1516 : }
1517 10 : TALLOC_FREE(smb_fname_dst->base_name);
1518 10 : smb_fname_dst->base_name = tmp;
1519 : }
1520 :
1521 : /* If the stream_names only differ by case, use original. */
1522 28 : if(!strcsequal(smb_fname_dst->stream_name,
1523 : orig_lcomp_stream)) {
1524 : /* Use the original stream. */
1525 0 : char *tmp = talloc_strdup(smb_fname_dst,
1526 : orig_lcomp_stream);
1527 0 : if (tmp == NULL) {
1528 0 : status = NT_STATUS_NO_MEMORY;
1529 0 : TALLOC_FREE(fname_dst_parent);
1530 0 : TALLOC_FREE(orig_lcomp_path);
1531 0 : TALLOC_FREE(orig_lcomp_stream);
1532 0 : goto out;
1533 : }
1534 0 : TALLOC_FREE(smb_fname_dst->stream_name);
1535 0 : smb_fname_dst->stream_name = tmp;
1536 : }
1537 28 : TALLOC_FREE(fname_dst_parent);
1538 28 : TALLOC_FREE(orig_lcomp_path);
1539 28 : TALLOC_FREE(orig_lcomp_stream);
1540 : }
1541 :
1542 : /*
1543 : * If the src and dest names are identical - including case,
1544 : * don't do the rename, just return success.
1545 : */
1546 :
1547 1136 : if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
1548 58 : strcsequal(fsp->fsp_name->stream_name,
1549 58 : smb_fname_dst->stream_name)) {
1550 18 : DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
1551 : "- returning success\n",
1552 : smb_fname_str_dbg(smb_fname_dst)));
1553 18 : status = NT_STATUS_OK;
1554 18 : goto out;
1555 : }
1556 :
1557 1060 : old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
1558 1060 : new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
1559 :
1560 : /* Return the correct error code if both names aren't streams. */
1561 1060 : if (!old_is_stream && new_is_stream) {
1562 4 : status = NT_STATUS_OBJECT_NAME_INVALID;
1563 4 : goto out;
1564 : }
1565 :
1566 1056 : if (old_is_stream && !new_is_stream) {
1567 0 : status = NT_STATUS_INVALID_PARAMETER;
1568 0 : goto out;
1569 : }
1570 :
1571 1056 : dst_exists = vfs_stat(conn, smb_fname_dst) == 0;
1572 :
1573 1056 : if(!replace_if_exists && dst_exists) {
1574 57 : DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
1575 : "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
1576 : smb_fname_str_dbg(smb_fname_dst)));
1577 57 : status = NT_STATUS_OBJECT_NAME_COLLISION;
1578 57 : goto out;
1579 : }
1580 :
1581 : /*
1582 : * Drop the pathref fsp on the destination otherwise we trip upon in in
1583 : * the below check for open files check.
1584 : */
1585 999 : if (smb_fname_dst_in->fsp != NULL) {
1586 26 : fd_close(smb_fname_dst_in->fsp);
1587 26 : file_free(NULL, smb_fname_dst_in->fsp);
1588 26 : SMB_ASSERT(smb_fname_dst_in->fsp == NULL);
1589 : }
1590 :
1591 999 : if (dst_exists) {
1592 32 : struct file_id fileid = vfs_file_id_from_sbuf(conn,
1593 32 : &smb_fname_dst->st);
1594 32 : files_struct *dst_fsp = file_find_di_first(conn->sconn,
1595 : fileid, true);
1596 : /* The file can be open when renaming a stream */
1597 32 : if (dst_fsp && !new_is_stream) {
1598 8 : DEBUG(3, ("rename_internals_fsp: Target file open\n"));
1599 8 : status = NT_STATUS_ACCESS_DENIED;
1600 8 : goto out;
1601 : }
1602 : }
1603 :
1604 : /* Ensure we have a valid stat struct for the source. */
1605 991 : status = vfs_stat_fsp(fsp);
1606 991 : if (!NT_STATUS_IS_OK(status)) {
1607 0 : goto out;
1608 : }
1609 :
1610 991 : status = can_rename(conn, fsp, attrs);
1611 :
1612 991 : if (!NT_STATUS_IS_OK(status)) {
1613 21 : DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
1614 : nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
1615 : smb_fname_str_dbg(smb_fname_dst)));
1616 21 : if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
1617 0 : status = NT_STATUS_ACCESS_DENIED;
1618 21 : goto out;
1619 : }
1620 :
1621 970 : if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
1622 0 : status = NT_STATUS_ACCESS_DENIED;
1623 0 : goto out;
1624 : }
1625 :
1626 : /* Do we have rights to move into the destination ? */
1627 970 : if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
1628 : /* We're moving a directory. */
1629 192 : access_mask = SEC_DIR_ADD_SUBDIR;
1630 : }
1631 :
1632 : /*
1633 : * Get a pathref on the destination parent directory, so
1634 : * we can call check_parent_access_fsp().
1635 : */
1636 970 : status = parent_pathref(ctx,
1637 : conn->cwd_fsp,
1638 : smb_fname_dst,
1639 : &parent_dir_fname_dst,
1640 : &parent_dir_fname_dst_atname);
1641 970 : if (!NT_STATUS_IS_OK(status)) {
1642 0 : goto out;
1643 : }
1644 :
1645 970 : status = check_parent_access_fsp(parent_dir_fname_dst->fsp,
1646 : access_mask);
1647 970 : if (!NT_STATUS_IS_OK(status)) {
1648 10 : DBG_INFO("check_parent_access_fsp on "
1649 : "dst %s returned %s\n",
1650 : smb_fname_str_dbg(smb_fname_dst),
1651 : nt_errstr(status));
1652 10 : goto out;
1653 : }
1654 :
1655 : /*
1656 : * If the target existed, make sure the destination
1657 : * atname has the same stat struct.
1658 : */
1659 960 : parent_dir_fname_dst_atname->st = smb_fname_dst->st;
1660 :
1661 : /*
1662 : * It's very common that source and
1663 : * destination directories are the same.
1664 : * Optimize by not opening the
1665 : * second parent_pathref if we know
1666 : * this is the case.
1667 : */
1668 :
1669 960 : status = SMB_VFS_PARENT_PATHNAME(conn,
1670 : ctx,
1671 : fsp->fsp_name,
1672 : &parent_dir_fname_src,
1673 : &parent_dir_fname_src_atname);
1674 960 : if (!NT_STATUS_IS_OK(status)) {
1675 0 : goto out;
1676 : }
1677 :
1678 : /*
1679 : * We do a case-sensitive string comparison. We want to be *sure*
1680 : * this is the same path. The worst that can happen if
1681 : * the case doesn't match is we lose out on the optimization,
1682 : * the code still works.
1683 : *
1684 : * We can ignore twrp fields here. Rename is not allowed on
1685 : * shadow copy handles.
1686 : */
1687 :
1688 960 : if (strcmp(parent_dir_fname_src->base_name,
1689 960 : parent_dir_fname_dst->base_name) == 0) {
1690 : /*
1691 : * parent directory is the same for source
1692 : * and destination.
1693 : */
1694 : /* Reparent the src_atname to the parent_dir_dest fname. */
1695 932 : parent_dir_fname_src_atname = talloc_move(
1696 : parent_dir_fname_dst,
1697 : &parent_dir_fname_src_atname);
1698 : /* Free the unneeded duplicate parent name. */
1699 932 : TALLOC_FREE(parent_dir_fname_src);
1700 : /*
1701 : * And make the source parent name a copy of the
1702 : * destination parent name.
1703 : */
1704 932 : parent_dir_fname_src = parent_dir_fname_dst;
1705 :
1706 : /*
1707 : * Ensure we have a pathref fsp on the
1708 : * parent_dir_fname_src_atname to match the code in the else
1709 : * branch where we use parent_pathref().
1710 : */
1711 948 : status = reference_smb_fname_fsp_link(
1712 : parent_dir_fname_src_atname,
1713 932 : fsp->fsp_name);
1714 932 : if (!NT_STATUS_IS_OK(status)) {
1715 0 : goto out;
1716 : }
1717 : } else {
1718 : /*
1719 : * source and destination parent directories are
1720 : * different.
1721 : *
1722 : * Get a pathref on the source parent directory, so
1723 : * we can do a relative rename.
1724 : */
1725 28 : TALLOC_FREE(parent_dir_fname_src);
1726 28 : status = parent_pathref(ctx,
1727 : conn->cwd_fsp,
1728 28 : fsp->fsp_name,
1729 : &parent_dir_fname_src,
1730 : &parent_dir_fname_src_atname);
1731 28 : if (!NT_STATUS_IS_OK(status)) {
1732 0 : goto out;
1733 : }
1734 : }
1735 :
1736 : /*
1737 : * Some modules depend on the source smb_fname having a valid stat.
1738 : * The parent_dir_fname_src_atname is the relative name of the
1739 : * currently open file, so just copy the stat from the open fsp.
1740 : */
1741 960 : parent_dir_fname_src_atname->st = fsp->fsp_name->st;
1742 :
1743 960 : lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
1744 :
1745 : /*
1746 : * We have the file open ourselves, so not being able to get the
1747 : * corresponding share mode lock is a fatal error.
1748 : */
1749 :
1750 960 : SMB_ASSERT(lck != NULL);
1751 :
1752 960 : ret = SMB_VFS_RENAMEAT(conn,
1753 : parent_dir_fname_src->fsp,
1754 : parent_dir_fname_src_atname,
1755 : parent_dir_fname_dst->fsp,
1756 : parent_dir_fname_dst_atname);
1757 960 : if (ret == 0) {
1758 960 : uint32_t create_options = fh_get_private_options(fsp->fh);
1759 :
1760 960 : DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
1761 : "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
1762 : smb_fname_str_dbg(smb_fname_dst)));
1763 :
1764 960 : notify_rename(conn,
1765 960 : fsp->fsp_flags.is_directory,
1766 960 : fsp->fsp_name,
1767 : smb_fname_dst);
1768 :
1769 960 : rename_open_files(conn, lck, fsp->file_id, fsp->name_hash,
1770 : smb_fname_dst);
1771 :
1772 1732 : if (!fsp->fsp_flags.is_directory &&
1773 1040 : (lp_map_archive(SNUM(conn)) ||
1774 268 : lp_store_dos_attributes(SNUM(conn))))
1775 : {
1776 : /*
1777 : * We must set the archive bit on the newly renamed
1778 : * file.
1779 : */
1780 772 : status = vfs_stat_fsp(fsp);
1781 772 : if (NT_STATUS_IS_OK(status)) {
1782 12 : uint32_t old_dosmode;
1783 772 : old_dosmode = fdos_mode(fsp);
1784 : /*
1785 : * We can use fsp->fsp_name here as it has
1786 : * already been changed to the new name.
1787 : */
1788 772 : SMB_ASSERT(fsp->fsp_name->fsp == fsp);
1789 772 : file_set_dosmode(conn,
1790 : fsp->fsp_name,
1791 : old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
1792 : NULL,
1793 : true);
1794 : }
1795 : }
1796 :
1797 : /*
1798 : * A rename acts as a new file create w.r.t. allowing an initial delete
1799 : * on close, probably because in Windows there is a new handle to the
1800 : * new file. If initial delete on close was requested but not
1801 : * originally set, we need to set it here. This is probably not 100% correct,
1802 : * but will work for the CIFSFS client which in non-posix mode
1803 : * depends on these semantics. JRA.
1804 : */
1805 :
1806 960 : if (create_options & FILE_DELETE_ON_CLOSE) {
1807 0 : status = can_set_delete_on_close(fsp, 0);
1808 :
1809 0 : if (NT_STATUS_IS_OK(status)) {
1810 : /* Note that here we set the *initial* delete on close flag,
1811 : * not the regular one. The magic gets handled in close. */
1812 0 : fsp->fsp_flags.initial_delete_on_close = true;
1813 : }
1814 : }
1815 960 : TALLOC_FREE(lck);
1816 960 : status = NT_STATUS_OK;
1817 960 : goto out;
1818 : }
1819 :
1820 0 : TALLOC_FREE(lck);
1821 :
1822 0 : if (errno == ENOTDIR || errno == EISDIR) {
1823 0 : status = NT_STATUS_OBJECT_NAME_COLLISION;
1824 : } else {
1825 0 : status = map_nt_error_from_unix(errno);
1826 : }
1827 :
1828 0 : DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
1829 : nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
1830 : smb_fname_str_dbg(smb_fname_dst)));
1831 :
1832 1078 : out:
1833 :
1834 : /*
1835 : * parent_dir_fname_src may be a copy of parent_dir_fname_dst.
1836 : * See the optimization for same source and destination directory
1837 : * above. Only free one in that case.
1838 : */
1839 1078 : if (parent_dir_fname_src != parent_dir_fname_dst) {
1840 38 : TALLOC_FREE(parent_dir_fname_src);
1841 : }
1842 1078 : TALLOC_FREE(parent_dir_fname_dst);
1843 1078 : TALLOC_FREE(smb_fname_dst);
1844 :
1845 1078 : return status;
1846 : }
1847 :
1848 : /****************************************************************************
1849 : The guts of the rename command, split out so it may be called by the NT SMB
1850 : code.
1851 : ****************************************************************************/
1852 :
1853 464 : NTSTATUS rename_internals(TALLOC_CTX *ctx,
1854 : connection_struct *conn,
1855 : struct smb_request *req,
1856 : struct files_struct *src_dirfsp,
1857 : struct smb_filename *smb_fname_src,
1858 : struct smb_filename *smb_fname_dst,
1859 : const char *dst_original_lcomp,
1860 : uint32_t attrs,
1861 : bool replace_if_exists,
1862 : uint32_t access_mask)
1863 : {
1864 464 : NTSTATUS status = NT_STATUS_OK;
1865 464 : int create_options = FILE_OPEN_REPARSE_POINT;
1866 464 : struct smb2_create_blobs *posx = NULL;
1867 464 : struct files_struct *fsp = NULL;
1868 464 : bool posix_pathname = (smb_fname_src->flags & SMB_FILENAME_POSIX_PATH);
1869 464 : bool case_sensitive = posix_pathname ? true : conn->case_sensitive;
1870 464 : bool case_preserve = posix_pathname ? true : conn->case_preserve;
1871 464 : bool short_case_preserve = posix_pathname ? true :
1872 438 : conn->short_case_preserve;
1873 :
1874 464 : if (posix_pathname) {
1875 26 : status = make_smb2_posix_create_ctx(talloc_tos(), &posx, 0777);
1876 26 : if (!NT_STATUS_IS_OK(status)) {
1877 0 : DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
1878 : nt_errstr(status));
1879 0 : goto out;
1880 : }
1881 : }
1882 :
1883 464 : DBG_NOTICE("case_sensitive = %d, "
1884 : "case_preserve = %d, short case preserve = %d, "
1885 : "directory = %s, newname = %s, "
1886 : "last_component_dest = %s\n",
1887 : case_sensitive, case_preserve,
1888 : short_case_preserve,
1889 : smb_fname_str_dbg(smb_fname_src),
1890 : smb_fname_str_dbg(smb_fname_dst),
1891 : dst_original_lcomp);
1892 :
1893 464 : ZERO_STRUCT(smb_fname_src->st);
1894 :
1895 464 : status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_src);
1896 464 : if (!NT_STATUS_IS_OK(status)) {
1897 14 : if (!NT_STATUS_EQUAL(status,
1898 : NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1899 0 : goto out;
1900 : }
1901 : /*
1902 : * Possible symlink src.
1903 : */
1904 14 : if (!(smb_fname_src->flags & SMB_FILENAME_POSIX_PATH)) {
1905 14 : goto out;
1906 : }
1907 0 : if (!S_ISLNK(smb_fname_src->st.st_ex_mode)) {
1908 0 : goto out;
1909 : }
1910 : }
1911 :
1912 450 : if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
1913 0 : create_options |= FILE_DIRECTORY_FILE;
1914 : }
1915 :
1916 450 : status = SMB_VFS_CREATE_FILE(
1917 : conn, /* conn */
1918 : req, /* req */
1919 : src_dirfsp, /* dirfsp */
1920 : smb_fname_src, /* fname */
1921 : access_mask, /* access_mask */
1922 : (FILE_SHARE_READ | /* share_access */
1923 : FILE_SHARE_WRITE),
1924 : FILE_OPEN, /* create_disposition*/
1925 : create_options, /* create_options */
1926 : 0, /* file_attributes */
1927 : 0, /* oplock_request */
1928 : NULL, /* lease */
1929 : 0, /* allocation_size */
1930 : 0, /* private_flags */
1931 : NULL, /* sd */
1932 : NULL, /* ea_list */
1933 : &fsp, /* result */
1934 : NULL, /* pinfo */
1935 : posx, /* in_context_blobs */
1936 : NULL); /* out_context_blobs */
1937 :
1938 450 : if (!NT_STATUS_IS_OK(status)) {
1939 72 : DBG_NOTICE("Could not open rename source %s: %s\n",
1940 : smb_fname_str_dbg(smb_fname_src),
1941 : nt_errstr(status));
1942 72 : goto out;
1943 : }
1944 :
1945 378 : status = rename_internals_fsp(conn,
1946 : fsp,
1947 : smb_fname_dst,
1948 : dst_original_lcomp,
1949 : attrs,
1950 : replace_if_exists);
1951 :
1952 378 : close_file_free(req, &fsp, NORMAL_CLOSE);
1953 :
1954 378 : DBG_NOTICE("Error %s rename %s -> %s\n",
1955 : nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
1956 : smb_fname_str_dbg(smb_fname_dst));
1957 :
1958 464 : out:
1959 464 : TALLOC_FREE(posx);
1960 464 : return status;
1961 : }
1962 :
1963 : /*******************************************************************
1964 : Copy a file as part of a reply_copy.
1965 : ******************************************************************/
1966 :
1967 : /*
1968 : * TODO: check error codes on all callers
1969 : */
1970 :
1971 16 : NTSTATUS copy_file(TALLOC_CTX *ctx,
1972 : connection_struct *conn,
1973 : struct smb_filename *smb_fname_src,
1974 : struct smb_filename *smb_fname_dst,
1975 : uint32_t new_create_disposition)
1976 : {
1977 16 : struct smb_filename *smb_fname_dst_tmp = NULL;
1978 16 : off_t ret=-1;
1979 0 : files_struct *fsp1,*fsp2;
1980 0 : uint32_t dosattrs;
1981 0 : NTSTATUS status;
1982 :
1983 :
1984 16 : smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
1985 16 : if (smb_fname_dst_tmp == NULL) {
1986 0 : return NT_STATUS_NO_MEMORY;
1987 : }
1988 :
1989 16 : status = vfs_file_exist(conn, smb_fname_src);
1990 16 : if (!NT_STATUS_IS_OK(status)) {
1991 0 : goto out;
1992 : }
1993 :
1994 16 : status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_src);
1995 16 : if (!NT_STATUS_IS_OK(status)) {
1996 0 : goto out;
1997 : }
1998 :
1999 : /* Open the src file for reading. */
2000 16 : status = SMB_VFS_CREATE_FILE(
2001 : conn, /* conn */
2002 : NULL, /* req */
2003 : NULL, /* dirfsp */
2004 : smb_fname_src, /* fname */
2005 : FILE_GENERIC_READ, /* access_mask */
2006 : FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2007 : FILE_OPEN, /* create_disposition*/
2008 : 0, /* create_options */
2009 : FILE_ATTRIBUTE_NORMAL, /* file_attributes */
2010 : INTERNAL_OPEN_ONLY, /* oplock_request */
2011 : NULL, /* lease */
2012 : 0, /* allocation_size */
2013 : 0, /* private_flags */
2014 : NULL, /* sd */
2015 : NULL, /* ea_list */
2016 : &fsp1, /* result */
2017 : NULL, /* psbuf */
2018 : NULL, NULL); /* create context */
2019 :
2020 16 : if (!NT_STATUS_IS_OK(status)) {
2021 0 : goto out;
2022 : }
2023 :
2024 16 : dosattrs = fdos_mode(fsp1);
2025 :
2026 16 : if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
2027 16 : ZERO_STRUCTP(&smb_fname_dst_tmp->st);
2028 : }
2029 :
2030 16 : status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_dst);
2031 16 : if (!NT_STATUS_IS_OK(status) &&
2032 16 : !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND))
2033 : {
2034 0 : goto out;
2035 : }
2036 :
2037 : /* Open the dst file for writing. */
2038 16 : status = SMB_VFS_CREATE_FILE(
2039 : conn, /* conn */
2040 : NULL, /* req */
2041 : NULL, /* dirfsp */
2042 : smb_fname_dst, /* fname */
2043 : FILE_GENERIC_WRITE, /* access_mask */
2044 : FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
2045 : new_create_disposition, /* create_disposition*/
2046 : 0, /* create_options */
2047 : dosattrs, /* file_attributes */
2048 : INTERNAL_OPEN_ONLY, /* oplock_request */
2049 : NULL, /* lease */
2050 : 0, /* allocation_size */
2051 : 0, /* private_flags */
2052 : NULL, /* sd */
2053 : NULL, /* ea_list */
2054 : &fsp2, /* result */
2055 : NULL, /* psbuf */
2056 : NULL, NULL); /* create context */
2057 :
2058 16 : if (!NT_STATUS_IS_OK(status)) {
2059 0 : close_file_free(NULL, &fsp1, ERROR_CLOSE);
2060 0 : goto out;
2061 : }
2062 :
2063 : /* Do the actual copy. */
2064 16 : if (smb_fname_src->st.st_ex_size) {
2065 16 : ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
2066 : } else {
2067 0 : ret = 0;
2068 : }
2069 :
2070 16 : close_file_free(NULL, &fsp1, NORMAL_CLOSE);
2071 :
2072 : /* Ensure the modtime is set correctly on the destination file. */
2073 16 : set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
2074 :
2075 : /*
2076 : * As we are opening fsp1 read-only we only expect
2077 : * an error on close on fsp2 if we are out of space.
2078 : * Thus we don't look at the error return from the
2079 : * close of fsp1.
2080 : */
2081 16 : status = close_file_free(NULL, &fsp2, NORMAL_CLOSE);
2082 :
2083 16 : if (!NT_STATUS_IS_OK(status)) {
2084 0 : goto out;
2085 : }
2086 :
2087 16 : if (ret != (off_t)smb_fname_src->st.st_ex_size) {
2088 0 : status = NT_STATUS_DISK_FULL;
2089 0 : goto out;
2090 : }
2091 :
2092 16 : status = NT_STATUS_OK;
2093 :
2094 16 : out:
2095 16 : TALLOC_FREE(smb_fname_dst_tmp);
2096 16 : return status;
2097 : }
2098 :
2099 : /****************************************************************************
2100 : Get a lock offset, dealing with large offset requests.
2101 : ****************************************************************************/
2102 :
2103 5671 : uint64_t get_lock_offset(const uint8_t *data, int data_offset,
2104 : bool large_file_format)
2105 : {
2106 5671 : uint64_t offset = 0;
2107 :
2108 5671 : if(!large_file_format) {
2109 5151 : offset = (uint64_t)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
2110 : } else {
2111 : /*
2112 : * No BVAL, this is reversed!
2113 : */
2114 520 : offset = (((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
2115 520 : ((uint64_t) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
2116 : }
2117 :
2118 5671 : return offset;
2119 : }
2120 :
2121 : struct smbd_do_unlocking_state {
2122 : struct files_struct *fsp;
2123 : uint16_t num_ulocks;
2124 : struct smbd_lock_element *ulocks;
2125 : NTSTATUS status;
2126 : };
2127 :
2128 2296 : static void smbd_do_unlocking_fn(
2129 : struct share_mode_lock *lck,
2130 : void *private_data)
2131 : {
2132 2296 : struct smbd_do_unlocking_state *state = private_data;
2133 2296 : struct files_struct *fsp = state->fsp;
2134 14 : uint16_t i;
2135 :
2136 4422 : for (i = 0; i < state->num_ulocks; i++) {
2137 2338 : struct smbd_lock_element *e = &state->ulocks[i];
2138 :
2139 2338 : DBG_DEBUG("unlock start=%"PRIu64", len=%"PRIu64" for "
2140 : "pid %"PRIu64", file %s\n",
2141 : e->offset,
2142 : e->count,
2143 : e->smblctx,
2144 : fsp_str_dbg(fsp));
2145 :
2146 2338 : if (e->brltype != UNLOCK_LOCK) {
2147 : /* this can only happen with SMB2 */
2148 8 : state->status = NT_STATUS_INVALID_PARAMETER;
2149 8 : return;
2150 : }
2151 :
2152 2330 : state->status = do_unlock(
2153 : fsp, e->smblctx, e->count, e->offset, e->lock_flav);
2154 :
2155 2330 : DBG_DEBUG("do_unlock returned %s\n",
2156 : nt_errstr(state->status));
2157 :
2158 2330 : if (!NT_STATUS_IS_OK(state->status)) {
2159 200 : return;
2160 : }
2161 : }
2162 :
2163 2084 : share_mode_wakeup_waiters(fsp->file_id);
2164 : }
2165 :
2166 2296 : NTSTATUS smbd_do_unlocking(struct smb_request *req,
2167 : files_struct *fsp,
2168 : uint16_t num_ulocks,
2169 : struct smbd_lock_element *ulocks)
2170 : {
2171 2296 : struct smbd_do_unlocking_state state = {
2172 : .fsp = fsp,
2173 : .num_ulocks = num_ulocks,
2174 : .ulocks = ulocks,
2175 : };
2176 14 : NTSTATUS status;
2177 :
2178 2296 : DBG_NOTICE("%s num_ulocks=%"PRIu16"\n", fsp_fnum_dbg(fsp), num_ulocks);
2179 :
2180 2296 : status = share_mode_do_locked_vfs_allowed(
2181 : fsp->file_id, smbd_do_unlocking_fn, &state);
2182 :
2183 2296 : if (!NT_STATUS_IS_OK(status)) {
2184 0 : DBG_DEBUG("share_mode_do_locked_vfs_allowed failed: %s\n",
2185 : nt_errstr(status));
2186 0 : return status;
2187 : }
2188 2296 : if (!NT_STATUS_IS_OK(state.status)) {
2189 212 : DBG_DEBUG("smbd_do_unlocking_fn failed: %s\n",
2190 : nt_errstr(status));
2191 212 : return state.status;
2192 : }
2193 :
2194 2084 : return NT_STATUS_OK;
2195 : }
|