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 "lib/param/loadparm.h"
32 #include "libcli/security/security.h"
33 #include "librpc/gen_ndr/ndr_dfsblobs.h"
34 #include "lib/tsocket/tsocket.h"
36 /**********************************************************************
37 Parse a DFS pathname of the form \hostname\service\reqpath
38 into the dfs_path structure.
39 If POSIX pathnames is true, the pathname may also be of the
40 form /hostname/service/reqpath.
41 We cope with either here.
43 Unfortunately, due to broken clients who might set the
44 SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
45 send a local path, we have to cope with that too....
47 If conn != NULL then ensure the provided service is
48 the one pointed to by the connection.
50 This version does everything using pointers within one copy of the
51 pathname string, talloced on the struct dfs_path pointer (which
52 must be talloced). This may be too clever to live....
54 **********************************************************************/
56 static NTSTATUS
parse_dfs_path(connection_struct
*conn
,
59 bool allow_broken_path
,
60 struct dfs_path
*pdp
, /* MUST BE TALLOCED */
61 bool *ppath_contains_wcard
)
67 NTSTATUS status
= NT_STATUS_OK
;
73 * This is the only talloc we should need to do
74 * on the struct dfs_path. All the pointers inside
75 * it should point to offsets within this string.
78 pathname_local
= talloc_strdup(pdp
, pathname
);
79 if (!pathname_local
) {
80 return NT_STATUS_NO_MEMORY
;
82 /* Get a pointer to the terminating '\0' */
83 eos_ptr
= &pathname_local
[strlen(pathname_local
)];
84 p
= temp
= pathname_local
;
87 * Non-broken DFS paths *must* start with the
88 * path separator. For Windows this is always '\\',
89 * for posix paths this is always '/'.
92 if (*pathname
== '/') {
93 pdp
->posix_path
= true;
96 pdp
->posix_path
= false;
100 if (allow_broken_path
&& (*pathname
!= sepchar
)) {
101 DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
102 pathname
, sepchar
));
104 * Possibly client sent a local path by mistake.
105 * Try and convert to a local path.
106 * Note that this is an SMB1-only fallback
107 * to cope with known broken SMB1 clients.
110 pdp
->hostname
= eos_ptr
; /* "" */
111 pdp
->servicename
= eos_ptr
; /* "" */
113 /* We've got no info about separators. */
114 pdp
->posix_path
= lp_posix_pathnames();
116 DEBUG(10,("parse_dfs_path: trying to convert %s to a "
123 * Safe to use on talloc'ed string as it only shrinks.
124 * It also doesn't affect the eos_ptr.
126 trim_char(temp
,sepchar
,sepchar
);
128 DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
132 /* Parse out hostname. */
133 p
= strchr_m(temp
,sepchar
);
135 DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
138 * Possibly client sent a local path by mistake.
139 * Try and convert to a local path.
142 pdp
->hostname
= eos_ptr
; /* "" */
143 pdp
->servicename
= eos_ptr
; /* "" */
146 DEBUG(10,("parse_dfs_path: trying to convert %s "
152 pdp
->hostname
= temp
;
154 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp
->hostname
));
156 /* Parse out servicename. */
158 p
= strchr_m(servicename
,sepchar
);
163 /* Is this really our servicename ? */
164 if (conn
&& !( strequal(servicename
, lp_servicename(talloc_tos(), SNUM(conn
)))
165 || (strequal(servicename
, HOMES_NAME
)
166 && strequal(lp_servicename(talloc_tos(), SNUM(conn
)),
167 get_current_username()) )) ) {
168 DEBUG(10,("parse_dfs_path: %s is not our servicename\n",
172 * Possibly client sent a local path by mistake.
173 * Try and convert to a local path.
176 pdp
->hostname
= eos_ptr
; /* "" */
177 pdp
->servicename
= eos_ptr
; /* "" */
179 /* Repair the path - replace the sepchar's
182 *servicename
= sepchar
;
188 DEBUG(10,("parse_dfs_path: trying to convert %s "
194 pdp
->servicename
= servicename
;
196 DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp
->servicename
));
199 /* Client sent self referral \server\share. */
200 pdp
->reqpath
= eos_ptr
; /* "" */
208 *ppath_contains_wcard
= False
;
212 /* Rest is reqpath. */
213 if (pdp
->posix_path
) {
214 status
= check_path_syntax_posix(pdp
->reqpath
);
217 status
= check_path_syntax_wcard(pdp
->reqpath
,
218 ppath_contains_wcard
);
220 status
= check_path_syntax(pdp
->reqpath
);
224 if (!NT_STATUS_IS_OK(status
)) {
225 DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
226 p
, nt_errstr(status
) ));
230 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp
->reqpath
));
234 /********************************************************
235 Fake up a connection struct for the VFS layer, for use in
236 applications (such as the python bindings), that do not want the
237 global working directory changed under them.
239 SMB_VFS_CONNECT requires root privileges.
240 *********************************************************/
242 static NTSTATUS
create_conn_struct_as_root(TALLOC_CTX
*ctx
,
243 struct messaging_context
*msg
,
244 connection_struct
**pconn
,
247 const struct auth_session_info
*session_info
)
249 connection_struct
*conn
;
251 const char *vfs_user
;
252 struct smbd_server_connection
*sconn
;
253 const char *servicename
= lp_const_servicename(snum
);
255 sconn
= talloc_zero(ctx
, struct smbd_server_connection
);
257 return NT_STATUS_NO_MEMORY
;
260 sconn
->raw_ev_ctx
= samba_tevent_context_init(sconn
);
261 if (sconn
->raw_ev_ctx
== NULL
) {
263 return NT_STATUS_NO_MEMORY
;
266 sconn
->root_ev_ctx
= sconn
->raw_ev_ctx
;
267 sconn
->guest_ev_ctx
= sconn
->raw_ev_ctx
;
268 sconn
->msg_ctx
= msg
;
270 conn
= conn_new(sconn
);
273 return NT_STATUS_NO_MEMORY
;
276 /* Now we have conn, we need to make sconn a child of conn,
277 * for a proper talloc tree */
278 talloc_steal(conn
, sconn
);
280 if (snum
== -1 && servicename
== NULL
) {
281 servicename
= "Unknown Service (snum == -1)";
284 connpath
= talloc_strdup(conn
, path
);
287 return NT_STATUS_NO_MEMORY
;
289 connpath
= talloc_string_sub(conn
,
295 return NT_STATUS_NO_MEMORY
;
298 /* needed for smbd_vfs_init() */
300 conn
->params
->service
= snum
;
301 conn
->cnum
= TID_FIELD_INVALID
;
303 if (session_info
!= NULL
) {
304 conn
->session_info
= copy_session_info(conn
, session_info
);
305 if (conn
->session_info
== NULL
) {
306 DEBUG(0, ("copy_serverinfo failed\n"));
308 return NT_STATUS_NO_MEMORY
;
310 vfs_user
= conn
->session_info
->unix_info
->unix_name
;
312 /* use current authenticated user in absence of session_info */
313 vfs_user
= get_current_username();
316 conn
->user_ev_ctx
= sconn
->raw_ev_ctx
;
318 set_conn_connectpath(conn
, connpath
);
321 * New code to check if there's a share security descriptor
322 * added from NT server manager. This is done after the
323 * smb.conf checks are done as we need a uid and token. JRA.
326 if (conn
->session_info
) {
327 share_access_check(conn
->session_info
->security_token
,
329 MAXIMUM_ALLOWED_ACCESS
,
330 &conn
->share_access
);
332 if ((conn
->share_access
& FILE_WRITE_DATA
) == 0) {
333 if ((conn
->share_access
& FILE_READ_DATA
) == 0) {
334 /* No access, read or write. */
335 DEBUG(3,("create_conn_struct: connection to %s "
336 "denied due to security "
340 return NT_STATUS_ACCESS_DENIED
;
342 conn
->read_only
= true;
346 conn
->share_access
= 0;
347 conn
->read_only
= true;
350 if (!smbd_vfs_init(conn
)) {
351 NTSTATUS status
= map_nt_error_from_unix(errno
);
352 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
357 /* this must be the first filesystem operation that we do */
358 if (SMB_VFS_CONNECT(conn
, servicename
, vfs_user
) < 0) {
359 DEBUG(0,("VFS connect failed!\n"));
361 return NT_STATUS_UNSUCCESSFUL
;
364 talloc_free(conn
->origpath
);
365 conn
->origpath
= talloc_strdup(conn
, conn
->connectpath
);
366 if (conn
->origpath
== NULL
) {
368 return NT_STATUS_NO_MEMORY
;
371 conn
->fs_capabilities
= SMB_VFS_FS_CAPABILITIES(conn
, &conn
->ts_res
);
372 conn
->tcon_done
= true;
373 *pconn
= talloc_move(ctx
, &conn
);
378 static int conn_struct_tos_destructor(struct conn_struct_tos
*c
)
380 if (c
->oldcwd_fname
!= NULL
) {
381 vfs_ChDir(c
->conn
, c
->oldcwd_fname
);
382 TALLOC_FREE(c
->oldcwd_fname
);
384 SMB_VFS_DISCONNECT(c
->conn
);
389 /********************************************************
390 Fake up a connection struct for the VFS layer, for use in
391 applications (such as the python bindings), that do not want the
392 global working directory changed under them.
394 SMB_VFS_CONNECT requires root privileges.
395 This temporary uses become_root() and unbecome_root().
397 But further impersonation has to be cone by the caller.
398 *********************************************************/
399 NTSTATUS
create_conn_struct_tos(struct messaging_context
*msg
,
402 const struct auth_session_info
*session_info
,
403 struct conn_struct_tos
**_c
)
405 struct conn_struct_tos
*c
= NULL
;
410 c
= talloc_zero(talloc_tos(), struct conn_struct_tos
);
412 return NT_STATUS_NO_MEMORY
;
416 status
= create_conn_struct_as_root(c
,
423 if (!NT_STATUS_IS_OK(status
)) {
428 talloc_set_destructor(c
, conn_struct_tos_destructor
);
434 /********************************************************
435 Fake up a connection struct for the VFS layer.
436 Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
438 See also the comment for create_conn_struct_tos() above!
440 The CWD change is reverted by the destructor of
441 conn_struct_tos when the current talloc_tos() is destroyed.
442 *********************************************************/
443 NTSTATUS
create_conn_struct_tos_cwd(struct messaging_context
*msg
,
446 const struct auth_session_info
*session_info
,
447 struct conn_struct_tos
**_c
)
449 struct conn_struct_tos
*c
= NULL
;
450 struct smb_filename smb_fname_connectpath
= {0};
455 status
= create_conn_struct_tos(msg
,
460 if (!NT_STATUS_IS_OK(status
)) {
465 * Windows seems to insist on doing trans2getdfsreferral() calls on
466 * the IPC$ share as the anonymous user. If we try to chdir as that
467 * user we will fail.... WTF ? JRA.
470 c
->oldcwd_fname
= vfs_GetWd(c
, c
->conn
);
471 if (c
->oldcwd_fname
== NULL
) {
472 status
= map_nt_error_from_unix(errno
);
473 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno
)));
478 smb_fname_connectpath
= (struct smb_filename
) {
479 .base_name
= c
->conn
->connectpath
482 if (vfs_ChDir(c
->conn
, &smb_fname_connectpath
) != 0) {
483 status
= map_nt_error_from_unix(errno
);
484 DBG_NOTICE("Can't ChDir to new conn path %s. "
486 c
->conn
->connectpath
, strerror(errno
));
487 TALLOC_FREE(c
->oldcwd_fname
);
496 static void shuffle_strlist(char **list
, int count
)
502 for (i
= count
; i
> 1; i
--) {
503 r
= generate_random() % i
;
511 /**********************************************************************
512 Parse the contents of a symlink to verify if it is an msdfs referral
513 A valid referral is of the form:
515 msdfs:server1\share1,server2\share2
516 msdfs:server1\share1\pathname,server2\share2\pathname
517 msdfs:server1/share1,server2/share2
518 msdfs:server1/share1/pathname,server2/share2/pathname.
520 Note that the alternate paths returned here must be of the canonicalized
524 \server\share\path\to\file,
526 even in posix path mode. This is because we have no knowledge if the
527 server we're referring to understands posix paths.
528 **********************************************************************/
530 static bool parse_msdfs_symlink(TALLOC_CTX
*ctx
,
533 struct referral
**preflist
,
538 char **alt_path
= NULL
;
540 struct referral
*reflist
;
543 temp
= talloc_strdup(ctx
, target
);
547 prot
= strtok_r(temp
, ":", &saveptr
);
549 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
553 alt_path
= talloc_array(ctx
, char *, MAX_REFERRAL_COUNT
);
558 /* parse out the alternate paths */
559 while((count
<MAX_REFERRAL_COUNT
) &&
560 ((alt_path
[count
] = strtok_r(NULL
, ",", &saveptr
)) != NULL
)) {
564 /* shuffle alternate paths */
565 if (lp_msdfs_shuffle_referrals(snum
)) {
566 shuffle_strlist(alt_path
, count
);
569 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count
));
572 reflist
= *preflist
= talloc_zero_array(ctx
,
573 struct referral
, count
);
574 if(reflist
== NULL
) {
575 TALLOC_FREE(alt_path
);
579 reflist
= *preflist
= NULL
;
582 for(i
=0;i
<count
;i
++) {
585 /* Canonicalize link target.
586 * Replace all /'s in the path by a \ */
587 string_replace(alt_path
[i
], '/', '\\');
589 /* Remove leading '\\'s */
591 while (*p
&& (*p
== '\\')) {
595 reflist
[i
].alternate_path
= talloc_asprintf(ctx
,
598 if (!reflist
[i
].alternate_path
) {
602 reflist
[i
].proximity
= 0;
603 reflist
[i
].ttl
= REFERRAL_TTL
;
604 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
605 reflist
[i
].alternate_path
));
610 TALLOC_FREE(alt_path
);
614 /**********************************************************************
615 Returns true if the unix path is a valid msdfs symlink and also
616 returns the target string from inside the link.
617 **********************************************************************/
619 static bool is_msdfs_link_internal(TALLOC_CTX
*ctx
,
620 connection_struct
*conn
,
621 struct smb_filename
*smb_fname
,
622 char **pp_link_target
)
624 int referral_len
= 0;
625 #if defined(HAVE_BROKEN_READLINK)
626 char link_target_buf
[PATH_MAX
];
628 char link_target_buf
[7];
631 char *link_target
= NULL
;
633 if (pp_link_target
) {
635 link_target
= talloc_array(ctx
, char, bufsize
);
639 *pp_link_target
= link_target
;
641 bufsize
= sizeof(link_target_buf
);
642 link_target
= link_target_buf
;
645 if (SMB_VFS_LSTAT(conn
, smb_fname
) != 0) {
646 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
647 smb_fname
->base_name
));
650 if (!S_ISLNK(smb_fname
->st
.st_ex_mode
)) {
651 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
652 smb_fname
->base_name
));
656 referral_len
= SMB_VFS_READLINK(conn
, smb_fname
,
657 link_target
, bufsize
- 1);
658 if (referral_len
== -1) {
659 DEBUG(0,("is_msdfs_link_read_target: Error reading "
660 "msdfs link %s: %s\n",
661 smb_fname
->base_name
, strerror(errno
)));
664 link_target
[referral_len
] = '\0';
666 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n", smb_fname
->base_name
,
669 if (!strnequal(link_target
, "msdfs:", 6)) {
676 if (link_target
!= link_target_buf
) {
677 TALLOC_FREE(link_target
);
682 /**********************************************************************
683 Returns true if the unix path is a valid msdfs symlink.
684 **********************************************************************/
686 bool is_msdfs_link(connection_struct
*conn
,
687 struct smb_filename
*smb_fname
)
689 return is_msdfs_link_internal(talloc_tos(),
695 /*****************************************************************
696 Used by other functions to decide if a dfs path is remote,
697 and to get the list of referred locations for that remote path.
699 search_flag: For findfirsts, dfs links themselves are not
700 redirected, but paths beyond the links are. For normal smb calls,
701 even dfs links need to be redirected.
703 consumedcntp: how much of the dfs path is being redirected. the client
704 should try the remaining path on the redirected server.
706 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
707 link redirect are in targetpath.
708 *****************************************************************/
710 static NTSTATUS
dfs_path_lookup(TALLOC_CTX
*ctx
,
711 connection_struct
*conn
,
712 const char *dfspath
, /* Incoming complete dfs path */
713 const struct dfs_path
*pdp
, /* Parsed out
714 server+share+extrapath. */
717 char **pp_targetpath
)
722 struct smb_filename
*smb_fname
= NULL
;
723 char *canon_dfspath
= NULL
; /* Canonicalized dfs path. (only '/'
726 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
727 conn
->connectpath
, pdp
->reqpath
));
730 * Note the unix path conversion here we're doing we
731 * throw away. We're looking for a symlink for a dfs
732 * resolution, if we don't find it we'll do another
733 * unix_convert later in the codepath.
736 status
= unix_convert(ctx
, conn
, pdp
->reqpath
, &smb_fname
,
739 if (!NT_STATUS_IS_OK(status
)) {
740 if (!NT_STATUS_EQUAL(status
,
741 NT_STATUS_OBJECT_PATH_NOT_FOUND
)) {
744 if (smb_fname
== NULL
|| smb_fname
->base_name
== NULL
) {
749 /* Optimization - check if we can redirect the whole path. */
751 if (is_msdfs_link_internal(ctx
, conn
, smb_fname
, pp_targetpath
)) {
752 /* XX_ALLOW_WCARD_XXX is called from search functions. */
754 (UCF_COND_ALLOW_WCARD_LCOMP
|
755 UCF_ALWAYS_ALLOW_WCARD_LCOMP
)) {
756 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
757 "for dfs link %s.\n", dfspath
));
758 status
= NT_STATUS_OK
;
762 DEBUG(6,("dfs_path_lookup: %s resolves to a "
763 "valid dfs link %s.\n", dfspath
,
764 pp_targetpath
? *pp_targetpath
: ""));
767 *consumedcntp
= strlen(dfspath
);
769 status
= NT_STATUS_PATH_NOT_COVERED
;
773 /* Prepare to test only for '/' components in the given path,
774 * so if a Windows path replace all '\\' characters with '/'.
775 * For a POSIX DFS path we know all separators are already '/'. */
777 canon_dfspath
= talloc_strdup(ctx
, dfspath
);
778 if (!canon_dfspath
) {
779 status
= NT_STATUS_NO_MEMORY
;
782 if (!pdp
->posix_path
) {
783 string_replace(canon_dfspath
, '\\', '/');
787 * localpath comes out of unix_convert, so it has
788 * no trailing backslash. Make sure that canon_dfspath hasn't either.
789 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
792 trim_char(canon_dfspath
,0,'/');
795 * Redirect if any component in the path is a link.
796 * We do this by walking backwards through the
797 * local path, chopping off the last component
798 * in both the local path and the canonicalized
799 * DFS path. If we hit a DFS link then we're done.
802 p
= strrchr_m(smb_fname
->base_name
, '/');
804 q
= strrchr_m(canon_dfspath
, '/');
813 if (is_msdfs_link_internal(ctx
, conn
,
814 smb_fname
, pp_targetpath
)) {
815 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
816 "parent %s is dfs link\n", dfspath
,
817 smb_fname_str_dbg(smb_fname
)));
820 *consumedcntp
= strlen(canon_dfspath
);
821 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
827 status
= NT_STATUS_PATH_NOT_COVERED
;
831 /* Step back on the filesystem. */
832 p
= strrchr_m(smb_fname
->base_name
, '/');
835 /* And in the canonicalized dfs path. */
836 q
= strrchr_m(canon_dfspath
, '/');
840 status
= NT_STATUS_OK
;
842 TALLOC_FREE(smb_fname
);
846 /*****************************************************************
847 Decides if a dfs pathname should be redirected or not.
848 If not, the pathname is converted to a tcon-relative local unix path
850 search_wcard_flag: this flag performs 2 functions both related
851 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
854 This function can return NT_STATUS_OK, meaning use the returned path as-is
855 (mapped into a local path).
856 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
857 any other NT_STATUS error which is a genuine error to be
858 returned to the client.
859 *****************************************************************/
861 static NTSTATUS
dfs_redirect(TALLOC_CTX
*ctx
,
862 connection_struct
*conn
,
865 bool allow_broken_path
,
867 bool *ppath_contains_wcard
)
870 bool search_wcard_flag
= (ucf_flags
&
871 (UCF_COND_ALLOW_WCARD_LCOMP
|UCF_ALWAYS_ALLOW_WCARD_LCOMP
));
872 struct dfs_path
*pdp
= talloc(ctx
, struct dfs_path
);
875 return NT_STATUS_NO_MEMORY
;
878 status
= parse_dfs_path(conn
, path_in
, search_wcard_flag
,
879 allow_broken_path
, pdp
,
880 ppath_contains_wcard
);
881 if (!NT_STATUS_IS_OK(status
)) {
886 if (pdp
->reqpath
[0] == '\0') {
888 *pp_path_out
= talloc_strdup(ctx
, "");
890 return NT_STATUS_NO_MEMORY
;
892 DEBUG(5,("dfs_redirect: self-referral.\n"));
896 /* If dfs pathname for a non-dfs share, convert to tcon-relative
897 path and return OK */
899 if (!lp_msdfs_root(SNUM(conn
))) {
900 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
903 return NT_STATUS_NO_MEMORY
;
908 /* If it looked like a local path (zero hostname/servicename)
909 * just treat as a tcon-relative path. */
911 if (pdp
->hostname
[0] == '\0' && pdp
->servicename
[0] == '\0') {
912 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
915 return NT_STATUS_NO_MEMORY
;
920 if (!( strequal(pdp
->servicename
, lp_servicename(talloc_tos(), SNUM(conn
)))
921 || (strequal(pdp
->servicename
, HOMES_NAME
)
922 && strequal(lp_servicename(talloc_tos(), SNUM(conn
)),
923 conn
->session_info
->unix_info
->sanitized_username
) )) ) {
925 /* The given sharename doesn't match this connection. */
928 return NT_STATUS_OBJECT_PATH_NOT_FOUND
;
931 status
= dfs_path_lookup(ctx
, conn
, path_in
, pdp
,
932 ucf_flags
, NULL
, NULL
);
933 if (!NT_STATUS_IS_OK(status
)) {
934 if (NT_STATUS_EQUAL(status
, NT_STATUS_PATH_NOT_COVERED
)) {
935 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in
));
937 DEBUG(10,("dfs_redirect: dfs_path_lookup "
938 "failed for %s with %s\n",
939 path_in
, nt_errstr(status
) ));
944 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in
));
946 /* Form non-dfs tcon-relative path */
947 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
950 return NT_STATUS_NO_MEMORY
;
953 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
960 /**********************************************************************
961 Return a self referral.
962 **********************************************************************/
964 static NTSTATUS
self_ref(TALLOC_CTX
*ctx
,
965 const char *dfs_path
,
966 struct junction_map
*jucn
,
968 bool *self_referralp
)
970 struct referral
*ref
;
972 *self_referralp
= True
;
974 jucn
->referral_count
= 1;
975 if((ref
= talloc_zero(ctx
, struct referral
)) == NULL
) {
976 return NT_STATUS_NO_MEMORY
;
979 ref
->alternate_path
= talloc_strdup(ctx
, dfs_path
);
980 if (!ref
->alternate_path
) {
982 return NT_STATUS_NO_MEMORY
;
985 ref
->ttl
= REFERRAL_TTL
;
986 jucn
->referral_list
= ref
;
987 *consumedcntp
= strlen(dfs_path
);
991 /**********************************************************************
992 Gets valid referrals for a dfs path and fills up the
993 junction_map structure.
994 **********************************************************************/
996 NTSTATUS
get_referred_path(TALLOC_CTX
*ctx
,
997 const char *dfs_path
,
998 const struct tsocket_address
*remote_address
,
999 const struct tsocket_address
*local_address
,
1000 bool allow_broken_path
,
1001 struct junction_map
*jucn
,
1003 bool *self_referralp
)
1005 TALLOC_CTX
*frame
= talloc_stackframe();
1006 struct conn_struct_tos
*c
= NULL
;
1007 struct connection_struct
*conn
= NULL
;
1008 char *targetpath
= NULL
;
1010 NTSTATUS status
= NT_STATUS_NOT_FOUND
;
1012 struct dfs_path
*pdp
= talloc_zero(frame
, struct dfs_path
);
1016 return NT_STATUS_NO_MEMORY
;
1019 *self_referralp
= False
;
1021 status
= parse_dfs_path(NULL
, dfs_path
, False
, allow_broken_path
,
1023 if (!NT_STATUS_IS_OK(status
)) {
1028 jucn
->service_name
= talloc_strdup(ctx
, pdp
->servicename
);
1029 jucn
->volume_name
= talloc_strdup(ctx
, pdp
->reqpath
);
1030 if (!jucn
->service_name
|| !jucn
->volume_name
) {
1032 return NT_STATUS_NO_MEMORY
;
1035 /* Verify the share is a dfs root */
1036 snum
= lp_servicenumber(jucn
->service_name
);
1038 char *service_name
= NULL
;
1039 if ((snum
= find_service(ctx
, jucn
->service_name
, &service_name
)) < 0) {
1041 return NT_STATUS_NOT_FOUND
;
1043 if (!service_name
) {
1045 return NT_STATUS_NO_MEMORY
;
1047 TALLOC_FREE(jucn
->service_name
);
1048 jucn
->service_name
= talloc_strdup(ctx
, service_name
);
1049 if (!jucn
->service_name
) {
1051 return NT_STATUS_NO_MEMORY
;
1055 if (!lp_msdfs_root(snum
) && (*lp_msdfs_proxy(talloc_tos(), snum
) == '\0')) {
1056 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
1058 pdp
->servicename
, dfs_path
));
1060 return NT_STATUS_NOT_FOUND
;
1064 * Self referrals are tested with a anonymous IPC connection and
1065 * a GET_DFS_REFERRAL call to \\server\share. (which means
1066 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
1067 * into the directory and will fail if it cannot (as the anonymous
1068 * user). Cope with this.
1071 if (pdp
->reqpath
[0] == '\0') {
1073 struct referral
*ref
;
1076 if (*lp_msdfs_proxy(talloc_tos(), snum
) == '\0') {
1078 return self_ref(ctx
,
1086 * It's an msdfs proxy share. Redirect to
1087 * the configured target share.
1090 tmp
= talloc_asprintf(frame
, "msdfs:%s",
1091 lp_msdfs_proxy(frame
, snum
));
1094 return NT_STATUS_NO_MEMORY
;
1097 if (!parse_msdfs_symlink(ctx
, snum
, tmp
, &ref
, &refcount
)) {
1099 return NT_STATUS_INVALID_PARAMETER
;
1101 jucn
->referral_count
= refcount
;
1102 jucn
->referral_list
= ref
;
1103 *consumedcntp
= strlen(dfs_path
);
1105 return NT_STATUS_OK
;
1108 status
= create_conn_struct_tos_cwd(server_messaging_context(),
1110 lp_path(frame
, snum
),
1113 if (!NT_STATUS_IS_OK(status
)) {
1122 * The remote and local address should be passed down to
1123 * create_conn_struct_cwd.
1125 if (conn
->sconn
->remote_address
== NULL
) {
1126 conn
->sconn
->remote_address
=
1127 tsocket_address_copy(remote_address
, conn
->sconn
);
1128 if (conn
->sconn
->remote_address
== NULL
) {
1130 return NT_STATUS_NO_MEMORY
;
1133 if (conn
->sconn
->local_address
== NULL
) {
1134 conn
->sconn
->local_address
=
1135 tsocket_address_copy(local_address
, conn
->sconn
);
1136 if (conn
->sconn
->local_address
== NULL
) {
1138 return NT_STATUS_NO_MEMORY
;
1142 /* If this is a DFS path dfs_lookup should return
1143 * NT_STATUS_PATH_NOT_COVERED. */
1145 status
= dfs_path_lookup(ctx
, conn
, dfs_path
, pdp
,
1146 0, consumedcntp
, &targetpath
);
1148 if (!NT_STATUS_EQUAL(status
, NT_STATUS_PATH_NOT_COVERED
)) {
1149 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
1151 if (NT_STATUS_IS_OK(status
)) {
1153 * We are in an error path here (we
1154 * know it's not a DFS path), but
1155 * dfs_path_lookup() can return
1156 * NT_STATUS_OK. Ensure we always
1157 * return a valid error code.
1159 * #9588 - ACLs are not inherited to directories
1162 status
= NT_STATUS_NOT_FOUND
;
1167 /* We know this is a valid dfs link. Parse the targetpath. */
1168 if (!parse_msdfs_symlink(ctx
, snum
, targetpath
,
1169 &jucn
->referral_list
,
1170 &jucn
->referral_count
)) {
1171 DEBUG(3,("get_referred_path: failed to parse symlink "
1172 "target %s\n", targetpath
));
1173 status
= NT_STATUS_NOT_FOUND
;
1177 status
= NT_STATUS_OK
;
1183 /******************************************************************
1184 Set up the DFS referral for the dfs pathname. This call returns
1185 the amount of the path covered by this server, and where the
1186 client should be redirected to. This is the meat of the
1187 TRANS2_GET_DFS_REFERRAL call.
1188 ******************************************************************/
1190 int setup_dfs_referral(connection_struct
*orig_conn
,
1191 const char *dfs_path
,
1192 int max_referral_level
,
1193 char **ppdata
, NTSTATUS
*pstatus
)
1195 char *pdata
= *ppdata
;
1197 struct dfs_GetDFSReferral
*r
;
1198 DATA_BLOB blob
= data_blob_null
;
1200 enum ndr_err_code ndr_err
;
1202 r
= talloc_zero(talloc_tos(), struct dfs_GetDFSReferral
);
1204 *pstatus
= NT_STATUS_NO_MEMORY
;
1208 r
->in
.req
.max_referral_level
= max_referral_level
;
1209 r
->in
.req
.servername
= talloc_strdup(r
, dfs_path
);
1210 if (r
->in
.req
.servername
== NULL
) {
1212 *pstatus
= NT_STATUS_NO_MEMORY
;
1216 status
= SMB_VFS_GET_DFS_REFERRALS(orig_conn
, r
);
1217 if (!NT_STATUS_IS_OK(status
)) {
1223 ndr_err
= ndr_push_struct_blob(&blob
, r
,
1225 (ndr_push_flags_fn_t
)ndr_push_dfs_referral_resp
);
1226 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1228 *pstatus
= NT_STATUS_INVALID_PARAMETER
;
1232 pdata
= (char *)SMB_REALLOC(pdata
, blob
.length
);
1235 DEBUG(0,("referral setup:"
1236 "malloc failed for Realloc!\n"));
1240 reply_size
= blob
.length
;
1241 memcpy(pdata
, blob
.data
, blob
.length
);
1244 *pstatus
= NT_STATUS_OK
;
1248 /**********************************************************************
1249 The following functions are called by the NETDFS RPC pipe functions
1250 **********************************************************************/
1252 /*********************************************************************
1253 Creates a junction structure from a DFS pathname
1254 **********************************************************************/
1256 bool create_junction(TALLOC_CTX
*ctx
,
1257 const char *dfs_path
,
1258 bool allow_broken_path
,
1259 struct junction_map
*jucn
)
1263 struct dfs_path
*pdp
= talloc(ctx
,struct dfs_path
);
1269 status
= parse_dfs_path(NULL
, dfs_path
, False
, allow_broken_path
,
1271 if (!NT_STATUS_IS_OK(status
)) {
1275 /* check if path is dfs : validate first token */
1276 if (!is_myname_or_ipaddr(pdp
->hostname
)) {
1277 DEBUG(4,("create_junction: Invalid hostname %s "
1279 pdp
->hostname
, dfs_path
));
1284 /* Check for a non-DFS share */
1285 snum
= lp_servicenumber(pdp
->servicename
);
1287 if(snum
< 0 || !lp_msdfs_root(snum
)) {
1288 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1294 jucn
->service_name
= talloc_strdup(ctx
, pdp
->servicename
);
1295 jucn
->volume_name
= talloc_strdup(ctx
, pdp
->reqpath
);
1296 jucn
->comment
= lp_comment(ctx
, snum
);
1299 if (!jucn
->service_name
|| !jucn
->volume_name
|| ! jucn
->comment
) {
1305 /**********************************************************************
1306 Forms a valid Unix pathname from the junction
1307 **********************************************************************/
1309 static bool junction_to_local_path_tos(const struct junction_map
*jucn
,
1311 connection_struct
**conn_out
)
1313 struct conn_struct_tos
*c
= NULL
;
1315 char *path_out
= NULL
;
1318 snum
= lp_servicenumber(jucn
->service_name
);
1322 status
= create_conn_struct_tos_cwd(server_messaging_context(),
1324 lp_path(talloc_tos(), snum
),
1327 if (!NT_STATUS_IS_OK(status
)) {
1331 path_out
= talloc_asprintf(c
,
1333 lp_path(talloc_tos(), snum
),
1335 if (path_out
== NULL
) {
1339 *pp_path_out
= path_out
;
1340 *conn_out
= c
->conn
;
1344 bool create_msdfs_link(const struct junction_map
*jucn
)
1346 TALLOC_CTX
*frame
= talloc_stackframe();
1348 char *msdfs_link
= NULL
;
1349 connection_struct
*conn
;
1351 bool insert_comma
= False
;
1353 struct smb_filename
*smb_fname
= NULL
;
1356 ok
= junction_to_local_path_tos(jucn
, &path
, &conn
);
1362 /* Form the msdfs_link contents */
1363 msdfs_link
= talloc_strdup(conn
, "msdfs:");
1367 for(i
=0; i
<jucn
->referral_count
; i
++) {
1368 char *refpath
= jucn
->referral_list
[i
].alternate_path
;
1370 /* Alternate paths always use Windows separators. */
1371 trim_char(refpath
, '\\', '\\');
1372 if(*refpath
== '\0') {
1374 insert_comma
= False
;
1378 if (i
> 0 && insert_comma
) {
1379 msdfs_link
= talloc_asprintf_append_buffer(msdfs_link
,
1383 msdfs_link
= talloc_asprintf_append_buffer(msdfs_link
,
1391 if (!insert_comma
) {
1392 insert_comma
= True
;
1396 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1399 smb_fname
= synthetic_smb_fname(frame
,
1404 if (smb_fname
== NULL
) {
1409 if(SMB_VFS_SYMLINK(conn
, msdfs_link
, smb_fname
) < 0) {
1410 if (errno
== EEXIST
) {
1411 if(SMB_VFS_UNLINK(conn
, smb_fname
)!=0) {
1412 TALLOC_FREE(smb_fname
);
1416 if (SMB_VFS_SYMLINK(conn
, msdfs_link
, smb_fname
) < 0) {
1417 DEBUG(1,("create_msdfs_link: symlink failed "
1418 "%s -> %s\nError: %s\n",
1419 path
, msdfs_link
, strerror(errno
)));
1431 bool remove_msdfs_link(const struct junction_map
*jucn
)
1433 TALLOC_CTX
*frame
= talloc_stackframe();
1435 connection_struct
*conn
;
1437 struct smb_filename
*smb_fname
;
1440 ok
= junction_to_local_path_tos(jucn
, &path
, &conn
);
1446 smb_fname
= synthetic_smb_fname(frame
,
1451 if (smb_fname
== NULL
) {
1457 if( SMB_VFS_UNLINK(conn
, smb_fname
) == 0 ) {
1465 /*********************************************************************
1466 Return the number of DFS links at the root of this share.
1467 *********************************************************************/
1469 static int count_dfs_links(TALLOC_CTX
*ctx
, int snum
)
1471 TALLOC_CTX
*frame
= talloc_stackframe();
1474 const char *dname
= NULL
;
1475 char *talloced
= NULL
;
1476 const char *connect_path
= lp_path(frame
, snum
);
1477 const char *msdfs_proxy
= lp_msdfs_proxy(frame
, snum
);
1478 struct conn_struct_tos
*c
= NULL
;
1479 connection_struct
*conn
= NULL
;
1481 struct smb_filename
*smb_fname
= NULL
;
1483 if(*connect_path
== '\0') {
1489 * Fake up a connection struct for the VFS layer.
1492 status
= create_conn_struct_tos_cwd(server_messaging_context(),
1497 if (!NT_STATUS_IS_OK(status
)) {
1498 DEBUG(3, ("create_conn_struct failed: %s\n",
1499 nt_errstr(status
)));
1505 /* Count a link for the msdfs root - convention */
1508 /* No more links if this is an msdfs proxy. */
1509 if (*msdfs_proxy
!= '\0') {
1513 smb_fname
= synthetic_smb_fname(frame
,
1518 if (smb_fname
== NULL
) {
1522 /* Now enumerate all dfs links */
1523 dirp
= SMB_VFS_OPENDIR(conn
, smb_fname
, NULL
, 0);
1528 while ((dname
= vfs_readdirname(conn
, dirp
, NULL
, &talloced
))
1530 struct smb_filename
*smb_dname
=
1531 synthetic_smb_fname(frame
,
1536 if (smb_dname
== NULL
) {
1539 if (is_msdfs_link(conn
, smb_dname
)) {
1542 TALLOC_FREE(talloced
);
1543 TALLOC_FREE(smb_dname
);
1546 SMB_VFS_CLOSEDIR(conn
,dirp
);
1553 /*********************************************************************
1554 *********************************************************************/
1556 static int form_junctions(TALLOC_CTX
*ctx
,
1558 struct junction_map
*jucn
,
1561 TALLOC_CTX
*frame
= talloc_stackframe();
1564 const char *dname
= NULL
;
1565 char *talloced
= NULL
;
1566 const char *connect_path
= lp_path(frame
, snum
);
1567 char *service_name
= lp_servicename(frame
, snum
);
1568 const char *msdfs_proxy
= lp_msdfs_proxy(frame
, snum
);
1569 struct conn_struct_tos
*c
= NULL
;
1570 connection_struct
*conn
= NULL
;
1571 struct referral
*ref
= NULL
;
1572 struct smb_filename
*smb_fname
= NULL
;
1575 if (jn_remain
== 0) {
1580 if(*connect_path
== '\0') {
1586 * Fake up a connection struct for the VFS layer.
1589 status
= create_conn_struct_tos_cwd(server_messaging_context(),
1594 if (!NT_STATUS_IS_OK(status
)) {
1595 DEBUG(3, ("create_conn_struct failed: %s\n",
1596 nt_errstr(status
)));
1602 /* form a junction for the msdfs root - convention
1603 DO NOT REMOVE THIS: NT clients will not work with us
1604 if this is not present
1606 jucn
[cnt
].service_name
= talloc_strdup(ctx
,service_name
);
1607 jucn
[cnt
].volume_name
= talloc_strdup(ctx
, "");
1608 if (!jucn
[cnt
].service_name
|| !jucn
[cnt
].volume_name
) {
1611 jucn
[cnt
].comment
= "";
1612 jucn
[cnt
].referral_count
= 1;
1614 ref
= jucn
[cnt
].referral_list
= talloc_zero(ctx
, struct referral
);
1615 if (jucn
[cnt
].referral_list
== NULL
) {
1620 ref
->ttl
= REFERRAL_TTL
;
1621 if (*msdfs_proxy
!= '\0') {
1622 ref
->alternate_path
= talloc_strdup(ctx
,
1625 ref
->alternate_path
= talloc_asprintf(ctx
,
1627 get_local_machine_name(),
1631 if (!ref
->alternate_path
) {
1636 /* Don't enumerate if we're an msdfs proxy. */
1637 if (*msdfs_proxy
!= '\0') {
1641 smb_fname
= synthetic_smb_fname(frame
,
1646 if (smb_fname
== NULL
) {
1650 /* Now enumerate all dfs links */
1651 dirp
= SMB_VFS_OPENDIR(conn
, smb_fname
, NULL
, 0);
1656 while ((dname
= vfs_readdirname(conn
, dirp
, NULL
, &talloced
))
1658 char *link_target
= NULL
;
1659 struct smb_filename
*smb_dname
= NULL
;
1661 if (cnt
>= jn_remain
) {
1662 DEBUG(2, ("form_junctions: ran out of MSDFS "
1664 TALLOC_FREE(talloced
);
1667 smb_dname
= synthetic_smb_fname(talloc_tos(),
1672 if (smb_dname
== NULL
) {
1673 TALLOC_FREE(talloced
);
1676 if (is_msdfs_link_internal(ctx
,
1678 smb_dname
, &link_target
)) {
1679 if (parse_msdfs_symlink(ctx
, snum
,
1681 &jucn
[cnt
].referral_list
,
1682 &jucn
[cnt
].referral_count
)) {
1684 jucn
[cnt
].service_name
= talloc_strdup(ctx
,
1686 jucn
[cnt
].volume_name
= talloc_strdup(ctx
,
1688 if (!jucn
[cnt
].service_name
||
1689 !jucn
[cnt
].volume_name
) {
1690 TALLOC_FREE(talloced
);
1693 jucn
[cnt
].comment
= "";
1696 TALLOC_FREE(link_target
);
1698 TALLOC_FREE(talloced
);
1699 TALLOC_FREE(smb_dname
);
1705 SMB_VFS_CLOSEDIR(conn
,dirp
);
1712 struct junction_map
*enum_msdfs_links(TALLOC_CTX
*ctx
, size_t *p_num_jn
)
1714 struct junction_map
*jn
= NULL
;
1716 size_t jn_count
= 0;
1720 if(!lp_host_msdfs()) {
1724 /* Ensure all the usershares are loaded. */
1726 load_registry_shares();
1727 sharecount
= load_usershare_shares(NULL
, connections_snum_used
);
1730 for(i
=0;i
< sharecount
;i
++) {
1731 if(lp_msdfs_root(i
)) {
1732 jn_count
+= count_dfs_links(ctx
, i
);
1735 if (jn_count
== 0) {
1738 jn
= talloc_array(ctx
, struct junction_map
, jn_count
);
1742 for(i
=0; i
< sharecount
; i
++) {
1743 if (*p_num_jn
>= jn_count
) {
1746 if(lp_msdfs_root(i
)) {
1747 *p_num_jn
+= form_junctions(ctx
, i
,
1749 jn_count
- *p_num_jn
);
1755 /******************************************************************************
1756 Core function to resolve a dfs pathname possibly containing a wildcard. If
1757 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1758 detected during dfs resolution.
1759 ******************************************************************************/
1761 NTSTATUS
resolve_dfspath_wcard(TALLOC_CTX
*ctx
,
1762 connection_struct
*conn
,
1763 const char *name_in
,
1765 bool allow_broken_path
,
1767 bool *ppath_contains_wcard
)
1769 bool path_contains_wcard
= false;
1770 NTSTATUS status
= NT_STATUS_OK
;
1772 status
= dfs_redirect(ctx
,
1778 &path_contains_wcard
);
1780 if (NT_STATUS_IS_OK(status
) &&
1781 ppath_contains_wcard
!= NULL
&&
1782 path_contains_wcard
) {
1783 *ppath_contains_wcard
= path_contains_wcard
;