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 /* unix_info could be NULL in session_info */
311 if (conn
->session_info
->unix_info
!= NULL
) {
312 vfs_user
= conn
->session_info
->unix_info
->unix_name
;
314 vfs_user
= get_current_username();
317 /* use current authenticated user in absence of session_info */
318 vfs_user
= get_current_username();
321 conn
->user_ev_ctx
= sconn
->raw_ev_ctx
;
323 set_conn_connectpath(conn
, connpath
);
326 * New code to check if there's a share security descriptor
327 * added from NT server manager. This is done after the
328 * smb.conf checks are done as we need a uid and token. JRA.
331 if (conn
->session_info
) {
332 share_access_check(conn
->session_info
->security_token
,
334 MAXIMUM_ALLOWED_ACCESS
,
335 &conn
->share_access
);
337 if ((conn
->share_access
& FILE_WRITE_DATA
) == 0) {
338 if ((conn
->share_access
& FILE_READ_DATA
) == 0) {
339 /* No access, read or write. */
340 DEBUG(3,("create_conn_struct: connection to %s "
341 "denied due to security "
345 return NT_STATUS_ACCESS_DENIED
;
347 conn
->read_only
= true;
351 conn
->share_access
= 0;
352 conn
->read_only
= true;
355 if (!smbd_vfs_init(conn
)) {
356 NTSTATUS status
= map_nt_error_from_unix(errno
);
357 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
362 /* this must be the first filesystem operation that we do */
363 if (SMB_VFS_CONNECT(conn
, servicename
, vfs_user
) < 0) {
364 DEBUG(0,("VFS connect failed!\n"));
366 return NT_STATUS_UNSUCCESSFUL
;
369 talloc_free(conn
->origpath
);
370 conn
->origpath
= talloc_strdup(conn
, conn
->connectpath
);
371 if (conn
->origpath
== NULL
) {
373 return NT_STATUS_NO_MEMORY
;
376 conn
->fs_capabilities
= SMB_VFS_FS_CAPABILITIES(conn
, &conn
->ts_res
);
377 conn
->tcon_done
= true;
378 *pconn
= talloc_move(ctx
, &conn
);
383 static int conn_struct_tos_destructor(struct conn_struct_tos
*c
)
385 if (c
->oldcwd_fname
!= NULL
) {
386 vfs_ChDir(c
->conn
, c
->oldcwd_fname
);
387 TALLOC_FREE(c
->oldcwd_fname
);
389 SMB_VFS_DISCONNECT(c
->conn
);
394 /********************************************************
395 Fake up a connection struct for the VFS layer, for use in
396 applications (such as the python bindings), that do not want the
397 global working directory changed under them.
399 SMB_VFS_CONNECT requires root privileges.
400 This temporary uses become_root() and unbecome_root().
402 But further impersonation has to be cone by the caller.
403 *********************************************************/
404 NTSTATUS
create_conn_struct_tos(struct messaging_context
*msg
,
407 const struct auth_session_info
*session_info
,
408 struct conn_struct_tos
**_c
)
410 struct conn_struct_tos
*c
= NULL
;
415 c
= talloc_zero(talloc_tos(), struct conn_struct_tos
);
417 return NT_STATUS_NO_MEMORY
;
421 status
= create_conn_struct_as_root(c
,
428 if (!NT_STATUS_IS_OK(status
)) {
433 talloc_set_destructor(c
, conn_struct_tos_destructor
);
439 /********************************************************
440 Fake up a connection struct for the VFS layer.
441 Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
443 See also the comment for create_conn_struct_tos() above!
445 The CWD change is reverted by the destructor of
446 conn_struct_tos when the current talloc_tos() is destroyed.
447 *********************************************************/
448 NTSTATUS
create_conn_struct_tos_cwd(struct messaging_context
*msg
,
451 const struct auth_session_info
*session_info
,
452 struct conn_struct_tos
**_c
)
454 struct conn_struct_tos
*c
= NULL
;
455 struct smb_filename smb_fname_connectpath
= {0};
460 status
= create_conn_struct_tos(msg
,
465 if (!NT_STATUS_IS_OK(status
)) {
470 * Windows seems to insist on doing trans2getdfsreferral() calls on
471 * the IPC$ share as the anonymous user. If we try to chdir as that
472 * user we will fail.... WTF ? JRA.
475 c
->oldcwd_fname
= vfs_GetWd(c
, c
->conn
);
476 if (c
->oldcwd_fname
== NULL
) {
477 status
= map_nt_error_from_unix(errno
);
478 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno
)));
483 smb_fname_connectpath
= (struct smb_filename
) {
484 .base_name
= c
->conn
->connectpath
487 if (vfs_ChDir(c
->conn
, &smb_fname_connectpath
) != 0) {
488 status
= map_nt_error_from_unix(errno
);
489 DBG_NOTICE("Can't ChDir to new conn path %s. "
491 c
->conn
->connectpath
, strerror(errno
));
492 TALLOC_FREE(c
->oldcwd_fname
);
501 static void shuffle_strlist(char **list
, int count
)
507 for (i
= count
; i
> 1; i
--) {
508 r
= generate_random() % i
;
516 /**********************************************************************
517 Parse the contents of a symlink to verify if it is an msdfs referral
518 A valid referral is of the form:
520 msdfs:server1\share1,server2\share2
521 msdfs:server1\share1\pathname,server2\share2\pathname
522 msdfs:server1/share1,server2/share2
523 msdfs:server1/share1/pathname,server2/share2/pathname.
525 Note that the alternate paths returned here must be of the canonicalized
529 \server\share\path\to\file,
531 even in posix path mode. This is because we have no knowledge if the
532 server we're referring to understands posix paths.
533 **********************************************************************/
535 static bool parse_msdfs_symlink(TALLOC_CTX
*ctx
,
538 struct referral
**preflist
,
543 char **alt_path
= NULL
;
545 struct referral
*reflist
;
548 temp
= talloc_strdup(ctx
, target
);
552 prot
= strtok_r(temp
, ":", &saveptr
);
554 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
558 alt_path
= talloc_array(ctx
, char *, MAX_REFERRAL_COUNT
);
563 /* parse out the alternate paths */
564 while((count
<MAX_REFERRAL_COUNT
) &&
565 ((alt_path
[count
] = strtok_r(NULL
, ",", &saveptr
)) != NULL
)) {
569 /* shuffle alternate paths */
570 if (lp_msdfs_shuffle_referrals(snum
)) {
571 shuffle_strlist(alt_path
, count
);
574 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count
));
577 reflist
= *preflist
= talloc_zero_array(ctx
,
578 struct referral
, count
);
579 if(reflist
== NULL
) {
580 TALLOC_FREE(alt_path
);
584 reflist
= *preflist
= NULL
;
587 for(i
=0;i
<count
;i
++) {
590 /* Canonicalize link target.
591 * Replace all /'s in the path by a \ */
592 string_replace(alt_path
[i
], '/', '\\');
594 /* Remove leading '\\'s */
596 while (*p
&& (*p
== '\\')) {
600 reflist
[i
].alternate_path
= talloc_asprintf(ctx
,
603 if (!reflist
[i
].alternate_path
) {
607 reflist
[i
].proximity
= 0;
608 reflist
[i
].ttl
= REFERRAL_TTL
;
609 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
610 reflist
[i
].alternate_path
));
615 TALLOC_FREE(alt_path
);
619 /**********************************************************************
620 Returns true if the unix path is a valid msdfs symlink and also
621 returns the target string from inside the link.
622 **********************************************************************/
624 static bool is_msdfs_link_internal(TALLOC_CTX
*ctx
,
625 connection_struct
*conn
,
626 struct smb_filename
*smb_fname
,
627 char **pp_link_target
)
629 int referral_len
= 0;
630 #if defined(HAVE_BROKEN_READLINK)
631 char link_target_buf
[PATH_MAX
];
633 char link_target_buf
[7];
636 char *link_target
= NULL
;
638 if (pp_link_target
) {
640 link_target
= talloc_array(ctx
, char, bufsize
);
644 *pp_link_target
= link_target
;
646 bufsize
= sizeof(link_target_buf
);
647 link_target
= link_target_buf
;
650 if (SMB_VFS_LSTAT(conn
, smb_fname
) != 0) {
651 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
652 smb_fname
->base_name
));
655 if (!S_ISLNK(smb_fname
->st
.st_ex_mode
)) {
656 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
657 smb_fname
->base_name
));
661 referral_len
= SMB_VFS_READLINK(conn
, smb_fname
,
662 link_target
, bufsize
- 1);
663 if (referral_len
== -1) {
664 DEBUG(0,("is_msdfs_link_read_target: Error reading "
665 "msdfs link %s: %s\n",
666 smb_fname
->base_name
, strerror(errno
)));
669 link_target
[referral_len
] = '\0';
671 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n", smb_fname
->base_name
,
674 if (!strnequal(link_target
, "msdfs:", 6)) {
681 if (link_target
!= link_target_buf
) {
682 TALLOC_FREE(link_target
);
687 /**********************************************************************
688 Returns true if the unix path is a valid msdfs symlink.
689 **********************************************************************/
691 bool is_msdfs_link(connection_struct
*conn
,
692 struct smb_filename
*smb_fname
)
694 return is_msdfs_link_internal(talloc_tos(),
700 /*****************************************************************
701 Used by other functions to decide if a dfs path is remote,
702 and to get the list of referred locations for that remote path.
704 search_flag: For findfirsts, dfs links themselves are not
705 redirected, but paths beyond the links are. For normal smb calls,
706 even dfs links need to be redirected.
708 consumedcntp: how much of the dfs path is being redirected. the client
709 should try the remaining path on the redirected server.
711 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
712 link redirect are in targetpath.
713 *****************************************************************/
715 static NTSTATUS
dfs_path_lookup(TALLOC_CTX
*ctx
,
716 connection_struct
*conn
,
717 const char *dfspath
, /* Incoming complete dfs path */
718 const struct dfs_path
*pdp
, /* Parsed out
719 server+share+extrapath. */
722 char **pp_targetpath
)
727 struct smb_filename
*smb_fname
= NULL
;
728 char *canon_dfspath
= NULL
; /* Canonicalized dfs path. (only '/'
731 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
732 conn
->connectpath
, pdp
->reqpath
));
735 * Note the unix path conversion here we're doing we
736 * throw away. We're looking for a symlink for a dfs
737 * resolution, if we don't find it we'll do another
738 * unix_convert later in the codepath.
741 status
= unix_convert(ctx
, conn
, pdp
->reqpath
, &smb_fname
,
744 if (!NT_STATUS_IS_OK(status
)) {
745 if (!NT_STATUS_EQUAL(status
,
746 NT_STATUS_OBJECT_PATH_NOT_FOUND
)) {
749 if (smb_fname
== NULL
|| smb_fname
->base_name
== NULL
) {
754 /* Optimization - check if we can redirect the whole path. */
756 if (is_msdfs_link_internal(ctx
, conn
, smb_fname
, pp_targetpath
)) {
757 /* XX_ALLOW_WCARD_XXX is called from search functions. */
759 (UCF_COND_ALLOW_WCARD_LCOMP
|
760 UCF_ALWAYS_ALLOW_WCARD_LCOMP
)) {
761 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
762 "for dfs link %s.\n", dfspath
));
763 status
= NT_STATUS_OK
;
767 DEBUG(6,("dfs_path_lookup: %s resolves to a "
768 "valid dfs link %s.\n", dfspath
,
769 pp_targetpath
? *pp_targetpath
: ""));
772 *consumedcntp
= strlen(dfspath
);
774 status
= NT_STATUS_PATH_NOT_COVERED
;
778 /* Prepare to test only for '/' components in the given path,
779 * so if a Windows path replace all '\\' characters with '/'.
780 * For a POSIX DFS path we know all separators are already '/'. */
782 canon_dfspath
= talloc_strdup(ctx
, dfspath
);
783 if (!canon_dfspath
) {
784 status
= NT_STATUS_NO_MEMORY
;
787 if (!pdp
->posix_path
) {
788 string_replace(canon_dfspath
, '\\', '/');
792 * localpath comes out of unix_convert, so it has
793 * no trailing backslash. Make sure that canon_dfspath hasn't either.
794 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
797 trim_char(canon_dfspath
,0,'/');
800 * Redirect if any component in the path is a link.
801 * We do this by walking backwards through the
802 * local path, chopping off the last component
803 * in both the local path and the canonicalized
804 * DFS path. If we hit a DFS link then we're done.
807 p
= strrchr_m(smb_fname
->base_name
, '/');
809 q
= strrchr_m(canon_dfspath
, '/');
818 if (is_msdfs_link_internal(ctx
, conn
,
819 smb_fname
, pp_targetpath
)) {
820 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
821 "parent %s is dfs link\n", dfspath
,
822 smb_fname_str_dbg(smb_fname
)));
825 *consumedcntp
= strlen(canon_dfspath
);
826 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
832 status
= NT_STATUS_PATH_NOT_COVERED
;
836 /* Step back on the filesystem. */
837 p
= strrchr_m(smb_fname
->base_name
, '/');
840 /* And in the canonicalized dfs path. */
841 q
= strrchr_m(canon_dfspath
, '/');
845 status
= NT_STATUS_OK
;
847 TALLOC_FREE(smb_fname
);
851 /*****************************************************************
852 Decides if a dfs pathname should be redirected or not.
853 If not, the pathname is converted to a tcon-relative local unix path
855 search_wcard_flag: this flag performs 2 functions both related
856 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
859 This function can return NT_STATUS_OK, meaning use the returned path as-is
860 (mapped into a local path).
861 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
862 any other NT_STATUS error which is a genuine error to be
863 returned to the client.
864 *****************************************************************/
866 static NTSTATUS
dfs_redirect(TALLOC_CTX
*ctx
,
867 connection_struct
*conn
,
870 bool allow_broken_path
,
872 bool *ppath_contains_wcard
)
875 bool search_wcard_flag
= (ucf_flags
&
876 (UCF_COND_ALLOW_WCARD_LCOMP
|UCF_ALWAYS_ALLOW_WCARD_LCOMP
));
877 struct dfs_path
*pdp
= talloc(ctx
, struct dfs_path
);
880 return NT_STATUS_NO_MEMORY
;
883 status
= parse_dfs_path(conn
, path_in
, search_wcard_flag
,
884 allow_broken_path
, pdp
,
885 ppath_contains_wcard
);
886 if (!NT_STATUS_IS_OK(status
)) {
891 if (pdp
->reqpath
[0] == '\0') {
893 *pp_path_out
= talloc_strdup(ctx
, "");
895 return NT_STATUS_NO_MEMORY
;
897 DEBUG(5,("dfs_redirect: self-referral.\n"));
901 /* If dfs pathname for a non-dfs share, convert to tcon-relative
902 path and return OK */
904 if (!lp_msdfs_root(SNUM(conn
))) {
905 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
908 return NT_STATUS_NO_MEMORY
;
913 /* If it looked like a local path (zero hostname/servicename)
914 * just treat as a tcon-relative path. */
916 if (pdp
->hostname
[0] == '\0' && pdp
->servicename
[0] == '\0') {
917 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
920 return NT_STATUS_NO_MEMORY
;
925 if (!( strequal(pdp
->servicename
, lp_servicename(talloc_tos(), SNUM(conn
)))
926 || (strequal(pdp
->servicename
, HOMES_NAME
)
927 && strequal(lp_servicename(talloc_tos(), SNUM(conn
)),
928 conn
->session_info
->unix_info
->sanitized_username
) )) ) {
930 /* The given sharename doesn't match this connection. */
933 return NT_STATUS_OBJECT_PATH_NOT_FOUND
;
936 status
= dfs_path_lookup(ctx
, conn
, path_in
, pdp
,
937 ucf_flags
, NULL
, NULL
);
938 if (!NT_STATUS_IS_OK(status
)) {
939 if (NT_STATUS_EQUAL(status
, NT_STATUS_PATH_NOT_COVERED
)) {
940 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in
));
942 DEBUG(10,("dfs_redirect: dfs_path_lookup "
943 "failed for %s with %s\n",
944 path_in
, nt_errstr(status
) ));
949 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in
));
951 /* Form non-dfs tcon-relative path */
952 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
955 return NT_STATUS_NO_MEMORY
;
958 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
965 /**********************************************************************
966 Return a self referral.
967 **********************************************************************/
969 static NTSTATUS
self_ref(TALLOC_CTX
*ctx
,
970 const char *dfs_path
,
971 struct junction_map
*jucn
,
973 bool *self_referralp
)
975 struct referral
*ref
;
977 *self_referralp
= True
;
979 jucn
->referral_count
= 1;
980 if((ref
= talloc_zero(ctx
, struct referral
)) == NULL
) {
981 return NT_STATUS_NO_MEMORY
;
984 ref
->alternate_path
= talloc_strdup(ctx
, dfs_path
);
985 if (!ref
->alternate_path
) {
987 return NT_STATUS_NO_MEMORY
;
990 ref
->ttl
= REFERRAL_TTL
;
991 jucn
->referral_list
= ref
;
992 *consumedcntp
= strlen(dfs_path
);
996 /**********************************************************************
997 Gets valid referrals for a dfs path and fills up the
998 junction_map structure.
999 **********************************************************************/
1001 NTSTATUS
get_referred_path(TALLOC_CTX
*ctx
,
1002 const char *dfs_path
,
1003 const struct tsocket_address
*remote_address
,
1004 const struct tsocket_address
*local_address
,
1005 bool allow_broken_path
,
1006 struct junction_map
*jucn
,
1008 bool *self_referralp
)
1010 TALLOC_CTX
*frame
= talloc_stackframe();
1011 struct conn_struct_tos
*c
= NULL
;
1012 struct connection_struct
*conn
= NULL
;
1013 char *targetpath
= NULL
;
1015 NTSTATUS status
= NT_STATUS_NOT_FOUND
;
1017 struct dfs_path
*pdp
= talloc_zero(frame
, struct dfs_path
);
1021 return NT_STATUS_NO_MEMORY
;
1024 *self_referralp
= False
;
1026 status
= parse_dfs_path(NULL
, dfs_path
, False
, allow_broken_path
,
1028 if (!NT_STATUS_IS_OK(status
)) {
1033 jucn
->service_name
= talloc_strdup(ctx
, pdp
->servicename
);
1034 jucn
->volume_name
= talloc_strdup(ctx
, pdp
->reqpath
);
1035 if (!jucn
->service_name
|| !jucn
->volume_name
) {
1037 return NT_STATUS_NO_MEMORY
;
1040 /* Verify the share is a dfs root */
1041 snum
= lp_servicenumber(jucn
->service_name
);
1043 char *service_name
= NULL
;
1044 if ((snum
= find_service(ctx
, jucn
->service_name
, &service_name
)) < 0) {
1046 return NT_STATUS_NOT_FOUND
;
1048 if (!service_name
) {
1050 return NT_STATUS_NO_MEMORY
;
1052 TALLOC_FREE(jucn
->service_name
);
1053 jucn
->service_name
= talloc_strdup(ctx
, service_name
);
1054 if (!jucn
->service_name
) {
1056 return NT_STATUS_NO_MEMORY
;
1060 if (!lp_msdfs_root(snum
) && (*lp_msdfs_proxy(talloc_tos(), snum
) == '\0')) {
1061 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
1063 pdp
->servicename
, dfs_path
));
1065 return NT_STATUS_NOT_FOUND
;
1069 * Self referrals are tested with a anonymous IPC connection and
1070 * a GET_DFS_REFERRAL call to \\server\share. (which means
1071 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
1072 * into the directory and will fail if it cannot (as the anonymous
1073 * user). Cope with this.
1076 if (pdp
->reqpath
[0] == '\0') {
1078 struct referral
*ref
;
1081 if (*lp_msdfs_proxy(talloc_tos(), snum
) == '\0') {
1083 return self_ref(ctx
,
1091 * It's an msdfs proxy share. Redirect to
1092 * the configured target share.
1095 tmp
= talloc_asprintf(frame
, "msdfs:%s",
1096 lp_msdfs_proxy(frame
, snum
));
1099 return NT_STATUS_NO_MEMORY
;
1102 if (!parse_msdfs_symlink(ctx
, snum
, tmp
, &ref
, &refcount
)) {
1104 return NT_STATUS_INVALID_PARAMETER
;
1106 jucn
->referral_count
= refcount
;
1107 jucn
->referral_list
= ref
;
1108 *consumedcntp
= strlen(dfs_path
);
1110 return NT_STATUS_OK
;
1113 status
= create_conn_struct_tos_cwd(server_messaging_context(),
1115 lp_path(frame
, snum
),
1118 if (!NT_STATUS_IS_OK(status
)) {
1127 * The remote and local address should be passed down to
1128 * create_conn_struct_cwd.
1130 if (conn
->sconn
->remote_address
== NULL
) {
1131 conn
->sconn
->remote_address
=
1132 tsocket_address_copy(remote_address
, conn
->sconn
);
1133 if (conn
->sconn
->remote_address
== NULL
) {
1135 return NT_STATUS_NO_MEMORY
;
1138 if (conn
->sconn
->local_address
== NULL
) {
1139 conn
->sconn
->local_address
=
1140 tsocket_address_copy(local_address
, conn
->sconn
);
1141 if (conn
->sconn
->local_address
== NULL
) {
1143 return NT_STATUS_NO_MEMORY
;
1147 /* If this is a DFS path dfs_lookup should return
1148 * NT_STATUS_PATH_NOT_COVERED. */
1150 status
= dfs_path_lookup(ctx
, conn
, dfs_path
, pdp
,
1151 0, consumedcntp
, &targetpath
);
1153 if (!NT_STATUS_EQUAL(status
, NT_STATUS_PATH_NOT_COVERED
)) {
1154 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
1156 if (NT_STATUS_IS_OK(status
)) {
1158 * We are in an error path here (we
1159 * know it's not a DFS path), but
1160 * dfs_path_lookup() can return
1161 * NT_STATUS_OK. Ensure we always
1162 * return a valid error code.
1164 * #9588 - ACLs are not inherited to directories
1167 status
= NT_STATUS_NOT_FOUND
;
1172 /* We know this is a valid dfs link. Parse the targetpath. */
1173 if (!parse_msdfs_symlink(ctx
, snum
, targetpath
,
1174 &jucn
->referral_list
,
1175 &jucn
->referral_count
)) {
1176 DEBUG(3,("get_referred_path: failed to parse symlink "
1177 "target %s\n", targetpath
));
1178 status
= NT_STATUS_NOT_FOUND
;
1182 status
= NT_STATUS_OK
;
1188 /******************************************************************
1189 Set up the DFS referral for the dfs pathname. This call returns
1190 the amount of the path covered by this server, and where the
1191 client should be redirected to. This is the meat of the
1192 TRANS2_GET_DFS_REFERRAL call.
1193 ******************************************************************/
1195 int setup_dfs_referral(connection_struct
*orig_conn
,
1196 const char *dfs_path
,
1197 int max_referral_level
,
1198 char **ppdata
, NTSTATUS
*pstatus
)
1200 char *pdata
= *ppdata
;
1202 struct dfs_GetDFSReferral
*r
;
1203 DATA_BLOB blob
= data_blob_null
;
1205 enum ndr_err_code ndr_err
;
1207 r
= talloc_zero(talloc_tos(), struct dfs_GetDFSReferral
);
1209 *pstatus
= NT_STATUS_NO_MEMORY
;
1213 r
->in
.req
.max_referral_level
= max_referral_level
;
1214 r
->in
.req
.servername
= talloc_strdup(r
, dfs_path
);
1215 if (r
->in
.req
.servername
== NULL
) {
1217 *pstatus
= NT_STATUS_NO_MEMORY
;
1221 status
= SMB_VFS_GET_DFS_REFERRALS(orig_conn
, r
);
1222 if (!NT_STATUS_IS_OK(status
)) {
1228 ndr_err
= ndr_push_struct_blob(&blob
, r
,
1230 (ndr_push_flags_fn_t
)ndr_push_dfs_referral_resp
);
1231 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1233 *pstatus
= NT_STATUS_INVALID_PARAMETER
;
1237 pdata
= (char *)SMB_REALLOC(pdata
, blob
.length
);
1240 DEBUG(0,("referral setup:"
1241 "malloc failed for Realloc!\n"));
1245 reply_size
= blob
.length
;
1246 memcpy(pdata
, blob
.data
, blob
.length
);
1249 *pstatus
= NT_STATUS_OK
;
1253 /**********************************************************************
1254 The following functions are called by the NETDFS RPC pipe functions
1255 **********************************************************************/
1257 /*********************************************************************
1258 Creates a junction structure from a DFS pathname
1259 **********************************************************************/
1261 bool create_junction(TALLOC_CTX
*ctx
,
1262 const char *dfs_path
,
1263 bool allow_broken_path
,
1264 struct junction_map
*jucn
)
1268 struct dfs_path
*pdp
= talloc(ctx
,struct dfs_path
);
1274 status
= parse_dfs_path(NULL
, dfs_path
, False
, allow_broken_path
,
1276 if (!NT_STATUS_IS_OK(status
)) {
1280 /* check if path is dfs : validate first token */
1281 if (!is_myname_or_ipaddr(pdp
->hostname
)) {
1282 DEBUG(4,("create_junction: Invalid hostname %s "
1284 pdp
->hostname
, dfs_path
));
1289 /* Check for a non-DFS share */
1290 snum
= lp_servicenumber(pdp
->servicename
);
1292 if(snum
< 0 || !lp_msdfs_root(snum
)) {
1293 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1299 jucn
->service_name
= talloc_strdup(ctx
, pdp
->servicename
);
1300 jucn
->volume_name
= talloc_strdup(ctx
, pdp
->reqpath
);
1301 jucn
->comment
= lp_comment(ctx
, snum
);
1304 if (!jucn
->service_name
|| !jucn
->volume_name
|| ! jucn
->comment
) {
1310 /**********************************************************************
1311 Forms a valid Unix pathname from the junction
1312 **********************************************************************/
1314 static bool junction_to_local_path_tos(const struct junction_map
*jucn
,
1316 connection_struct
**conn_out
)
1318 struct conn_struct_tos
*c
= NULL
;
1320 char *path_out
= NULL
;
1323 snum
= lp_servicenumber(jucn
->service_name
);
1327 status
= create_conn_struct_tos_cwd(server_messaging_context(),
1329 lp_path(talloc_tos(), snum
),
1332 if (!NT_STATUS_IS_OK(status
)) {
1336 path_out
= talloc_asprintf(c
,
1338 lp_path(talloc_tos(), snum
),
1340 if (path_out
== NULL
) {
1344 *pp_path_out
= path_out
;
1345 *conn_out
= c
->conn
;
1349 bool create_msdfs_link(const struct junction_map
*jucn
)
1351 TALLOC_CTX
*frame
= talloc_stackframe();
1353 char *msdfs_link
= NULL
;
1354 connection_struct
*conn
;
1356 bool insert_comma
= False
;
1358 struct smb_filename
*smb_fname
= NULL
;
1361 ok
= junction_to_local_path_tos(jucn
, &path
, &conn
);
1367 /* Form the msdfs_link contents */
1368 msdfs_link
= talloc_strdup(conn
, "msdfs:");
1372 for(i
=0; i
<jucn
->referral_count
; i
++) {
1373 char *refpath
= jucn
->referral_list
[i
].alternate_path
;
1375 /* Alternate paths always use Windows separators. */
1376 trim_char(refpath
, '\\', '\\');
1377 if(*refpath
== '\0') {
1379 insert_comma
= False
;
1383 if (i
> 0 && insert_comma
) {
1384 msdfs_link
= talloc_asprintf_append_buffer(msdfs_link
,
1388 msdfs_link
= talloc_asprintf_append_buffer(msdfs_link
,
1396 if (!insert_comma
) {
1397 insert_comma
= True
;
1401 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1404 smb_fname
= synthetic_smb_fname(frame
,
1409 if (smb_fname
== NULL
) {
1414 if(SMB_VFS_SYMLINK(conn
, msdfs_link
, smb_fname
) < 0) {
1415 if (errno
== EEXIST
) {
1416 if(SMB_VFS_UNLINK(conn
, smb_fname
)!=0) {
1417 TALLOC_FREE(smb_fname
);
1421 if (SMB_VFS_SYMLINK(conn
, msdfs_link
, smb_fname
) < 0) {
1422 DEBUG(1,("create_msdfs_link: symlink failed "
1423 "%s -> %s\nError: %s\n",
1424 path
, msdfs_link
, strerror(errno
)));
1436 bool remove_msdfs_link(const struct junction_map
*jucn
)
1438 TALLOC_CTX
*frame
= talloc_stackframe();
1440 connection_struct
*conn
;
1442 struct smb_filename
*smb_fname
;
1445 ok
= junction_to_local_path_tos(jucn
, &path
, &conn
);
1451 smb_fname
= synthetic_smb_fname(frame
,
1456 if (smb_fname
== NULL
) {
1462 if( SMB_VFS_UNLINK(conn
, smb_fname
) == 0 ) {
1470 /*********************************************************************
1471 Return the number of DFS links at the root of this share.
1472 *********************************************************************/
1474 static int count_dfs_links(TALLOC_CTX
*ctx
, int snum
)
1476 TALLOC_CTX
*frame
= talloc_stackframe();
1479 const char *dname
= NULL
;
1480 char *talloced
= NULL
;
1481 const char *connect_path
= lp_path(frame
, snum
);
1482 const char *msdfs_proxy
= lp_msdfs_proxy(frame
, snum
);
1483 struct conn_struct_tos
*c
= NULL
;
1484 connection_struct
*conn
= NULL
;
1486 struct smb_filename
*smb_fname
= NULL
;
1488 if(*connect_path
== '\0') {
1494 * Fake up a connection struct for the VFS layer.
1497 status
= create_conn_struct_tos_cwd(server_messaging_context(),
1502 if (!NT_STATUS_IS_OK(status
)) {
1503 DEBUG(3, ("create_conn_struct failed: %s\n",
1504 nt_errstr(status
)));
1510 /* Count a link for the msdfs root - convention */
1513 /* No more links if this is an msdfs proxy. */
1514 if (*msdfs_proxy
!= '\0') {
1518 smb_fname
= synthetic_smb_fname(frame
,
1523 if (smb_fname
== NULL
) {
1527 /* Now enumerate all dfs links */
1528 dirp
= SMB_VFS_OPENDIR(conn
, smb_fname
, NULL
, 0);
1533 while ((dname
= vfs_readdirname(conn
, dirp
, NULL
, &talloced
))
1535 struct smb_filename
*smb_dname
=
1536 synthetic_smb_fname(frame
,
1541 if (smb_dname
== NULL
) {
1544 if (is_msdfs_link(conn
, smb_dname
)) {
1547 TALLOC_FREE(talloced
);
1548 TALLOC_FREE(smb_dname
);
1551 SMB_VFS_CLOSEDIR(conn
,dirp
);
1558 /*********************************************************************
1559 *********************************************************************/
1561 static int form_junctions(TALLOC_CTX
*ctx
,
1563 struct junction_map
*jucn
,
1566 TALLOC_CTX
*frame
= talloc_stackframe();
1569 const char *dname
= NULL
;
1570 char *talloced
= NULL
;
1571 const char *connect_path
= lp_path(frame
, snum
);
1572 char *service_name
= lp_servicename(frame
, snum
);
1573 const char *msdfs_proxy
= lp_msdfs_proxy(frame
, snum
);
1574 struct conn_struct_tos
*c
= NULL
;
1575 connection_struct
*conn
= NULL
;
1576 struct referral
*ref
= NULL
;
1577 struct smb_filename
*smb_fname
= NULL
;
1580 if (jn_remain
== 0) {
1585 if(*connect_path
== '\0') {
1591 * Fake up a connection struct for the VFS layer.
1594 status
= create_conn_struct_tos_cwd(server_messaging_context(),
1599 if (!NT_STATUS_IS_OK(status
)) {
1600 DEBUG(3, ("create_conn_struct failed: %s\n",
1601 nt_errstr(status
)));
1607 /* form a junction for the msdfs root - convention
1608 DO NOT REMOVE THIS: NT clients will not work with us
1609 if this is not present
1611 jucn
[cnt
].service_name
= talloc_strdup(ctx
,service_name
);
1612 jucn
[cnt
].volume_name
= talloc_strdup(ctx
, "");
1613 if (!jucn
[cnt
].service_name
|| !jucn
[cnt
].volume_name
) {
1616 jucn
[cnt
].comment
= "";
1617 jucn
[cnt
].referral_count
= 1;
1619 ref
= jucn
[cnt
].referral_list
= talloc_zero(ctx
, struct referral
);
1620 if (jucn
[cnt
].referral_list
== NULL
) {
1625 ref
->ttl
= REFERRAL_TTL
;
1626 if (*msdfs_proxy
!= '\0') {
1627 ref
->alternate_path
= talloc_strdup(ctx
,
1630 ref
->alternate_path
= talloc_asprintf(ctx
,
1632 get_local_machine_name(),
1636 if (!ref
->alternate_path
) {
1641 /* Don't enumerate if we're an msdfs proxy. */
1642 if (*msdfs_proxy
!= '\0') {
1646 smb_fname
= synthetic_smb_fname(frame
,
1651 if (smb_fname
== NULL
) {
1655 /* Now enumerate all dfs links */
1656 dirp
= SMB_VFS_OPENDIR(conn
, smb_fname
, NULL
, 0);
1661 while ((dname
= vfs_readdirname(conn
, dirp
, NULL
, &talloced
))
1663 char *link_target
= NULL
;
1664 struct smb_filename
*smb_dname
= NULL
;
1666 if (cnt
>= jn_remain
) {
1667 DEBUG(2, ("form_junctions: ran out of MSDFS "
1669 TALLOC_FREE(talloced
);
1672 smb_dname
= synthetic_smb_fname(talloc_tos(),
1677 if (smb_dname
== NULL
) {
1678 TALLOC_FREE(talloced
);
1681 if (is_msdfs_link_internal(ctx
,
1683 smb_dname
, &link_target
)) {
1684 if (parse_msdfs_symlink(ctx
, snum
,
1686 &jucn
[cnt
].referral_list
,
1687 &jucn
[cnt
].referral_count
)) {
1689 jucn
[cnt
].service_name
= talloc_strdup(ctx
,
1691 jucn
[cnt
].volume_name
= talloc_strdup(ctx
,
1693 if (!jucn
[cnt
].service_name
||
1694 !jucn
[cnt
].volume_name
) {
1695 TALLOC_FREE(talloced
);
1698 jucn
[cnt
].comment
= "";
1701 TALLOC_FREE(link_target
);
1703 TALLOC_FREE(talloced
);
1704 TALLOC_FREE(smb_dname
);
1710 SMB_VFS_CLOSEDIR(conn
,dirp
);
1717 struct junction_map
*enum_msdfs_links(TALLOC_CTX
*ctx
, size_t *p_num_jn
)
1719 struct junction_map
*jn
= NULL
;
1721 size_t jn_count
= 0;
1725 if(!lp_host_msdfs()) {
1729 /* Ensure all the usershares are loaded. */
1731 load_registry_shares();
1732 sharecount
= load_usershare_shares(NULL
, connections_snum_used
);
1735 for(i
=0;i
< sharecount
;i
++) {
1736 if(lp_msdfs_root(i
)) {
1737 jn_count
+= count_dfs_links(ctx
, i
);
1740 if (jn_count
== 0) {
1743 jn
= talloc_array(ctx
, struct junction_map
, jn_count
);
1747 for(i
=0; i
< sharecount
; i
++) {
1748 if (*p_num_jn
>= jn_count
) {
1751 if(lp_msdfs_root(i
)) {
1752 *p_num_jn
+= form_junctions(ctx
, i
,
1754 jn_count
- *p_num_jn
);
1760 /******************************************************************************
1761 Core function to resolve a dfs pathname possibly containing a wildcard. If
1762 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1763 detected during dfs resolution.
1764 ******************************************************************************/
1766 NTSTATUS
resolve_dfspath_wcard(TALLOC_CTX
*ctx
,
1767 connection_struct
*conn
,
1768 const char *name_in
,
1770 bool allow_broken_path
,
1772 bool *ppath_contains_wcard
)
1774 bool path_contains_wcard
= false;
1775 NTSTATUS status
= NT_STATUS_OK
;
1777 status
= dfs_redirect(ctx
,
1783 &path_contains_wcard
);
1785 if (NT_STATUS_IS_OK(status
) &&
1786 ppath_contains_wcard
!= NULL
&&
1787 path_contains_wcard
) {
1788 *ppath_contains_wcard
= path_contains_wcard
;