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_READLINKAT(conn
,
664 if (referral_len
== -1) {
665 DEBUG(0,("is_msdfs_link_read_target: Error reading "
666 "msdfs link %s: %s\n",
667 smb_fname
->base_name
, strerror(errno
)));
670 link_target
[referral_len
] = '\0';
672 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n", smb_fname
->base_name
,
675 if (!strnequal(link_target
, "msdfs:", 6)) {
682 if (link_target
!= link_target_buf
) {
683 TALLOC_FREE(link_target
);
688 /**********************************************************************
689 Returns true if the unix path is a valid msdfs symlink.
690 **********************************************************************/
692 bool is_msdfs_link(connection_struct
*conn
,
693 struct smb_filename
*smb_fname
)
695 return is_msdfs_link_internal(talloc_tos(),
701 /*****************************************************************
702 Used by other functions to decide if a dfs path is remote,
703 and to get the list of referred locations for that remote path.
705 search_flag: For findfirsts, dfs links themselves are not
706 redirected, but paths beyond the links are. For normal smb calls,
707 even dfs links need to be redirected.
709 consumedcntp: how much of the dfs path is being redirected. the client
710 should try the remaining path on the redirected server.
712 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
713 link redirect are in targetpath.
714 *****************************************************************/
716 static NTSTATUS
dfs_path_lookup(TALLOC_CTX
*ctx
,
717 connection_struct
*conn
,
718 const char *dfspath
, /* Incoming complete dfs path */
719 const struct dfs_path
*pdp
, /* Parsed out
720 server+share+extrapath. */
723 char **pp_targetpath
)
728 struct smb_filename
*smb_fname
= NULL
;
729 char *canon_dfspath
= NULL
; /* Canonicalized dfs path. (only '/'
732 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
733 conn
->connectpath
, pdp
->reqpath
));
736 * Note the unix path conversion here we're doing we
737 * throw away. We're looking for a symlink for a dfs
738 * resolution, if we don't find it we'll do another
739 * unix_convert later in the codepath.
742 status
= unix_convert(ctx
, conn
, pdp
->reqpath
, &smb_fname
,
745 if (!NT_STATUS_IS_OK(status
)) {
746 if (!NT_STATUS_EQUAL(status
,
747 NT_STATUS_OBJECT_PATH_NOT_FOUND
)) {
750 if (smb_fname
== NULL
|| smb_fname
->base_name
== NULL
) {
755 /* Optimization - check if we can redirect the whole path. */
757 if (is_msdfs_link_internal(ctx
, conn
, smb_fname
, pp_targetpath
)) {
758 /* XX_ALLOW_WCARD_XXX is called from search functions. */
760 (UCF_COND_ALLOW_WCARD_LCOMP
|
761 UCF_ALWAYS_ALLOW_WCARD_LCOMP
)) {
762 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
763 "for dfs link %s.\n", dfspath
));
764 status
= NT_STATUS_OK
;
768 DEBUG(6,("dfs_path_lookup: %s resolves to a "
769 "valid dfs link %s.\n", dfspath
,
770 pp_targetpath
? *pp_targetpath
: ""));
773 *consumedcntp
= strlen(dfspath
);
775 status
= NT_STATUS_PATH_NOT_COVERED
;
779 /* Prepare to test only for '/' components in the given path,
780 * so if a Windows path replace all '\\' characters with '/'.
781 * For a POSIX DFS path we know all separators are already '/'. */
783 canon_dfspath
= talloc_strdup(ctx
, dfspath
);
784 if (!canon_dfspath
) {
785 status
= NT_STATUS_NO_MEMORY
;
788 if (!pdp
->posix_path
) {
789 string_replace(canon_dfspath
, '\\', '/');
793 * localpath comes out of unix_convert, so it has
794 * no trailing backslash. Make sure that canon_dfspath hasn't either.
795 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
798 trim_char(canon_dfspath
,0,'/');
801 * Redirect if any component in the path is a link.
802 * We do this by walking backwards through the
803 * local path, chopping off the last component
804 * in both the local path and the canonicalized
805 * DFS path. If we hit a DFS link then we're done.
808 p
= strrchr_m(smb_fname
->base_name
, '/');
810 q
= strrchr_m(canon_dfspath
, '/');
819 if (is_msdfs_link_internal(ctx
, conn
,
820 smb_fname
, pp_targetpath
)) {
821 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
822 "parent %s is dfs link\n", dfspath
,
823 smb_fname_str_dbg(smb_fname
)));
826 *consumedcntp
= strlen(canon_dfspath
);
827 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
833 status
= NT_STATUS_PATH_NOT_COVERED
;
837 /* Step back on the filesystem. */
838 p
= strrchr_m(smb_fname
->base_name
, '/');
841 /* And in the canonicalized dfs path. */
842 q
= strrchr_m(canon_dfspath
, '/');
846 status
= NT_STATUS_OK
;
848 TALLOC_FREE(smb_fname
);
852 /*****************************************************************
853 Decides if a dfs pathname should be redirected or not.
854 If not, the pathname is converted to a tcon-relative local unix path
856 search_wcard_flag: this flag performs 2 functions both related
857 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
860 This function can return NT_STATUS_OK, meaning use the returned path as-is
861 (mapped into a local path).
862 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
863 any other NT_STATUS error which is a genuine error to be
864 returned to the client.
865 *****************************************************************/
867 static NTSTATUS
dfs_redirect(TALLOC_CTX
*ctx
,
868 connection_struct
*conn
,
871 bool allow_broken_path
,
873 bool *ppath_contains_wcard
)
876 bool search_wcard_flag
= (ucf_flags
&
877 (UCF_COND_ALLOW_WCARD_LCOMP
|UCF_ALWAYS_ALLOW_WCARD_LCOMP
));
878 struct dfs_path
*pdp
= talloc(ctx
, struct dfs_path
);
881 return NT_STATUS_NO_MEMORY
;
884 status
= parse_dfs_path(conn
, path_in
, search_wcard_flag
,
885 allow_broken_path
, pdp
,
886 ppath_contains_wcard
);
887 if (!NT_STATUS_IS_OK(status
)) {
892 if (pdp
->reqpath
[0] == '\0') {
894 *pp_path_out
= talloc_strdup(ctx
, "");
896 return NT_STATUS_NO_MEMORY
;
898 DEBUG(5,("dfs_redirect: self-referral.\n"));
902 /* If dfs pathname for a non-dfs share, convert to tcon-relative
903 path and return OK */
905 if (!lp_msdfs_root(SNUM(conn
))) {
906 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
909 return NT_STATUS_NO_MEMORY
;
914 /* If it looked like a local path (zero hostname/servicename)
915 * just treat as a tcon-relative path. */
917 if (pdp
->hostname
[0] == '\0' && pdp
->servicename
[0] == '\0') {
918 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
921 return NT_STATUS_NO_MEMORY
;
926 if (!( strequal(pdp
->servicename
, lp_servicename(talloc_tos(), SNUM(conn
)))
927 || (strequal(pdp
->servicename
, HOMES_NAME
)
928 && strequal(lp_servicename(talloc_tos(), SNUM(conn
)),
929 conn
->session_info
->unix_info
->sanitized_username
) )) ) {
931 /* The given sharename doesn't match this connection. */
934 return NT_STATUS_OBJECT_PATH_NOT_FOUND
;
937 status
= dfs_path_lookup(ctx
, conn
, path_in
, pdp
,
938 ucf_flags
, NULL
, NULL
);
939 if (!NT_STATUS_IS_OK(status
)) {
940 if (NT_STATUS_EQUAL(status
, NT_STATUS_PATH_NOT_COVERED
)) {
941 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in
));
943 DEBUG(10,("dfs_redirect: dfs_path_lookup "
944 "failed for %s with %s\n",
945 path_in
, nt_errstr(status
) ));
950 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in
));
952 /* Form non-dfs tcon-relative path */
953 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
956 return NT_STATUS_NO_MEMORY
;
959 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
966 /**********************************************************************
967 Return a self referral.
968 **********************************************************************/
970 static NTSTATUS
self_ref(TALLOC_CTX
*ctx
,
971 const char *dfs_path
,
972 struct junction_map
*jucn
,
974 bool *self_referralp
)
976 struct referral
*ref
;
978 *self_referralp
= True
;
980 jucn
->referral_count
= 1;
981 if((ref
= talloc_zero(ctx
, struct referral
)) == NULL
) {
982 return NT_STATUS_NO_MEMORY
;
985 ref
->alternate_path
= talloc_strdup(ctx
, dfs_path
);
986 if (!ref
->alternate_path
) {
988 return NT_STATUS_NO_MEMORY
;
991 ref
->ttl
= REFERRAL_TTL
;
992 jucn
->referral_list
= ref
;
993 *consumedcntp
= strlen(dfs_path
);
997 /**********************************************************************
998 Gets valid referrals for a dfs path and fills up the
999 junction_map structure.
1000 **********************************************************************/
1002 NTSTATUS
get_referred_path(TALLOC_CTX
*ctx
,
1003 const char *dfs_path
,
1004 const struct tsocket_address
*remote_address
,
1005 const struct tsocket_address
*local_address
,
1006 bool allow_broken_path
,
1007 struct junction_map
*jucn
,
1009 bool *self_referralp
)
1011 TALLOC_CTX
*frame
= talloc_stackframe();
1012 struct conn_struct_tos
*c
= NULL
;
1013 struct connection_struct
*conn
= NULL
;
1014 char *targetpath
= NULL
;
1016 NTSTATUS status
= NT_STATUS_NOT_FOUND
;
1018 struct dfs_path
*pdp
= talloc_zero(frame
, struct dfs_path
);
1022 return NT_STATUS_NO_MEMORY
;
1025 *self_referralp
= False
;
1027 status
= parse_dfs_path(NULL
, dfs_path
, False
, allow_broken_path
,
1029 if (!NT_STATUS_IS_OK(status
)) {
1034 jucn
->service_name
= talloc_strdup(ctx
, pdp
->servicename
);
1035 jucn
->volume_name
= talloc_strdup(ctx
, pdp
->reqpath
);
1036 if (!jucn
->service_name
|| !jucn
->volume_name
) {
1038 return NT_STATUS_NO_MEMORY
;
1041 /* Verify the share is a dfs root */
1042 snum
= lp_servicenumber(jucn
->service_name
);
1044 char *service_name
= NULL
;
1045 if ((snum
= find_service(ctx
, jucn
->service_name
, &service_name
)) < 0) {
1047 return NT_STATUS_NOT_FOUND
;
1049 if (!service_name
) {
1051 return NT_STATUS_NO_MEMORY
;
1053 TALLOC_FREE(jucn
->service_name
);
1054 jucn
->service_name
= talloc_strdup(ctx
, service_name
);
1055 if (!jucn
->service_name
) {
1057 return NT_STATUS_NO_MEMORY
;
1061 if (!lp_msdfs_root(snum
) && (*lp_msdfs_proxy(talloc_tos(), snum
) == '\0')) {
1062 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
1064 pdp
->servicename
, dfs_path
));
1066 return NT_STATUS_NOT_FOUND
;
1070 * Self referrals are tested with a anonymous IPC connection and
1071 * a GET_DFS_REFERRAL call to \\server\share. (which means
1072 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
1073 * into the directory and will fail if it cannot (as the anonymous
1074 * user). Cope with this.
1077 if (pdp
->reqpath
[0] == '\0') {
1079 struct referral
*ref
;
1082 if (*lp_msdfs_proxy(talloc_tos(), snum
) == '\0') {
1084 return self_ref(ctx
,
1092 * It's an msdfs proxy share. Redirect to
1093 * the configured target share.
1096 tmp
= talloc_asprintf(frame
, "msdfs:%s",
1097 lp_msdfs_proxy(frame
, snum
));
1100 return NT_STATUS_NO_MEMORY
;
1103 if (!parse_msdfs_symlink(ctx
, snum
, tmp
, &ref
, &refcount
)) {
1105 return NT_STATUS_INVALID_PARAMETER
;
1107 jucn
->referral_count
= refcount
;
1108 jucn
->referral_list
= ref
;
1109 *consumedcntp
= strlen(dfs_path
);
1111 return NT_STATUS_OK
;
1114 status
= create_conn_struct_tos_cwd(global_messaging_context(),
1116 lp_path(frame
, snum
),
1119 if (!NT_STATUS_IS_OK(status
)) {
1128 * The remote and local address should be passed down to
1129 * create_conn_struct_cwd.
1131 if (conn
->sconn
->remote_address
== NULL
) {
1132 conn
->sconn
->remote_address
=
1133 tsocket_address_copy(remote_address
, conn
->sconn
);
1134 if (conn
->sconn
->remote_address
== NULL
) {
1136 return NT_STATUS_NO_MEMORY
;
1139 if (conn
->sconn
->local_address
== NULL
) {
1140 conn
->sconn
->local_address
=
1141 tsocket_address_copy(local_address
, conn
->sconn
);
1142 if (conn
->sconn
->local_address
== NULL
) {
1144 return NT_STATUS_NO_MEMORY
;
1148 /* If this is a DFS path dfs_lookup should return
1149 * NT_STATUS_PATH_NOT_COVERED. */
1151 status
= dfs_path_lookup(ctx
, conn
, dfs_path
, pdp
,
1152 0, consumedcntp
, &targetpath
);
1154 if (!NT_STATUS_EQUAL(status
, NT_STATUS_PATH_NOT_COVERED
)) {
1155 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
1157 if (NT_STATUS_IS_OK(status
)) {
1159 * We are in an error path here (we
1160 * know it's not a DFS path), but
1161 * dfs_path_lookup() can return
1162 * NT_STATUS_OK. Ensure we always
1163 * return a valid error code.
1165 * #9588 - ACLs are not inherited to directories
1168 status
= NT_STATUS_NOT_FOUND
;
1173 /* We know this is a valid dfs link. Parse the targetpath. */
1174 if (!parse_msdfs_symlink(ctx
, snum
, targetpath
,
1175 &jucn
->referral_list
,
1176 &jucn
->referral_count
)) {
1177 DEBUG(3,("get_referred_path: failed to parse symlink "
1178 "target %s\n", targetpath
));
1179 status
= NT_STATUS_NOT_FOUND
;
1183 status
= NT_STATUS_OK
;
1189 /******************************************************************
1190 Set up the DFS referral for the dfs pathname. This call returns
1191 the amount of the path covered by this server, and where the
1192 client should be redirected to. This is the meat of the
1193 TRANS2_GET_DFS_REFERRAL call.
1194 ******************************************************************/
1196 int setup_dfs_referral(connection_struct
*orig_conn
,
1197 const char *dfs_path
,
1198 int max_referral_level
,
1199 char **ppdata
, NTSTATUS
*pstatus
)
1201 char *pdata
= *ppdata
;
1203 struct dfs_GetDFSReferral
*r
;
1204 DATA_BLOB blob
= data_blob_null
;
1206 enum ndr_err_code ndr_err
;
1208 r
= talloc_zero(talloc_tos(), struct dfs_GetDFSReferral
);
1210 *pstatus
= NT_STATUS_NO_MEMORY
;
1214 r
->in
.req
.max_referral_level
= max_referral_level
;
1215 r
->in
.req
.servername
= talloc_strdup(r
, dfs_path
);
1216 if (r
->in
.req
.servername
== NULL
) {
1218 *pstatus
= NT_STATUS_NO_MEMORY
;
1222 status
= SMB_VFS_GET_DFS_REFERRALS(orig_conn
, r
);
1223 if (!NT_STATUS_IS_OK(status
)) {
1229 ndr_err
= ndr_push_struct_blob(&blob
, r
,
1231 (ndr_push_flags_fn_t
)ndr_push_dfs_referral_resp
);
1232 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1234 *pstatus
= NT_STATUS_INVALID_PARAMETER
;
1238 pdata
= (char *)SMB_REALLOC(pdata
, blob
.length
);
1241 DEBUG(0,("referral setup:"
1242 "malloc failed for Realloc!\n"));
1246 reply_size
= blob
.length
;
1247 memcpy(pdata
, blob
.data
, blob
.length
);
1250 *pstatus
= NT_STATUS_OK
;
1254 /**********************************************************************
1255 The following functions are called by the NETDFS RPC pipe functions
1256 **********************************************************************/
1258 /*********************************************************************
1259 Creates a junction structure from a DFS pathname
1260 **********************************************************************/
1262 bool create_junction(TALLOC_CTX
*ctx
,
1263 const char *dfs_path
,
1264 bool allow_broken_path
,
1265 struct junction_map
*jucn
)
1267 const struct loadparm_substitution
*lp_sub
=
1268 loadparm_s3_global_substitution();
1271 struct dfs_path
*pdp
= talloc(ctx
,struct dfs_path
);
1277 status
= parse_dfs_path(NULL
, dfs_path
, False
, allow_broken_path
,
1279 if (!NT_STATUS_IS_OK(status
)) {
1283 /* check if path is dfs : validate first token */
1284 if (!is_myname_or_ipaddr(pdp
->hostname
)) {
1285 DEBUG(4,("create_junction: Invalid hostname %s "
1287 pdp
->hostname
, dfs_path
));
1292 /* Check for a non-DFS share */
1293 snum
= lp_servicenumber(pdp
->servicename
);
1295 if(snum
< 0 || !lp_msdfs_root(snum
)) {
1296 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1302 jucn
->service_name
= talloc_strdup(ctx
, pdp
->servicename
);
1303 jucn
->volume_name
= talloc_strdup(ctx
, pdp
->reqpath
);
1304 jucn
->comment
= lp_comment(ctx
, lp_sub
, snum
);
1307 if (!jucn
->service_name
|| !jucn
->volume_name
|| ! jucn
->comment
) {
1313 /**********************************************************************
1314 Forms a valid Unix pathname from the junction
1315 **********************************************************************/
1317 static bool junction_to_local_path_tos(const struct junction_map
*jucn
,
1319 connection_struct
**conn_out
)
1321 struct conn_struct_tos
*c
= NULL
;
1323 char *path_out
= NULL
;
1326 snum
= lp_servicenumber(jucn
->service_name
);
1330 status
= create_conn_struct_tos_cwd(global_messaging_context(),
1332 lp_path(talloc_tos(), snum
),
1335 if (!NT_STATUS_IS_OK(status
)) {
1339 path_out
= talloc_asprintf(c
,
1341 lp_path(talloc_tos(), snum
),
1343 if (path_out
== NULL
) {
1347 *pp_path_out
= path_out
;
1348 *conn_out
= c
->conn
;
1352 bool create_msdfs_link(const struct junction_map
*jucn
)
1354 TALLOC_CTX
*frame
= talloc_stackframe();
1356 char *msdfs_link
= NULL
;
1357 connection_struct
*conn
;
1359 bool insert_comma
= False
;
1361 struct smb_filename
*smb_fname
= NULL
;
1365 ok
= junction_to_local_path_tos(jucn
, &path
, &conn
);
1371 /* Form the msdfs_link contents */
1372 msdfs_link
= talloc_strdup(conn
, "msdfs:");
1376 for(i
=0; i
<jucn
->referral_count
; i
++) {
1377 char *refpath
= jucn
->referral_list
[i
].alternate_path
;
1379 /* Alternate paths always use Windows separators. */
1380 trim_char(refpath
, '\\', '\\');
1381 if(*refpath
== '\0') {
1383 insert_comma
= False
;
1387 if (i
> 0 && insert_comma
) {
1388 msdfs_link
= talloc_asprintf_append_buffer(msdfs_link
,
1392 msdfs_link
= talloc_asprintf_append_buffer(msdfs_link
,
1400 if (!insert_comma
) {
1401 insert_comma
= True
;
1405 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1408 smb_fname
= synthetic_smb_fname(frame
,
1413 if (smb_fname
== NULL
) {
1418 retval
= SMB_VFS_SYMLINKAT(conn
,
1423 if (errno
== EEXIST
) {
1424 retval
= SMB_VFS_UNLINKAT(conn
,
1429 TALLOC_FREE(smb_fname
);
1433 retval
= SMB_VFS_SYMLINKAT(conn
,
1438 DEBUG(1,("create_msdfs_link: symlinkat failed "
1439 "%s -> %s\nError: %s\n",
1440 path
, msdfs_link
, strerror(errno
)));
1452 bool remove_msdfs_link(const struct junction_map
*jucn
)
1454 TALLOC_CTX
*frame
= talloc_stackframe();
1456 connection_struct
*conn
;
1458 struct smb_filename
*smb_fname
;
1462 ok
= junction_to_local_path_tos(jucn
, &path
, &conn
);
1468 smb_fname
= synthetic_smb_fname(frame
,
1473 if (smb_fname
== NULL
) {
1479 retval
= SMB_VFS_UNLINKAT(conn
,
1491 /*********************************************************************
1492 Return the number of DFS links at the root of this share.
1493 *********************************************************************/
1495 static int count_dfs_links(TALLOC_CTX
*ctx
, int snum
)
1497 TALLOC_CTX
*frame
= talloc_stackframe();
1500 const char *dname
= NULL
;
1501 char *talloced
= NULL
;
1502 const char *connect_path
= lp_path(frame
, snum
);
1503 const char *msdfs_proxy
= lp_msdfs_proxy(frame
, snum
);
1504 struct conn_struct_tos
*c
= NULL
;
1505 connection_struct
*conn
= NULL
;
1507 struct smb_filename
*smb_fname
= NULL
;
1509 if(*connect_path
== '\0') {
1515 * Fake up a connection struct for the VFS layer.
1518 status
= create_conn_struct_tos_cwd(global_messaging_context(),
1523 if (!NT_STATUS_IS_OK(status
)) {
1524 DEBUG(3, ("create_conn_struct failed: %s\n",
1525 nt_errstr(status
)));
1531 /* Count a link for the msdfs root - convention */
1534 /* No more links if this is an msdfs proxy. */
1535 if (*msdfs_proxy
!= '\0') {
1539 smb_fname
= synthetic_smb_fname(frame
,
1544 if (smb_fname
== NULL
) {
1548 /* Now enumerate all dfs links */
1549 dirp
= SMB_VFS_OPENDIR(conn
, smb_fname
, NULL
, 0);
1554 while ((dname
= vfs_readdirname(conn
, dirp
, NULL
, &talloced
))
1556 struct smb_filename
*smb_dname
=
1557 synthetic_smb_fname(frame
,
1562 if (smb_dname
== NULL
) {
1565 if (is_msdfs_link(conn
, smb_dname
)) {
1568 TALLOC_FREE(talloced
);
1569 TALLOC_FREE(smb_dname
);
1572 SMB_VFS_CLOSEDIR(conn
,dirp
);
1579 /*********************************************************************
1580 *********************************************************************/
1582 static int form_junctions(TALLOC_CTX
*ctx
,
1584 struct junction_map
*jucn
,
1587 TALLOC_CTX
*frame
= talloc_stackframe();
1590 const char *dname
= NULL
;
1591 char *talloced
= NULL
;
1592 const char *connect_path
= lp_path(frame
, snum
);
1593 char *service_name
= lp_servicename(frame
, snum
);
1594 const char *msdfs_proxy
= lp_msdfs_proxy(frame
, snum
);
1595 struct conn_struct_tos
*c
= NULL
;
1596 connection_struct
*conn
= NULL
;
1597 struct referral
*ref
= NULL
;
1598 struct smb_filename
*smb_fname
= NULL
;
1601 if (jn_remain
== 0) {
1606 if(*connect_path
== '\0') {
1612 * Fake up a connection struct for the VFS layer.
1615 status
= create_conn_struct_tos_cwd(global_messaging_context(),
1620 if (!NT_STATUS_IS_OK(status
)) {
1621 DEBUG(3, ("create_conn_struct failed: %s\n",
1622 nt_errstr(status
)));
1628 /* form a junction for the msdfs root - convention
1629 DO NOT REMOVE THIS: NT clients will not work with us
1630 if this is not present
1632 jucn
[cnt
].service_name
= talloc_strdup(ctx
,service_name
);
1633 jucn
[cnt
].volume_name
= talloc_strdup(ctx
, "");
1634 if (!jucn
[cnt
].service_name
|| !jucn
[cnt
].volume_name
) {
1637 jucn
[cnt
].comment
= "";
1638 jucn
[cnt
].referral_count
= 1;
1640 ref
= jucn
[cnt
].referral_list
= talloc_zero(ctx
, struct referral
);
1641 if (jucn
[cnt
].referral_list
== NULL
) {
1646 ref
->ttl
= REFERRAL_TTL
;
1647 if (*msdfs_proxy
!= '\0') {
1648 ref
->alternate_path
= talloc_strdup(ctx
,
1651 ref
->alternate_path
= talloc_asprintf(ctx
,
1653 get_local_machine_name(),
1657 if (!ref
->alternate_path
) {
1662 /* Don't enumerate if we're an msdfs proxy. */
1663 if (*msdfs_proxy
!= '\0') {
1667 smb_fname
= synthetic_smb_fname(frame
,
1672 if (smb_fname
== NULL
) {
1676 /* Now enumerate all dfs links */
1677 dirp
= SMB_VFS_OPENDIR(conn
, smb_fname
, NULL
, 0);
1682 while ((dname
= vfs_readdirname(conn
, dirp
, NULL
, &talloced
))
1684 char *link_target
= NULL
;
1685 struct smb_filename
*smb_dname
= NULL
;
1687 if (cnt
>= jn_remain
) {
1688 DEBUG(2, ("form_junctions: ran out of MSDFS "
1690 TALLOC_FREE(talloced
);
1693 smb_dname
= synthetic_smb_fname(talloc_tos(),
1698 if (smb_dname
== NULL
) {
1699 TALLOC_FREE(talloced
);
1702 if (is_msdfs_link_internal(ctx
,
1704 smb_dname
, &link_target
)) {
1705 if (parse_msdfs_symlink(ctx
, snum
,
1707 &jucn
[cnt
].referral_list
,
1708 &jucn
[cnt
].referral_count
)) {
1710 jucn
[cnt
].service_name
= talloc_strdup(ctx
,
1712 jucn
[cnt
].volume_name
= talloc_strdup(ctx
,
1714 if (!jucn
[cnt
].service_name
||
1715 !jucn
[cnt
].volume_name
) {
1716 TALLOC_FREE(talloced
);
1719 jucn
[cnt
].comment
= "";
1722 TALLOC_FREE(link_target
);
1724 TALLOC_FREE(talloced
);
1725 TALLOC_FREE(smb_dname
);
1731 SMB_VFS_CLOSEDIR(conn
,dirp
);
1738 struct junction_map
*enum_msdfs_links(TALLOC_CTX
*ctx
, size_t *p_num_jn
)
1740 struct junction_map
*jn
= NULL
;
1742 size_t jn_count
= 0;
1746 if(!lp_host_msdfs()) {
1750 /* Ensure all the usershares are loaded. */
1752 load_registry_shares();
1753 sharecount
= load_usershare_shares(NULL
, connections_snum_used
);
1756 for(i
=0;i
< sharecount
;i
++) {
1757 if(lp_msdfs_root(i
)) {
1758 jn_count
+= count_dfs_links(ctx
, i
);
1761 if (jn_count
== 0) {
1764 jn
= talloc_array(ctx
, struct junction_map
, jn_count
);
1768 for(i
=0; i
< sharecount
; i
++) {
1769 if (*p_num_jn
>= jn_count
) {
1772 if(lp_msdfs_root(i
)) {
1773 *p_num_jn
+= form_junctions(ctx
, i
,
1775 jn_count
- *p_num_jn
);
1781 /******************************************************************************
1782 Core function to resolve a dfs pathname possibly containing a wildcard. If
1783 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1784 detected during dfs resolution.
1785 ******************************************************************************/
1787 NTSTATUS
resolve_dfspath_wcard(TALLOC_CTX
*ctx
,
1788 connection_struct
*conn
,
1789 const char *name_in
,
1791 bool allow_broken_path
,
1793 bool *ppath_contains_wcard
)
1795 bool path_contains_wcard
= false;
1796 NTSTATUS status
= NT_STATUS_OK
;
1798 status
= dfs_redirect(ctx
,
1804 &path_contains_wcard
);
1806 if (NT_STATUS_IS_OK(status
) &&
1807 ppath_contains_wcard
!= NULL
&&
1808 path_contains_wcard
) {
1809 *ppath_contains_wcard
= path_contains_wcard
;