2 Unix SMB/Netbios implementation.
4 MSDFS services for Samba
5 Copyright (C) Shirish Kalele 2000
6 Copyright (C) Jeremy Allison 2007
7 Copyright (C) Robin McCorkell 2015
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/>.
24 #define DBGC_CLASS DBGC_MSDFS
26 #include "system/filesys.h"
27 #include "smbd/smbd.h"
28 #include "smbd/globals.h"
31 #include "../auth/auth_util.h"
32 #include "lib/param/loadparm.h"
33 #include "libcli/security/security.h"
34 #include "librpc/gen_ndr/ndr_dfsblobs.h"
35 #include "lib/tsocket/tsocket.h"
37 /**********************************************************************
38 Parse a DFS pathname of the form \hostname\service\reqpath
39 into the dfs_path structure.
40 If POSIX pathnames is true, the pathname may also be of the
41 form /hostname/service/reqpath.
42 We cope with either here.
44 Unfortunately, due to broken clients who might set the
45 SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
46 send a local path, we have to cope with that too....
48 If conn != NULL then ensure the provided service is
49 the one pointed to by the connection.
51 This version does everything using pointers within one copy of the
52 pathname string, talloced on the struct dfs_path pointer (which
53 must be talloced). This may be too clever to live....
55 **********************************************************************/
57 static NTSTATUS
parse_dfs_path(connection_struct
*conn
,
60 bool allow_broken_path
,
61 struct dfs_path
*pdp
, /* MUST BE TALLOCED */
62 bool *ppath_contains_wcard
)
68 NTSTATUS status
= NT_STATUS_OK
;
74 * This is the only talloc we should need to do
75 * on the struct dfs_path. All the pointers inside
76 * it should point to offsets within this string.
79 pathname_local
= talloc_strdup(pdp
, pathname
);
80 if (!pathname_local
) {
81 return NT_STATUS_NO_MEMORY
;
83 /* Get a pointer to the terminating '\0' */
84 eos_ptr
= &pathname_local
[strlen(pathname_local
)];
85 p
= temp
= pathname_local
;
88 * Non-broken DFS paths *must* start with the
89 * path separator. For Windows this is always '\\',
90 * for posix paths this is always '/'.
93 if (*pathname
== '/') {
94 pdp
->posix_path
= true;
97 pdp
->posix_path
= false;
101 if (allow_broken_path
&& (*pathname
!= sepchar
)) {
102 DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
103 pathname
, sepchar
));
105 * Possibly client sent a local path by mistake.
106 * Try and convert to a local path.
107 * Note that this is an SMB1-only fallback
108 * to cope with known broken SMB1 clients.
111 pdp
->hostname
= eos_ptr
; /* "" */
112 pdp
->servicename
= eos_ptr
; /* "" */
114 /* We've got no info about separators. */
115 pdp
->posix_path
= lp_posix_pathnames();
117 DEBUG(10,("parse_dfs_path: trying to convert %s to a "
124 * Safe to use on talloc'ed string as it only shrinks.
125 * It also doesn't affect the eos_ptr.
127 trim_char(temp
,sepchar
,sepchar
);
129 DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
133 /* Parse out hostname. */
134 p
= strchr_m(temp
,sepchar
);
136 DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
139 * Possibly client sent a local path by mistake.
140 * Try and convert to a local path.
143 pdp
->hostname
= eos_ptr
; /* "" */
144 pdp
->servicename
= eos_ptr
; /* "" */
147 DEBUG(10,("parse_dfs_path: trying to convert %s "
153 pdp
->hostname
= temp
;
155 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp
->hostname
));
157 /* Parse out servicename. */
159 p
= strchr_m(servicename
,sepchar
);
164 /* Is this really our servicename ? */
165 if (conn
&& !( strequal(servicename
, lp_servicename(talloc_tos(), SNUM(conn
)))
166 || (strequal(servicename
, HOMES_NAME
)
167 && strequal(lp_servicename(talloc_tos(), SNUM(conn
)),
168 get_current_username()) )) ) {
169 DEBUG(10,("parse_dfs_path: %s is not our servicename\n",
173 * Possibly client sent a local path by mistake.
174 * Try and convert to a local path.
177 pdp
->hostname
= eos_ptr
; /* "" */
178 pdp
->servicename
= eos_ptr
; /* "" */
180 /* Repair the path - replace the sepchar's
183 *servicename
= sepchar
;
189 DEBUG(10,("parse_dfs_path: trying to convert %s "
195 pdp
->servicename
= servicename
;
197 DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp
->servicename
));
200 /* Client sent self referral \server\share. */
201 pdp
->reqpath
= eos_ptr
; /* "" */
209 *ppath_contains_wcard
= False
;
213 /* Rest is reqpath. */
214 if (pdp
->posix_path
) {
215 status
= check_path_syntax_posix(pdp
->reqpath
);
218 status
= check_path_syntax_wcard(pdp
->reqpath
,
219 ppath_contains_wcard
);
221 status
= check_path_syntax(pdp
->reqpath
);
225 if (!NT_STATUS_IS_OK(status
)) {
226 DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
227 p
, nt_errstr(status
) ));
231 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp
->reqpath
));
235 /********************************************************
236 Fake up a connection struct for the VFS layer, for use in
237 applications (such as the python bindings), that do not want the
238 global working directory changed under them.
240 SMB_VFS_CONNECT requires root privileges.
241 *********************************************************/
243 static NTSTATUS
create_conn_struct_as_root(TALLOC_CTX
*ctx
,
244 struct messaging_context
*msg
,
245 connection_struct
**pconn
,
248 const struct auth_session_info
*session_info
)
250 connection_struct
*conn
;
252 const char *vfs_user
;
253 struct smbd_server_connection
*sconn
;
254 const char *servicename
= lp_const_servicename(snum
);
256 sconn
= talloc_zero(ctx
, struct smbd_server_connection
);
258 return NT_STATUS_NO_MEMORY
;
261 sconn
->ev_ctx
= samba_tevent_context_init(sconn
);
262 if (sconn
->ev_ctx
== NULL
) {
264 return NT_STATUS_NO_MEMORY
;
267 sconn
->msg_ctx
= msg
;
269 conn
= conn_new(sconn
);
272 return NT_STATUS_NO_MEMORY
;
275 /* Now we have conn, we need to make sconn a child of conn,
276 * for a proper talloc tree */
277 talloc_steal(conn
, sconn
);
279 if (snum
== -1 && servicename
== NULL
) {
280 servicename
= "Unknown Service (snum == -1)";
283 connpath
= talloc_strdup(conn
, path
);
286 return NT_STATUS_NO_MEMORY
;
288 connpath
= talloc_string_sub(conn
,
294 return NT_STATUS_NO_MEMORY
;
297 /* needed for smbd_vfs_init() */
299 conn
->params
->service
= snum
;
300 conn
->cnum
= TID_FIELD_INVALID
;
302 if (session_info
!= NULL
) {
303 conn
->session_info
= copy_session_info(conn
, session_info
);
304 if (conn
->session_info
== NULL
) {
305 DEBUG(0, ("copy_serverinfo failed\n"));
307 return NT_STATUS_NO_MEMORY
;
309 /* unix_info could be NULL in session_info */
310 if (conn
->session_info
->unix_info
!= NULL
) {
311 vfs_user
= conn
->session_info
->unix_info
->unix_name
;
313 vfs_user
= get_current_username();
316 /* use current authenticated user in absence of session_info */
317 vfs_user
= get_current_username();
320 set_conn_connectpath(conn
, connpath
);
323 * New code to check if there's a share security descriptor
324 * added from NT server manager. This is done after the
325 * smb.conf checks are done as we need a uid and token. JRA.
328 if (conn
->session_info
) {
329 share_access_check(conn
->session_info
->security_token
,
331 MAXIMUM_ALLOWED_ACCESS
,
332 &conn
->share_access
);
334 if ((conn
->share_access
& FILE_WRITE_DATA
) == 0) {
335 if ((conn
->share_access
& FILE_READ_DATA
) == 0) {
336 /* No access, read or write. */
337 DEBUG(3,("create_conn_struct: connection to %s "
338 "denied due to security "
342 return NT_STATUS_ACCESS_DENIED
;
344 conn
->read_only
= true;
348 conn
->share_access
= 0;
349 conn
->read_only
= true;
352 if (!smbd_vfs_init(conn
)) {
353 NTSTATUS status
= map_nt_error_from_unix(errno
);
354 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
359 /* this must be the first filesystem operation that we do */
360 if (SMB_VFS_CONNECT(conn
, servicename
, vfs_user
) < 0) {
361 DEBUG(0,("VFS connect failed!\n"));
363 return NT_STATUS_UNSUCCESSFUL
;
366 talloc_free(conn
->origpath
);
367 conn
->origpath
= talloc_strdup(conn
, conn
->connectpath
);
368 if (conn
->origpath
== NULL
) {
370 return NT_STATUS_NO_MEMORY
;
373 conn
->fs_capabilities
= SMB_VFS_FS_CAPABILITIES(conn
, &conn
->ts_res
);
374 conn
->tcon_done
= true;
375 *pconn
= talloc_move(ctx
, &conn
);
380 static int conn_struct_tos_destructor(struct conn_struct_tos
*c
)
382 if (c
->oldcwd_fname
!= NULL
) {
383 vfs_ChDir(c
->conn
, c
->oldcwd_fname
);
384 TALLOC_FREE(c
->oldcwd_fname
);
386 SMB_VFS_DISCONNECT(c
->conn
);
391 /********************************************************
392 Fake up a connection struct for the VFS layer, for use in
393 applications (such as the python bindings), that do not want the
394 global working directory changed under them.
396 SMB_VFS_CONNECT requires root privileges.
397 This temporary uses become_root() and unbecome_root().
399 But further impersonation has to be cone by the caller.
400 *********************************************************/
401 NTSTATUS
create_conn_struct_tos(struct messaging_context
*msg
,
404 const struct auth_session_info
*session_info
,
405 struct conn_struct_tos
**_c
)
407 struct conn_struct_tos
*c
= NULL
;
412 c
= talloc_zero(talloc_tos(), struct conn_struct_tos
);
414 return NT_STATUS_NO_MEMORY
;
418 status
= create_conn_struct_as_root(c
,
425 if (!NT_STATUS_IS_OK(status
)) {
430 talloc_set_destructor(c
, conn_struct_tos_destructor
);
436 /********************************************************
437 Fake up a connection struct for the VFS layer.
438 Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
440 See also the comment for create_conn_struct_tos() above!
442 The CWD change is reverted by the destructor of
443 conn_struct_tos when the current talloc_tos() is destroyed.
444 *********************************************************/
445 NTSTATUS
create_conn_struct_tos_cwd(struct messaging_context
*msg
,
448 const struct auth_session_info
*session_info
,
449 struct conn_struct_tos
**_c
)
451 struct conn_struct_tos
*c
= NULL
;
452 struct smb_filename smb_fname_connectpath
= {0};
457 status
= create_conn_struct_tos(msg
,
462 if (!NT_STATUS_IS_OK(status
)) {
467 * Windows seems to insist on doing trans2getdfsreferral() calls on
468 * the IPC$ share as the anonymous user. If we try to chdir as that
469 * user we will fail.... WTF ? JRA.
472 c
->oldcwd_fname
= vfs_GetWd(c
, c
->conn
);
473 if (c
->oldcwd_fname
== NULL
) {
474 status
= map_nt_error_from_unix(errno
);
475 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno
)));
480 smb_fname_connectpath
= (struct smb_filename
) {
481 .base_name
= c
->conn
->connectpath
484 if (vfs_ChDir(c
->conn
, &smb_fname_connectpath
) != 0) {
485 status
= map_nt_error_from_unix(errno
);
486 DBG_NOTICE("Can't ChDir to new conn path %s. "
488 c
->conn
->connectpath
, strerror(errno
));
489 TALLOC_FREE(c
->oldcwd_fname
);
498 static void shuffle_strlist(char **list
, int count
)
504 for (i
= count
; i
> 1; i
--) {
505 r
= generate_random() % i
;
513 /**********************************************************************
514 Parse the contents of a symlink to verify if it is an msdfs referral
515 A valid referral is of the form:
517 msdfs:server1\share1,server2\share2
518 msdfs:server1\share1\pathname,server2\share2\pathname
519 msdfs:server1/share1,server2/share2
520 msdfs:server1/share1/pathname,server2/share2/pathname.
522 Note that the alternate paths returned here must be of the canonicalized
526 \server\share\path\to\file,
528 even in posix path mode. This is because we have no knowledge if the
529 server we're referring to understands posix paths.
530 **********************************************************************/
532 static bool parse_msdfs_symlink(TALLOC_CTX
*ctx
,
535 struct referral
**preflist
,
540 char **alt_path
= NULL
;
542 struct referral
*reflist
;
545 temp
= talloc_strdup(ctx
, target
);
549 prot
= strtok_r(temp
, ":", &saveptr
);
551 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
555 alt_path
= talloc_array(ctx
, char *, MAX_REFERRAL_COUNT
);
560 /* parse out the alternate paths */
561 while((count
<MAX_REFERRAL_COUNT
) &&
562 ((alt_path
[count
] = strtok_r(NULL
, ",", &saveptr
)) != NULL
)) {
566 /* shuffle alternate paths */
567 if (lp_msdfs_shuffle_referrals(snum
)) {
568 shuffle_strlist(alt_path
, count
);
571 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count
));
574 reflist
= *preflist
= talloc_zero_array(ctx
,
575 struct referral
, count
);
576 if(reflist
== NULL
) {
577 TALLOC_FREE(alt_path
);
581 reflist
= *preflist
= NULL
;
584 for(i
=0;i
<count
;i
++) {
587 /* Canonicalize link target.
588 * Replace all /'s in the path by a \ */
589 string_replace(alt_path
[i
], '/', '\\');
591 /* Remove leading '\\'s */
593 while (*p
&& (*p
== '\\')) {
597 reflist
[i
].alternate_path
= talloc_asprintf(ctx
,
600 if (!reflist
[i
].alternate_path
) {
604 reflist
[i
].proximity
= 0;
605 reflist
[i
].ttl
= REFERRAL_TTL
;
606 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
607 reflist
[i
].alternate_path
));
612 TALLOC_FREE(alt_path
);
616 /**********************************************************************
617 Returns true if the unix path is a valid msdfs symlink and also
618 returns the target string from inside the link.
619 **********************************************************************/
621 static bool is_msdfs_link_internal(TALLOC_CTX
*ctx
,
622 connection_struct
*conn
,
623 struct smb_filename
*smb_fname
,
624 char **pp_link_target
)
626 int referral_len
= 0;
627 #if defined(HAVE_BROKEN_READLINK)
628 char link_target_buf
[PATH_MAX
];
630 char link_target_buf
[7];
633 char *link_target
= NULL
;
635 if (pp_link_target
) {
637 link_target
= talloc_array(ctx
, char, bufsize
);
641 *pp_link_target
= link_target
;
643 bufsize
= sizeof(link_target_buf
);
644 link_target
= link_target_buf
;
647 if (SMB_VFS_LSTAT(conn
, smb_fname
) != 0) {
648 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
649 smb_fname
->base_name
));
652 if (!S_ISLNK(smb_fname
->st
.st_ex_mode
)) {
653 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
654 smb_fname
->base_name
));
658 referral_len
= SMB_VFS_READLINK(conn
, smb_fname
,
659 link_target
, bufsize
- 1);
660 if (referral_len
== -1) {
661 DEBUG(0,("is_msdfs_link_read_target: Error reading "
662 "msdfs link %s: %s\n",
663 smb_fname
->base_name
, strerror(errno
)));
666 link_target
[referral_len
] = '\0';
668 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n", smb_fname
->base_name
,
671 if (!strnequal(link_target
, "msdfs:", 6)) {
678 if (link_target
!= link_target_buf
) {
679 TALLOC_FREE(link_target
);
684 /**********************************************************************
685 Returns true if the unix path is a valid msdfs symlink.
686 **********************************************************************/
688 bool is_msdfs_link(connection_struct
*conn
,
689 struct smb_filename
*smb_fname
)
691 return is_msdfs_link_internal(talloc_tos(),
697 /*****************************************************************
698 Used by other functions to decide if a dfs path is remote,
699 and to get the list of referred locations for that remote path.
701 search_flag: For findfirsts, dfs links themselves are not
702 redirected, but paths beyond the links are. For normal smb calls,
703 even dfs links need to be redirected.
705 consumedcntp: how much of the dfs path is being redirected. the client
706 should try the remaining path on the redirected server.
708 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
709 link redirect are in targetpath.
710 *****************************************************************/
712 static NTSTATUS
dfs_path_lookup(TALLOC_CTX
*ctx
,
713 connection_struct
*conn
,
714 const char *dfspath
, /* Incoming complete dfs path */
715 const struct dfs_path
*pdp
, /* Parsed out
716 server+share+extrapath. */
719 char **pp_targetpath
)
724 struct smb_filename
*smb_fname
= NULL
;
725 char *canon_dfspath
= NULL
; /* Canonicalized dfs path. (only '/'
728 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
729 conn
->connectpath
, pdp
->reqpath
));
732 * Note the unix path conversion here we're doing we
733 * throw away. We're looking for a symlink for a dfs
734 * resolution, if we don't find it we'll do another
735 * unix_convert later in the codepath.
738 status
= unix_convert(ctx
, conn
, pdp
->reqpath
, &smb_fname
,
741 if (!NT_STATUS_IS_OK(status
)) {
742 if (!NT_STATUS_EQUAL(status
,
743 NT_STATUS_OBJECT_PATH_NOT_FOUND
)) {
746 if (smb_fname
== NULL
|| smb_fname
->base_name
== NULL
) {
751 /* Optimization - check if we can redirect the whole path. */
753 if (is_msdfs_link_internal(ctx
, conn
, smb_fname
, pp_targetpath
)) {
754 /* XX_ALLOW_WCARD_XXX is called from search functions. */
756 (UCF_COND_ALLOW_WCARD_LCOMP
|
757 UCF_ALWAYS_ALLOW_WCARD_LCOMP
)) {
758 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
759 "for dfs link %s.\n", dfspath
));
760 status
= NT_STATUS_OK
;
764 DEBUG(6,("dfs_path_lookup: %s resolves to a "
765 "valid dfs link %s.\n", dfspath
,
766 pp_targetpath
? *pp_targetpath
: ""));
769 *consumedcntp
= strlen(dfspath
);
771 status
= NT_STATUS_PATH_NOT_COVERED
;
775 /* Prepare to test only for '/' components in the given path,
776 * so if a Windows path replace all '\\' characters with '/'.
777 * For a POSIX DFS path we know all separators are already '/'. */
779 canon_dfspath
= talloc_strdup(ctx
, dfspath
);
780 if (!canon_dfspath
) {
781 status
= NT_STATUS_NO_MEMORY
;
784 if (!pdp
->posix_path
) {
785 string_replace(canon_dfspath
, '\\', '/');
789 * localpath comes out of unix_convert, so it has
790 * no trailing backslash. Make sure that canon_dfspath hasn't either.
791 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
794 trim_char(canon_dfspath
,0,'/');
797 * Redirect if any component in the path is a link.
798 * We do this by walking backwards through the
799 * local path, chopping off the last component
800 * in both the local path and the canonicalized
801 * DFS path. If we hit a DFS link then we're done.
804 p
= strrchr_m(smb_fname
->base_name
, '/');
806 q
= strrchr_m(canon_dfspath
, '/');
815 if (is_msdfs_link_internal(ctx
, conn
,
816 smb_fname
, pp_targetpath
)) {
817 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
818 "parent %s is dfs link\n", dfspath
,
819 smb_fname_str_dbg(smb_fname
)));
822 *consumedcntp
= strlen(canon_dfspath
);
823 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
829 status
= NT_STATUS_PATH_NOT_COVERED
;
833 /* Step back on the filesystem. */
834 p
= strrchr_m(smb_fname
->base_name
, '/');
837 /* And in the canonicalized dfs path. */
838 q
= strrchr_m(canon_dfspath
, '/');
842 status
= NT_STATUS_OK
;
844 TALLOC_FREE(smb_fname
);
848 /*****************************************************************
849 Decides if a dfs pathname should be redirected or not.
850 If not, the pathname is converted to a tcon-relative local unix path
852 search_wcard_flag: this flag performs 2 functions both related
853 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
856 This function can return NT_STATUS_OK, meaning use the returned path as-is
857 (mapped into a local path).
858 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
859 any other NT_STATUS error which is a genuine error to be
860 returned to the client.
861 *****************************************************************/
863 static NTSTATUS
dfs_redirect(TALLOC_CTX
*ctx
,
864 connection_struct
*conn
,
867 bool allow_broken_path
,
869 bool *ppath_contains_wcard
)
872 bool search_wcard_flag
= (ucf_flags
&
873 (UCF_COND_ALLOW_WCARD_LCOMP
|UCF_ALWAYS_ALLOW_WCARD_LCOMP
));
874 struct dfs_path
*pdp
= talloc(ctx
, struct dfs_path
);
877 return NT_STATUS_NO_MEMORY
;
880 status
= parse_dfs_path(conn
, path_in
, search_wcard_flag
,
881 allow_broken_path
, pdp
,
882 ppath_contains_wcard
);
883 if (!NT_STATUS_IS_OK(status
)) {
888 if (pdp
->reqpath
[0] == '\0') {
890 *pp_path_out
= talloc_strdup(ctx
, "");
892 return NT_STATUS_NO_MEMORY
;
894 DEBUG(5,("dfs_redirect: self-referral.\n"));
898 /* If dfs pathname for a non-dfs share, convert to tcon-relative
899 path and return OK */
901 if (!lp_msdfs_root(SNUM(conn
))) {
902 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
905 return NT_STATUS_NO_MEMORY
;
910 /* If it looked like a local path (zero hostname/servicename)
911 * just treat as a tcon-relative path. */
913 if (pdp
->hostname
[0] == '\0' && pdp
->servicename
[0] == '\0') {
914 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
917 return NT_STATUS_NO_MEMORY
;
922 if (!( strequal(pdp
->servicename
, lp_servicename(talloc_tos(), SNUM(conn
)))
923 || (strequal(pdp
->servicename
, HOMES_NAME
)
924 && strequal(lp_servicename(talloc_tos(), SNUM(conn
)),
925 conn
->session_info
->unix_info
->sanitized_username
) )) ) {
927 /* The given sharename doesn't match this connection. */
930 return NT_STATUS_OBJECT_PATH_NOT_FOUND
;
933 status
= dfs_path_lookup(ctx
, conn
, path_in
, pdp
,
934 ucf_flags
, NULL
, NULL
);
935 if (!NT_STATUS_IS_OK(status
)) {
936 if (NT_STATUS_EQUAL(status
, NT_STATUS_PATH_NOT_COVERED
)) {
937 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in
));
939 DEBUG(10,("dfs_redirect: dfs_path_lookup "
940 "failed for %s with %s\n",
941 path_in
, nt_errstr(status
) ));
946 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in
));
948 /* Form non-dfs tcon-relative path */
949 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
952 return NT_STATUS_NO_MEMORY
;
955 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
962 /**********************************************************************
963 Return a self referral.
964 **********************************************************************/
966 static NTSTATUS
self_ref(TALLOC_CTX
*ctx
,
967 const char *dfs_path
,
968 struct junction_map
*jucn
,
970 bool *self_referralp
)
972 struct referral
*ref
;
974 *self_referralp
= True
;
976 jucn
->referral_count
= 1;
977 if((ref
= talloc_zero(ctx
, struct referral
)) == NULL
) {
978 return NT_STATUS_NO_MEMORY
;
981 ref
->alternate_path
= talloc_strdup(ctx
, dfs_path
);
982 if (!ref
->alternate_path
) {
984 return NT_STATUS_NO_MEMORY
;
987 ref
->ttl
= REFERRAL_TTL
;
988 jucn
->referral_list
= ref
;
989 *consumedcntp
= strlen(dfs_path
);
993 /**********************************************************************
994 Gets valid referrals for a dfs path and fills up the
995 junction_map structure.
996 **********************************************************************/
998 NTSTATUS
get_referred_path(TALLOC_CTX
*ctx
,
999 const char *dfs_path
,
1000 const struct tsocket_address
*remote_address
,
1001 const struct tsocket_address
*local_address
,
1002 bool allow_broken_path
,
1003 struct junction_map
*jucn
,
1005 bool *self_referralp
)
1007 TALLOC_CTX
*frame
= talloc_stackframe();
1008 struct conn_struct_tos
*c
= NULL
;
1009 struct connection_struct
*conn
= NULL
;
1010 char *targetpath
= NULL
;
1012 NTSTATUS status
= NT_STATUS_NOT_FOUND
;
1014 struct dfs_path
*pdp
= talloc_zero(frame
, struct dfs_path
);
1018 return NT_STATUS_NO_MEMORY
;
1021 *self_referralp
= False
;
1023 status
= parse_dfs_path(NULL
, dfs_path
, False
, allow_broken_path
,
1025 if (!NT_STATUS_IS_OK(status
)) {
1030 jucn
->service_name
= talloc_strdup(ctx
, pdp
->servicename
);
1031 jucn
->volume_name
= talloc_strdup(ctx
, pdp
->reqpath
);
1032 if (!jucn
->service_name
|| !jucn
->volume_name
) {
1034 return NT_STATUS_NO_MEMORY
;
1037 /* Verify the share is a dfs root */
1038 snum
= lp_servicenumber(jucn
->service_name
);
1040 char *service_name
= NULL
;
1041 if ((snum
= find_service(ctx
, jucn
->service_name
, &service_name
)) < 0) {
1043 return NT_STATUS_NOT_FOUND
;
1045 if (!service_name
) {
1047 return NT_STATUS_NO_MEMORY
;
1049 TALLOC_FREE(jucn
->service_name
);
1050 jucn
->service_name
= talloc_strdup(ctx
, service_name
);
1051 if (!jucn
->service_name
) {
1053 return NT_STATUS_NO_MEMORY
;
1057 if (!lp_msdfs_root(snum
) && (*lp_msdfs_proxy(talloc_tos(), snum
) == '\0')) {
1058 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
1060 pdp
->servicename
, dfs_path
));
1062 return NT_STATUS_NOT_FOUND
;
1066 * Self referrals are tested with a anonymous IPC connection and
1067 * a GET_DFS_REFERRAL call to \\server\share. (which means
1068 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
1069 * into the directory and will fail if it cannot (as the anonymous
1070 * user). Cope with this.
1073 if (pdp
->reqpath
[0] == '\0') {
1075 struct referral
*ref
;
1078 if (*lp_msdfs_proxy(talloc_tos(), snum
) == '\0') {
1080 return self_ref(ctx
,
1088 * It's an msdfs proxy share. Redirect to
1089 * the configured target share.
1092 tmp
= talloc_asprintf(frame
, "msdfs:%s",
1093 lp_msdfs_proxy(frame
, snum
));
1096 return NT_STATUS_NO_MEMORY
;
1099 if (!parse_msdfs_symlink(ctx
, snum
, tmp
, &ref
, &refcount
)) {
1101 return NT_STATUS_INVALID_PARAMETER
;
1103 jucn
->referral_count
= refcount
;
1104 jucn
->referral_list
= ref
;
1105 *consumedcntp
= strlen(dfs_path
);
1107 return NT_STATUS_OK
;
1110 status
= create_conn_struct_tos_cwd(global_messaging_context(),
1112 lp_path(frame
, snum
),
1115 if (!NT_STATUS_IS_OK(status
)) {
1124 * The remote and local address should be passed down to
1125 * create_conn_struct_cwd.
1127 if (conn
->sconn
->remote_address
== NULL
) {
1128 conn
->sconn
->remote_address
=
1129 tsocket_address_copy(remote_address
, conn
->sconn
);
1130 if (conn
->sconn
->remote_address
== NULL
) {
1132 return NT_STATUS_NO_MEMORY
;
1135 if (conn
->sconn
->local_address
== NULL
) {
1136 conn
->sconn
->local_address
=
1137 tsocket_address_copy(local_address
, conn
->sconn
);
1138 if (conn
->sconn
->local_address
== NULL
) {
1140 return NT_STATUS_NO_MEMORY
;
1144 /* If this is a DFS path dfs_lookup should return
1145 * NT_STATUS_PATH_NOT_COVERED. */
1147 status
= dfs_path_lookup(ctx
, conn
, dfs_path
, pdp
,
1148 0, consumedcntp
, &targetpath
);
1150 if (!NT_STATUS_EQUAL(status
, NT_STATUS_PATH_NOT_COVERED
)) {
1151 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
1153 if (NT_STATUS_IS_OK(status
)) {
1155 * We are in an error path here (we
1156 * know it's not a DFS path), but
1157 * dfs_path_lookup() can return
1158 * NT_STATUS_OK. Ensure we always
1159 * return a valid error code.
1161 * #9588 - ACLs are not inherited to directories
1164 status
= NT_STATUS_NOT_FOUND
;
1169 /* We know this is a valid dfs link. Parse the targetpath. */
1170 if (!parse_msdfs_symlink(ctx
, snum
, targetpath
,
1171 &jucn
->referral_list
,
1172 &jucn
->referral_count
)) {
1173 DEBUG(3,("get_referred_path: failed to parse symlink "
1174 "target %s\n", targetpath
));
1175 status
= NT_STATUS_NOT_FOUND
;
1179 status
= NT_STATUS_OK
;
1185 /******************************************************************
1186 Set up the DFS referral for the dfs pathname. This call returns
1187 the amount of the path covered by this server, and where the
1188 client should be redirected to. This is the meat of the
1189 TRANS2_GET_DFS_REFERRAL call.
1190 ******************************************************************/
1192 int setup_dfs_referral(connection_struct
*orig_conn
,
1193 const char *dfs_path
,
1194 int max_referral_level
,
1195 char **ppdata
, NTSTATUS
*pstatus
)
1197 char *pdata
= *ppdata
;
1199 struct dfs_GetDFSReferral
*r
;
1200 DATA_BLOB blob
= data_blob_null
;
1202 enum ndr_err_code ndr_err
;
1204 r
= talloc_zero(talloc_tos(), struct dfs_GetDFSReferral
);
1206 *pstatus
= NT_STATUS_NO_MEMORY
;
1210 r
->in
.req
.max_referral_level
= max_referral_level
;
1211 r
->in
.req
.servername
= talloc_strdup(r
, dfs_path
);
1212 if (r
->in
.req
.servername
== NULL
) {
1214 *pstatus
= NT_STATUS_NO_MEMORY
;
1218 status
= SMB_VFS_GET_DFS_REFERRALS(orig_conn
, r
);
1219 if (!NT_STATUS_IS_OK(status
)) {
1225 ndr_err
= ndr_push_struct_blob(&blob
, r
,
1227 (ndr_push_flags_fn_t
)ndr_push_dfs_referral_resp
);
1228 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1230 *pstatus
= NT_STATUS_INVALID_PARAMETER
;
1234 pdata
= (char *)SMB_REALLOC(pdata
, blob
.length
);
1237 DEBUG(0,("referral setup:"
1238 "malloc failed for Realloc!\n"));
1242 reply_size
= blob
.length
;
1243 memcpy(pdata
, blob
.data
, blob
.length
);
1246 *pstatus
= NT_STATUS_OK
;
1250 /**********************************************************************
1251 The following functions are called by the NETDFS RPC pipe functions
1252 **********************************************************************/
1254 /*********************************************************************
1255 Creates a junction structure from a DFS pathname
1256 **********************************************************************/
1258 bool create_junction(TALLOC_CTX
*ctx
,
1259 const char *dfs_path
,
1260 bool allow_broken_path
,
1261 struct junction_map
*jucn
)
1265 struct dfs_path
*pdp
= talloc(ctx
,struct dfs_path
);
1271 status
= parse_dfs_path(NULL
, dfs_path
, False
, allow_broken_path
,
1273 if (!NT_STATUS_IS_OK(status
)) {
1277 /* check if path is dfs : validate first token */
1278 if (!is_myname_or_ipaddr(pdp
->hostname
)) {
1279 DEBUG(4,("create_junction: Invalid hostname %s "
1281 pdp
->hostname
, dfs_path
));
1286 /* Check for a non-DFS share */
1287 snum
= lp_servicenumber(pdp
->servicename
);
1289 if(snum
< 0 || !lp_msdfs_root(snum
)) {
1290 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1296 jucn
->service_name
= talloc_strdup(ctx
, pdp
->servicename
);
1297 jucn
->volume_name
= talloc_strdup(ctx
, pdp
->reqpath
);
1298 jucn
->comment
= lp_comment(ctx
, snum
);
1301 if (!jucn
->service_name
|| !jucn
->volume_name
|| ! jucn
->comment
) {
1307 /**********************************************************************
1308 Forms a valid Unix pathname from the junction
1309 **********************************************************************/
1311 static bool junction_to_local_path_tos(const struct junction_map
*jucn
,
1313 connection_struct
**conn_out
)
1315 struct conn_struct_tos
*c
= NULL
;
1317 char *path_out
= NULL
;
1320 snum
= lp_servicenumber(jucn
->service_name
);
1324 status
= create_conn_struct_tos_cwd(global_messaging_context(),
1326 lp_path(talloc_tos(), snum
),
1329 if (!NT_STATUS_IS_OK(status
)) {
1333 path_out
= talloc_asprintf(c
,
1335 lp_path(talloc_tos(), snum
),
1337 if (path_out
== NULL
) {
1341 *pp_path_out
= path_out
;
1342 *conn_out
= c
->conn
;
1346 bool create_msdfs_link(const struct junction_map
*jucn
)
1348 TALLOC_CTX
*frame
= talloc_stackframe();
1350 char *msdfs_link
= NULL
;
1351 connection_struct
*conn
;
1353 bool insert_comma
= False
;
1355 struct smb_filename
*smb_fname
= NULL
;
1358 ok
= junction_to_local_path_tos(jucn
, &path
, &conn
);
1364 /* Form the msdfs_link contents */
1365 msdfs_link
= talloc_strdup(conn
, "msdfs:");
1369 for(i
=0; i
<jucn
->referral_count
; i
++) {
1370 char *refpath
= jucn
->referral_list
[i
].alternate_path
;
1372 /* Alternate paths always use Windows separators. */
1373 trim_char(refpath
, '\\', '\\');
1374 if(*refpath
== '\0') {
1376 insert_comma
= False
;
1380 if (i
> 0 && insert_comma
) {
1381 msdfs_link
= talloc_asprintf_append_buffer(msdfs_link
,
1385 msdfs_link
= talloc_asprintf_append_buffer(msdfs_link
,
1393 if (!insert_comma
) {
1394 insert_comma
= True
;
1398 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1401 smb_fname
= synthetic_smb_fname(frame
,
1406 if (smb_fname
== NULL
) {
1411 if(SMB_VFS_SYMLINK(conn
, msdfs_link
, smb_fname
) < 0) {
1412 if (errno
== EEXIST
) {
1413 if(SMB_VFS_UNLINK(conn
, smb_fname
)!=0) {
1414 TALLOC_FREE(smb_fname
);
1418 if (SMB_VFS_SYMLINK(conn
, msdfs_link
, smb_fname
) < 0) {
1419 DEBUG(1,("create_msdfs_link: symlink failed "
1420 "%s -> %s\nError: %s\n",
1421 path
, msdfs_link
, strerror(errno
)));
1433 bool remove_msdfs_link(const struct junction_map
*jucn
)
1435 TALLOC_CTX
*frame
= talloc_stackframe();
1437 connection_struct
*conn
;
1439 struct smb_filename
*smb_fname
;
1442 ok
= junction_to_local_path_tos(jucn
, &path
, &conn
);
1448 smb_fname
= synthetic_smb_fname(frame
,
1453 if (smb_fname
== NULL
) {
1459 if( SMB_VFS_UNLINK(conn
, smb_fname
) == 0 ) {
1467 /*********************************************************************
1468 Return the number of DFS links at the root of this share.
1469 *********************************************************************/
1471 static int count_dfs_links(TALLOC_CTX
*ctx
, int snum
)
1473 TALLOC_CTX
*frame
= talloc_stackframe();
1476 const char *dname
= NULL
;
1477 char *talloced
= NULL
;
1478 const char *connect_path
= lp_path(frame
, snum
);
1479 const char *msdfs_proxy
= lp_msdfs_proxy(frame
, snum
);
1480 struct conn_struct_tos
*c
= NULL
;
1481 connection_struct
*conn
= NULL
;
1483 struct smb_filename
*smb_fname
= NULL
;
1485 if(*connect_path
== '\0') {
1491 * Fake up a connection struct for the VFS layer.
1494 status
= create_conn_struct_tos_cwd(global_messaging_context(),
1499 if (!NT_STATUS_IS_OK(status
)) {
1500 DEBUG(3, ("create_conn_struct failed: %s\n",
1501 nt_errstr(status
)));
1507 /* Count a link for the msdfs root - convention */
1510 /* No more links if this is an msdfs proxy. */
1511 if (*msdfs_proxy
!= '\0') {
1515 smb_fname
= synthetic_smb_fname(frame
,
1520 if (smb_fname
== NULL
) {
1524 /* Now enumerate all dfs links */
1525 dirp
= SMB_VFS_OPENDIR(conn
, smb_fname
, NULL
, 0);
1530 while ((dname
= vfs_readdirname(conn
, dirp
, NULL
, &talloced
))
1532 struct smb_filename
*smb_dname
=
1533 synthetic_smb_fname(frame
,
1538 if (smb_dname
== NULL
) {
1541 if (is_msdfs_link(conn
, smb_dname
)) {
1544 TALLOC_FREE(talloced
);
1545 TALLOC_FREE(smb_dname
);
1548 SMB_VFS_CLOSEDIR(conn
,dirp
);
1555 /*********************************************************************
1556 *********************************************************************/
1558 static int form_junctions(TALLOC_CTX
*ctx
,
1560 struct junction_map
*jucn
,
1563 TALLOC_CTX
*frame
= talloc_stackframe();
1566 const char *dname
= NULL
;
1567 char *talloced
= NULL
;
1568 const char *connect_path
= lp_path(frame
, snum
);
1569 char *service_name
= lp_servicename(frame
, snum
);
1570 const char *msdfs_proxy
= lp_msdfs_proxy(frame
, snum
);
1571 struct conn_struct_tos
*c
= NULL
;
1572 connection_struct
*conn
= NULL
;
1573 struct referral
*ref
= NULL
;
1574 struct smb_filename
*smb_fname
= NULL
;
1577 if (jn_remain
== 0) {
1582 if(*connect_path
== '\0') {
1588 * Fake up a connection struct for the VFS layer.
1591 status
= create_conn_struct_tos_cwd(global_messaging_context(),
1596 if (!NT_STATUS_IS_OK(status
)) {
1597 DEBUG(3, ("create_conn_struct failed: %s\n",
1598 nt_errstr(status
)));
1604 /* form a junction for the msdfs root - convention
1605 DO NOT REMOVE THIS: NT clients will not work with us
1606 if this is not present
1608 jucn
[cnt
].service_name
= talloc_strdup(ctx
,service_name
);
1609 jucn
[cnt
].volume_name
= talloc_strdup(ctx
, "");
1610 if (!jucn
[cnt
].service_name
|| !jucn
[cnt
].volume_name
) {
1613 jucn
[cnt
].comment
= "";
1614 jucn
[cnt
].referral_count
= 1;
1616 ref
= jucn
[cnt
].referral_list
= talloc_zero(ctx
, struct referral
);
1617 if (jucn
[cnt
].referral_list
== NULL
) {
1622 ref
->ttl
= REFERRAL_TTL
;
1623 if (*msdfs_proxy
!= '\0') {
1624 ref
->alternate_path
= talloc_strdup(ctx
,
1627 ref
->alternate_path
= talloc_asprintf(ctx
,
1629 get_local_machine_name(),
1633 if (!ref
->alternate_path
) {
1638 /* Don't enumerate if we're an msdfs proxy. */
1639 if (*msdfs_proxy
!= '\0') {
1643 smb_fname
= synthetic_smb_fname(frame
,
1648 if (smb_fname
== NULL
) {
1652 /* Now enumerate all dfs links */
1653 dirp
= SMB_VFS_OPENDIR(conn
, smb_fname
, NULL
, 0);
1658 while ((dname
= vfs_readdirname(conn
, dirp
, NULL
, &talloced
))
1660 char *link_target
= NULL
;
1661 struct smb_filename
*smb_dname
= NULL
;
1663 if (cnt
>= jn_remain
) {
1664 DEBUG(2, ("form_junctions: ran out of MSDFS "
1666 TALLOC_FREE(talloced
);
1669 smb_dname
= synthetic_smb_fname(talloc_tos(),
1674 if (smb_dname
== NULL
) {
1675 TALLOC_FREE(talloced
);
1678 if (is_msdfs_link_internal(ctx
,
1680 smb_dname
, &link_target
)) {
1681 if (parse_msdfs_symlink(ctx
, snum
,
1683 &jucn
[cnt
].referral_list
,
1684 &jucn
[cnt
].referral_count
)) {
1686 jucn
[cnt
].service_name
= talloc_strdup(ctx
,
1688 jucn
[cnt
].volume_name
= talloc_strdup(ctx
,
1690 if (!jucn
[cnt
].service_name
||
1691 !jucn
[cnt
].volume_name
) {
1692 TALLOC_FREE(talloced
);
1695 jucn
[cnt
].comment
= "";
1698 TALLOC_FREE(link_target
);
1700 TALLOC_FREE(talloced
);
1701 TALLOC_FREE(smb_dname
);
1707 SMB_VFS_CLOSEDIR(conn
,dirp
);
1714 struct junction_map
*enum_msdfs_links(TALLOC_CTX
*ctx
, size_t *p_num_jn
)
1716 struct junction_map
*jn
= NULL
;
1718 size_t jn_count
= 0;
1722 if(!lp_host_msdfs()) {
1726 /* Ensure all the usershares are loaded. */
1728 load_registry_shares();
1729 sharecount
= load_usershare_shares(NULL
, connections_snum_used
);
1732 for(i
=0;i
< sharecount
;i
++) {
1733 if(lp_msdfs_root(i
)) {
1734 jn_count
+= count_dfs_links(ctx
, i
);
1737 if (jn_count
== 0) {
1740 jn
= talloc_array(ctx
, struct junction_map
, jn_count
);
1744 for(i
=0; i
< sharecount
; i
++) {
1745 if (*p_num_jn
>= jn_count
) {
1748 if(lp_msdfs_root(i
)) {
1749 *p_num_jn
+= form_junctions(ctx
, i
,
1751 jn_count
- *p_num_jn
);
1757 /******************************************************************************
1758 Core function to resolve a dfs pathname possibly containing a wildcard. If
1759 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1760 detected during dfs resolution.
1761 ******************************************************************************/
1763 NTSTATUS
resolve_dfspath_wcard(TALLOC_CTX
*ctx
,
1764 connection_struct
*conn
,
1765 const char *name_in
,
1767 bool allow_broken_path
,
1769 bool *ppath_contains_wcard
)
1771 bool path_contains_wcard
= false;
1772 NTSTATUS status
= NT_STATUS_OK
;
1774 status
= dfs_redirect(ctx
,
1780 &path_contains_wcard
);
1782 if (NT_STATUS_IS_OK(status
) &&
1783 ppath_contains_wcard
!= NULL
&&
1784 path_contains_wcard
) {
1785 *ppath_contains_wcard
= path_contains_wcard
;