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"
36 #include "lib/global_contexts.h"
37 #include "source3/lib/substitute.h"
39 /**********************************************************************
40 Parse a DFS pathname of the form \hostname\service\reqpath
41 into the dfs_path structure.
42 If POSIX pathnames is true, the pathname may also be of the
43 form /hostname/service/reqpath.
44 We cope with either here.
46 Unfortunately, due to broken clients who might set the
47 SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
48 send a local path, we have to cope with that too....
50 If conn != NULL then ensure the provided service is
51 the one pointed to by the connection.
53 This version does everything using pointers within one copy of the
54 pathname string, talloced on the struct dfs_path pointer (which
55 must be talloced). This may be too clever to live....
57 **********************************************************************/
59 static NTSTATUS parse_dfs_path(connection_struct *conn,
62 bool allow_broken_path,
63 struct dfs_path *pdp) /* MUST BE TALLOCED */
65 const struct loadparm_substitution *lp_sub =
66 loadparm_s3_global_substitution();
71 NTSTATUS status = NT_STATUS_OK;
77 * This is the only talloc we should need to do
78 * on the struct dfs_path. All the pointers inside
79 * it should point to offsets within this string.
82 pathname_local = talloc_strdup(pdp, pathname);
83 if (!pathname_local) {
84 return NT_STATUS_NO_MEMORY;
86 /* Get a pointer to the terminating '\0' */
87 eos_ptr = &pathname_local[strlen(pathname_local)];
88 p = temp = pathname_local;
91 * Non-broken DFS paths *must* start with the
92 * path separator. For Windows this is always '\\',
93 * for posix paths this is always '/'.
96 if (*pathname == '/') {
97 pdp->posix_path = true;
100 pdp->posix_path = false;
104 if (allow_broken_path && (*pathname != sepchar)) {
105 DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
106 pathname, sepchar ));
108 * Possibly client sent a local path by mistake.
109 * Try and convert to a local path.
110 * Note that this is an SMB1-only fallback
111 * to cope with known broken SMB1 clients.
114 pdp->hostname = eos_ptr; /* "" */
115 pdp->servicename = eos_ptr; /* "" */
117 /* We've got no info about separators. */
118 pdp->posix_path = lp_posix_pathnames();
120 DEBUG(10,("parse_dfs_path: trying to convert %s to a "
127 * Safe to use on talloc'ed string as it only shrinks.
128 * It also doesn't affect the eos_ptr.
130 trim_char(temp,sepchar,sepchar);
132 DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
136 /* Parse out hostname. */
137 p = strchr_m(temp,sepchar);
139 DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
142 * Possibly client sent a local path by mistake.
143 * Try and convert to a local path.
146 pdp->hostname = eos_ptr; /* "" */
147 pdp->servicename = eos_ptr; /* "" */
150 DEBUG(10,("parse_dfs_path: trying to convert %s "
156 pdp->hostname = temp;
158 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
160 /* Parse out servicename. */
162 p = strchr_m(servicename,sepchar);
167 /* Is this really our servicename ? */
168 if (conn && !( strequal(servicename, lp_servicename(talloc_tos(), lp_sub, SNUM(conn)))
169 || (strequal(servicename, HOMES_NAME)
170 && strequal(lp_servicename(talloc_tos(), lp_sub, SNUM(conn)),
171 get_current_username()) )) ) {
172 DEBUG(10,("parse_dfs_path: %s is not our servicename\n",
176 * Possibly client sent a local path by mistake.
177 * Try and convert to a local path.
180 pdp->hostname = eos_ptr; /* "" */
181 pdp->servicename = eos_ptr; /* "" */
183 /* Repair the path - replace the sepchar's
186 *servicename = sepchar;
192 DEBUG(10,("parse_dfs_path: trying to convert %s "
198 pdp->servicename = servicename;
200 DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
203 /* Client sent self referral \server\share. */
204 pdp->reqpath = eos_ptr; /* "" */
214 /* Rest is reqpath. */
215 if (pdp->posix_path) {
216 status = check_path_syntax_posix(pdp->reqpath);
219 bool has_wcard = ms_has_wild(pdp->reqpath);
221 return NT_STATUS_INVALID_PARAMETER;
224 status = check_path_syntax(pdp->reqpath);
227 if (!NT_STATUS_IS_OK(status)) {
228 DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
229 p, nt_errstr(status) ));
233 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
237 /********************************************************
238 Fake up a connection struct for the VFS layer, for use in
239 applications (such as the python bindings), that do not want the
240 global working directory changed under them.
242 SMB_VFS_CONNECT requires root privileges.
243 *********************************************************/
245 static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx,
246 struct tevent_context *ev,
247 struct messaging_context *msg,
248 connection_struct **pconn,
251 const struct auth_session_info *session_info)
253 connection_struct *conn;
255 const char *vfs_user;
256 struct smbd_server_connection *sconn;
257 const char *servicename = lp_const_servicename(snum);
260 sconn = talloc_zero(ctx, struct smbd_server_connection);
262 return NT_STATUS_NO_MEMORY;
266 sconn->msg_ctx = msg;
268 conn = conn_new(sconn);
271 return NT_STATUS_NO_MEMORY;
274 /* Now we have conn, we need to make sconn a child of conn,
275 * for a proper talloc tree */
276 talloc_steal(conn, sconn);
278 if (snum == -1 && servicename == NULL) {
279 servicename = "Unknown Service (snum == -1)";
282 connpath = talloc_strdup(conn, path);
285 return NT_STATUS_NO_MEMORY;
287 connpath = talloc_string_sub(conn,
293 return NT_STATUS_NO_MEMORY;
296 /* needed for smbd_vfs_init() */
298 conn->params->service = snum;
299 conn->cnum = TID_FIELD_INVALID;
301 SMB_ASSERT(session_info != NULL);
303 conn->session_info = copy_session_info(conn, session_info);
304 if (conn->session_info == NULL) {
305 DBG_ERR("copy_serverinfo failed\n");
307 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 conn_setup_case_options(conn);
319 set_conn_connectpath(conn, connpath);
322 * New code to check if there's a share security descriptor
323 * added from NT server manager. This is done after the
324 * smb.conf checks are done as we need a uid and token. JRA.
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 DBG_WARNING("connection to %s "
336 "denied due to security "
340 return NT_STATUS_ACCESS_DENIED;
342 conn->read_only = true;
345 if (!smbd_vfs_init(conn)) {
346 NTSTATUS status = map_nt_error_from_unix(errno);
347 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
352 /* this must be the first filesystem operation that we do */
353 if (SMB_VFS_CONNECT(conn, servicename, vfs_user) < 0) {
354 DEBUG(0,("VFS connect failed!\n"));
356 return NT_STATUS_UNSUCCESSFUL;
359 ok = canonicalize_connect_path(conn);
361 DBG_ERR("Failed to canonicalize sharepath\n");
363 return NT_STATUS_ACCESS_DENIED;
366 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
367 conn->tcon_done = true;
368 *pconn = talloc_move(ctx, &conn);
373 static int conn_struct_tos_destructor(struct conn_struct_tos *c)
375 if (c->oldcwd_fname != NULL) {
376 vfs_ChDir(c->conn, c->oldcwd_fname);
377 TALLOC_FREE(c->oldcwd_fname);
379 SMB_VFS_DISCONNECT(c->conn);
384 /********************************************************
385 Fake up a connection struct for the VFS layer, for use in
386 applications (such as the python bindings), that do not want the
387 global working directory changed under them.
389 SMB_VFS_CONNECT requires root privileges.
390 This temporary uses become_root() and unbecome_root().
392 But further impersonation has to be cone by the caller.
393 *********************************************************/
394 NTSTATUS create_conn_struct_tos(struct messaging_context *msg,
397 const struct auth_session_info *session_info,
398 struct conn_struct_tos **_c)
400 struct conn_struct_tos *c = NULL;
401 struct tevent_context *ev = NULL;
406 c = talloc_zero(talloc_tos(), struct conn_struct_tos);
408 return NT_STATUS_NO_MEMORY;
411 ev = samba_tevent_context_init(c);
414 return NT_STATUS_NO_MEMORY;
418 status = create_conn_struct_as_root(c,
426 if (!NT_STATUS_IS_OK(status)) {
431 talloc_set_destructor(c, conn_struct_tos_destructor);
437 /********************************************************
438 Fake up a connection struct for the VFS layer.
439 Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
441 See also the comment for create_conn_struct_tos() above!
443 The CWD change is reverted by the destructor of
444 conn_struct_tos when the current talloc_tos() is destroyed.
445 *********************************************************/
446 NTSTATUS create_conn_struct_tos_cwd(struct messaging_context *msg,
449 const struct auth_session_info *session_info,
450 struct conn_struct_tos **_c)
452 struct conn_struct_tos *c = NULL;
453 struct smb_filename smb_fname_connectpath = {0};
458 status = create_conn_struct_tos(msg,
463 if (!NT_STATUS_IS_OK(status)) {
468 * Windows seems to insist on doing trans2getdfsreferral() calls on
469 * the IPC$ share as the anonymous user. If we try to chdir as that
470 * user we will fail.... WTF ? JRA.
473 c->oldcwd_fname = vfs_GetWd(c, c->conn);
474 if (c->oldcwd_fname == NULL) {
475 status = map_nt_error_from_unix(errno);
476 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
481 smb_fname_connectpath = (struct smb_filename) {
482 .base_name = c->conn->connectpath
485 if (vfs_ChDir(c->conn, &smb_fname_connectpath) != 0) {
486 status = map_nt_error_from_unix(errno);
487 DBG_NOTICE("Can't ChDir to new conn path %s. "
489 c->conn->connectpath, strerror(errno));
490 TALLOC_FREE(c->oldcwd_fname);
499 /********************************************************
500 Fake up a connection struct for the VFS layer.
501 This takes an TALLOC_CTX and tevent_context from the
502 caller and the resulting connection_struct is stable
503 across the lifetime of mem_ctx and ev.
505 Note: this performs a vfs connect and changes cwd.
507 See also the comment for create_conn_struct_tos() above!
508 *********************************************************/
510 NTSTATUS create_conn_struct_cwd(TALLOC_CTX *mem_ctx,
511 struct tevent_context *ev,
512 struct messaging_context *msg,
513 const struct auth_session_info *session_info,
516 struct connection_struct **c)
521 status = create_conn_struct_as_root(mem_ctx,
532 static void shuffle_strlist(char **list, int count)
538 for (i = count; i > 1; i--) {
539 r = generate_random() % i;
547 /**********************************************************************
548 Parse the contents of a symlink to verify if it is an msdfs referral
549 A valid referral is of the form:
551 msdfs:server1\share1,server2\share2
552 msdfs:server1\share1\pathname,server2\share2\pathname
553 msdfs:server1/share1,server2/share2
554 msdfs:server1/share1/pathname,server2/share2/pathname.
556 Note that the alternate paths returned here must be of the canonicalized
560 \server\share\path\to\file,
562 even in posix path mode. This is because we have no knowledge if the
563 server we're referring to understands posix paths.
564 **********************************************************************/
566 bool parse_msdfs_symlink(TALLOC_CTX *ctx,
567 bool shuffle_referrals,
569 struct referral **ppreflist,
574 char **alt_path = NULL;
576 struct referral *reflist = NULL;
579 temp = talloc_strdup(ctx, target);
583 prot = strtok_r(temp, ":", &saveptr);
585 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
590 alt_path = talloc_array(ctx, char *, MAX_REFERRAL_COUNT);
596 /* parse out the alternate paths */
597 while((count<MAX_REFERRAL_COUNT) &&
598 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
602 /* shuffle alternate paths */
603 if (shuffle_referrals) {
604 shuffle_strlist(alt_path, count);
607 DBG_DEBUG("count=%zu\n", count);
610 reflist = talloc_zero_array(ctx,
611 struct referral, count);
612 if(reflist == NULL) {
614 TALLOC_FREE(alt_path);
621 for(i=0;i<count;i++) {
624 /* Canonicalize link target.
625 * Replace all /'s in the path by a \ */
626 string_replace(alt_path[i], '/', '\\');
628 /* Remove leading '\\'s */
630 while (*p && (*p == '\\')) {
634 reflist[i].alternate_path = talloc_asprintf(reflist,
637 if (!reflist[i].alternate_path) {
639 TALLOC_FREE(alt_path);
640 TALLOC_FREE(reflist);
644 reflist[i].proximity = 0;
645 reflist[i].ttl = REFERRAL_TTL;
646 DBG_DEBUG("Created alt path: %s\n",
647 reflist[i].alternate_path);
650 if (ppreflist != NULL) {
651 *ppreflist = reflist;
653 TALLOC_FREE(reflist);
655 if (prefcount != NULL) {
659 TALLOC_FREE(alt_path);
663 /**********************************************************************
664 Returns true if the unix path is a valid msdfs symlink.
665 **********************************************************************/
667 bool is_msdfs_link(struct files_struct *dirfsp,
668 struct smb_filename *atname)
670 NTSTATUS status = SMB_VFS_READ_DFS_PATHAT(dirfsp->conn,
676 return (NT_STATUS_IS_OK(status));
679 /*****************************************************************
680 Used by other functions to decide if a dfs path is remote,
681 and to get the list of referred locations for that remote path.
683 search_flag: For findfirsts, dfs links themselves are not
684 redirected, but paths beyond the links are. For normal smb calls,
685 even dfs links need to be redirected.
687 consumedcntp: how much of the dfs path is being redirected. the client
688 should try the remaining path on the redirected server.
690 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
691 link redirect are in targetpath.
692 *****************************************************************/
694 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
695 connection_struct *conn,
696 const char *dfspath, /* Incoming complete dfs path */
697 const struct dfs_path *pdp, /* Parsed out
698 server+share+extrapath. */
701 struct referral **ppreflist,
702 size_t *preferral_count)
707 struct smb_filename *smb_fname = NULL;
708 struct smb_filename *parent_fname = NULL;
709 struct smb_filename *atname = NULL;
710 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
713 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
714 conn->connectpath, pdp->reqpath));
717 * Note the unix path conversion here we're doing we
718 * throw away. We're looking for a symlink for a dfs
719 * resolution, if we don't find it we'll do another
720 * unix_convert later in the codepath.
723 status = unix_convert(ctx, conn, pdp->reqpath, 0, &smb_fname,
726 if (!NT_STATUS_IS_OK(status)) {
727 if (!NT_STATUS_EQUAL(status,
728 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
731 if (smb_fname == NULL || smb_fname->base_name == NULL) {
736 /* Optimization - check if we can redirect the whole path. */
737 status = parent_pathref(ctx,
742 if (NT_STATUS_IS_OK(status)) {
744 * We must have a parent_fname->fsp before
745 * we can call SMB_VFS_READ_DFS_PATHAT().
747 status = SMB_VFS_READ_DFS_PATHAT(conn,
753 /* We're now done with parent_fname and atname. */
754 TALLOC_FREE(parent_fname);
756 if (NT_STATUS_IS_OK(status)) {
757 /* XX_ALLOW_WCARD_XXX is called from search functions.*/
758 if (ucf_flags & UCF_ALWAYS_ALLOW_WCARD_LCOMP) {
759 DBG_INFO("(FindFirst) No redirection "
760 "for dfs link %s.\n",
762 status = NT_STATUS_OK;
766 DBG_INFO("%s resolves to a valid dfs link\n",
770 *consumedcntp = strlen(dfspath);
772 status = NT_STATUS_PATH_NOT_COVERED;
777 /* Prepare to test only for '/' components in the given path,
778 * so if a Windows path replace all '\\' characters with '/'.
779 * For a POSIX DFS path we know all separators are already '/'. */
781 canon_dfspath = talloc_strdup(ctx, dfspath);
782 if (!canon_dfspath) {
783 status = NT_STATUS_NO_MEMORY;
786 if (!pdp->posix_path) {
787 string_replace(canon_dfspath, '\\', '/');
791 * localpath comes out of unix_convert, so it has
792 * no trailing backslash. Make sure that canon_dfspath hasn't either.
793 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
796 trim_char(canon_dfspath,0,'/');
799 * Redirect if any component in the path is a link.
800 * We do this by walking backwards through the
801 * local path, chopping off the last component
802 * in both the local path and the canonicalized
803 * DFS path. If we hit a DFS link then we're done.
806 p = strrchr_m(smb_fname->base_name, '/');
808 q = strrchr_m(canon_dfspath, '/');
818 * Ensure parent_pathref() calls vfs_stat() on
819 * the newly truncated path.
821 SET_STAT_INVALID(smb_fname->st);
822 status = parent_pathref(ctx,
827 if (NT_STATUS_IS_OK(status)) {
829 * We must have a parent_fname->fsp before
830 * we can call SMB_VFS_READ_DFS_PATHAT().
832 status = SMB_VFS_READ_DFS_PATHAT(conn,
839 /* We're now done with parent_fname and atname. */
840 TALLOC_FREE(parent_fname);
842 if (NT_STATUS_IS_OK(status)) {
843 DBG_INFO("Redirecting %s because "
844 "parent %s is a dfs link\n",
846 smb_fname_str_dbg(smb_fname));
849 *consumedcntp = strlen(canon_dfspath);
850 DBG_DEBUG("Path consumed: %s "
856 status = NT_STATUS_PATH_NOT_COVERED;
861 /* Step back on the filesystem. */
862 p = strrchr_m(smb_fname->base_name, '/');
865 /* And in the canonicalized dfs path. */
866 q = strrchr_m(canon_dfspath, '/');
870 status = NT_STATUS_OK;
873 /* This should already be free, but make sure. */
874 TALLOC_FREE(parent_fname);
875 TALLOC_FREE(smb_fname);
879 /*****************************************************************
880 Decides if a dfs pathname should be redirected or not.
881 If not, the pathname is converted to a tcon-relative local unix path
883 search_wcard_flag: this flag performs 2 functions both related
884 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
887 This function can return NT_STATUS_OK, meaning use the returned path as-is
888 (mapped into a local path).
889 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
890 any other NT_STATUS error which is a genuine error to be
891 returned to the client.
892 *****************************************************************/
894 NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
895 connection_struct *conn,
898 bool allow_broken_path,
901 const struct loadparm_substitution *lp_sub =
902 loadparm_s3_global_substitution();
904 bool search_wcard_flag = (ucf_flags & UCF_ALWAYS_ALLOW_WCARD_LCOMP);
905 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
908 return NT_STATUS_NO_MEMORY;
911 status = parse_dfs_path(conn, path_in, search_wcard_flag,
912 allow_broken_path, pdp);
913 if (!NT_STATUS_IS_OK(status)) {
918 if (pdp->reqpath[0] == '\0') {
920 *pp_path_out = talloc_strdup(ctx, "");
922 return NT_STATUS_NO_MEMORY;
924 DEBUG(5,("dfs_redirect: self-referral.\n"));
928 /* If dfs pathname for a non-dfs share, convert to tcon-relative
929 path and return OK */
931 if (!lp_msdfs_root(SNUM(conn))) {
932 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
935 return NT_STATUS_NO_MEMORY;
940 /* If it looked like a local path (zero hostname/servicename)
941 * just treat as a tcon-relative path. */
943 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
944 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
947 return NT_STATUS_NO_MEMORY;
952 if (!( strequal(pdp->servicename, lp_servicename(talloc_tos(), lp_sub, SNUM(conn)))
953 || (strequal(pdp->servicename, HOMES_NAME)
954 && strequal(lp_servicename(talloc_tos(), lp_sub, SNUM(conn)),
955 conn->session_info->unix_info->sanitized_username) )) ) {
957 /* The given sharename doesn't match this connection. */
960 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
963 status = dfs_path_lookup(ctx,
968 NULL, /* int *consumedcntp */
969 NULL, /* struct referral **ppreflist */
970 NULL); /* size_t *preferral_count */
971 if (!NT_STATUS_IS_OK(status)) {
972 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
973 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
975 DEBUG(10,("dfs_redirect: dfs_path_lookup "
976 "failed for %s with %s\n",
977 path_in, nt_errstr(status) ));
982 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
984 /* Form non-dfs tcon-relative path */
985 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
988 return NT_STATUS_NO_MEMORY;
991 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
998 /**********************************************************************
999 Return a self referral.
1000 **********************************************************************/
1002 static NTSTATUS self_ref(TALLOC_CTX *ctx,
1003 const char *dfs_path,
1004 struct junction_map *jucn,
1006 bool *self_referralp)
1008 struct referral *ref;
1010 *self_referralp = True;
1012 jucn->referral_count = 1;
1013 if((ref = talloc_zero(ctx, struct referral)) == NULL) {
1014 return NT_STATUS_NO_MEMORY;
1017 ref->alternate_path = talloc_strdup(ctx, dfs_path);
1018 if (!ref->alternate_path) {
1020 return NT_STATUS_NO_MEMORY;
1023 ref->ttl = REFERRAL_TTL;
1024 jucn->referral_list = ref;
1025 *consumedcntp = strlen(dfs_path);
1026 return NT_STATUS_OK;
1029 /**********************************************************************
1030 Gets valid referrals for a dfs path and fills up the
1031 junction_map structure.
1032 **********************************************************************/
1034 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
1035 struct auth_session_info *session_info,
1036 const char *dfs_path,
1037 const struct tsocket_address *remote_address,
1038 const struct tsocket_address *local_address,
1039 bool allow_broken_path,
1040 struct junction_map *jucn,
1042 bool *self_referralp)
1044 TALLOC_CTX *frame = talloc_stackframe();
1045 const struct loadparm_substitution *lp_sub =
1046 loadparm_s3_global_substitution();
1047 struct conn_struct_tos *c = NULL;
1048 struct connection_struct *conn = NULL;
1050 NTSTATUS status = NT_STATUS_NOT_FOUND;
1051 struct dfs_path *pdp = talloc_zero(frame, struct dfs_path);
1055 return NT_STATUS_NO_MEMORY;
1058 *self_referralp = False;
1060 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path, pdp);
1061 if (!NT_STATUS_IS_OK(status)) {
1066 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1067 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1068 if (!jucn->service_name || !jucn->volume_name) {
1070 return NT_STATUS_NO_MEMORY;
1073 /* Verify the share is a dfs root */
1074 snum = lp_servicenumber(jucn->service_name);
1076 char *service_name = NULL;
1077 if ((snum = find_service(ctx, jucn->service_name, &service_name)) < 0) {
1079 return NT_STATUS_NOT_FOUND;
1081 if (!service_name) {
1083 return NT_STATUS_NO_MEMORY;
1085 TALLOC_FREE(jucn->service_name);
1086 jucn->service_name = talloc_strdup(ctx, service_name);
1087 if (!jucn->service_name) {
1089 return NT_STATUS_NO_MEMORY;
1093 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(talloc_tos(), lp_sub, snum) == '\0')) {
1094 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
1096 pdp->servicename, dfs_path));
1098 return NT_STATUS_NOT_FOUND;
1102 * Self referrals are tested with a anonymous IPC connection and
1103 * a GET_DFS_REFERRAL call to \\server\share. (which means
1104 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
1105 * into the directory and will fail if it cannot (as the anonymous
1106 * user). Cope with this.
1109 if (pdp->reqpath[0] == '\0') {
1111 struct referral *ref;
1114 if (*lp_msdfs_proxy(talloc_tos(), lp_sub, snum) == '\0') {
1116 return self_ref(ctx,
1124 * It's an msdfs proxy share. Redirect to
1125 * the configured target share.
1128 tmp = talloc_asprintf(frame, "msdfs:%s",
1129 lp_msdfs_proxy(frame, lp_sub, snum));
1132 return NT_STATUS_NO_MEMORY;
1135 if (!parse_msdfs_symlink(ctx,
1136 lp_msdfs_shuffle_referrals(snum),
1141 return NT_STATUS_INVALID_PARAMETER;
1143 jucn->referral_count = refcount;
1144 jucn->referral_list = ref;
1145 *consumedcntp = strlen(dfs_path);
1147 return NT_STATUS_OK;
1150 status = create_conn_struct_tos_cwd(global_messaging_context(),
1152 lp_path(frame, lp_sub, snum),
1155 if (!NT_STATUS_IS_OK(status)) {
1164 * The remote and local address should be passed down to
1165 * create_conn_struct_cwd.
1167 if (conn->sconn->remote_address == NULL) {
1168 conn->sconn->remote_address =
1169 tsocket_address_copy(remote_address, conn->sconn);
1170 if (conn->sconn->remote_address == NULL) {
1172 return NT_STATUS_NO_MEMORY;
1175 if (conn->sconn->local_address == NULL) {
1176 conn->sconn->local_address =
1177 tsocket_address_copy(local_address, conn->sconn);
1178 if (conn->sconn->local_address == NULL) {
1180 return NT_STATUS_NO_MEMORY;
1184 /* If this is a DFS path dfs_lookup should return
1185 * NT_STATUS_PATH_NOT_COVERED. */
1187 status = dfs_path_lookup(ctx,
1193 &jucn->referral_list,
1194 &jucn->referral_count);
1196 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
1197 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
1199 if (NT_STATUS_IS_OK(status)) {
1201 * We are in an error path here (we
1202 * know it's not a DFS path), but
1203 * dfs_path_lookup() can return
1204 * NT_STATUS_OK. Ensure we always
1205 * return a valid error code.
1207 * #9588 - ACLs are not inherited to directories
1210 status = NT_STATUS_NOT_FOUND;
1215 status = NT_STATUS_OK;
1221 /******************************************************************
1222 Set up the DFS referral for the dfs pathname. This call returns
1223 the amount of the path covered by this server, and where the
1224 client should be redirected to. This is the meat of the
1225 TRANS2_GET_DFS_REFERRAL call.
1226 ******************************************************************/
1228 int setup_dfs_referral(connection_struct *orig_conn,
1229 const char *dfs_path,
1230 int max_referral_level,
1231 char **ppdata, NTSTATUS *pstatus)
1233 char *pdata = *ppdata;
1235 struct dfs_GetDFSReferral *r;
1236 DATA_BLOB blob = data_blob_null;
1238 enum ndr_err_code ndr_err;
1240 r = talloc_zero(talloc_tos(), struct dfs_GetDFSReferral);
1242 *pstatus = NT_STATUS_NO_MEMORY;
1246 r->in.req.max_referral_level = max_referral_level;
1247 r->in.req.servername = talloc_strdup(r, dfs_path);
1248 if (r->in.req.servername == NULL) {
1250 *pstatus = NT_STATUS_NO_MEMORY;
1254 status = SMB_VFS_GET_DFS_REFERRALS(orig_conn, r);
1255 if (!NT_STATUS_IS_OK(status)) {
1261 ndr_err = ndr_push_struct_blob(&blob, r,
1263 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1264 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1266 *pstatus = NT_STATUS_INVALID_PARAMETER;
1270 pdata = (char *)SMB_REALLOC(pdata, blob.length);
1273 DEBUG(0,("referral setup:"
1274 "malloc failed for Realloc!\n"));
1278 reply_size = blob.length;
1279 memcpy(pdata, blob.data, blob.length);
1282 *pstatus = NT_STATUS_OK;
1286 /**********************************************************************
1287 The following functions are called by the NETDFS RPC pipe functions
1288 **********************************************************************/
1290 /*********************************************************************
1291 Creates a junction structure from a DFS pathname
1292 **********************************************************************/
1294 bool create_junction(TALLOC_CTX *ctx,
1295 const char *dfs_path,
1296 bool allow_broken_path,
1297 struct junction_map *jucn)
1299 const struct loadparm_substitution *lp_sub =
1300 loadparm_s3_global_substitution();
1302 struct dfs_path *pdp = talloc(ctx,struct dfs_path);
1308 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path, pdp);
1309 if (!NT_STATUS_IS_OK(status)) {
1313 /* check if path is dfs : validate first token */
1314 if (!is_myname_or_ipaddr(pdp->hostname)) {
1315 DEBUG(4,("create_junction: Invalid hostname %s "
1317 pdp->hostname, dfs_path));
1322 /* Check for a non-DFS share */
1323 snum = lp_servicenumber(pdp->servicename);
1325 if(snum < 0 || !lp_msdfs_root(snum)) {
1326 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1332 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1333 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1334 jucn->comment = lp_comment(ctx, lp_sub, snum);
1337 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1343 /**********************************************************************
1344 Forms a valid Unix pathname from the junction
1345 **********************************************************************/
1347 static bool junction_to_local_path_tos(const struct junction_map *jucn,
1348 struct auth_session_info *session_info,
1350 connection_struct **conn_out)
1352 const struct loadparm_substitution *lp_sub =
1353 loadparm_s3_global_substitution();
1354 struct conn_struct_tos *c = NULL;
1356 char *path_out = NULL;
1359 snum = lp_servicenumber(jucn->service_name);
1363 status = create_conn_struct_tos_cwd(global_messaging_context(),
1365 lp_path(talloc_tos(), lp_sub, snum),
1368 if (!NT_STATUS_IS_OK(status)) {
1372 path_out = talloc_asprintf(c,
1374 lp_path(talloc_tos(), lp_sub, snum),
1376 if (path_out == NULL) {
1380 *pp_path_out = path_out;
1381 *conn_out = c->conn;
1386 * Create a msdfs string in Samba format we can store
1387 * in a filesystem object (currently a symlink).
1390 char *msdfs_link_string(TALLOC_CTX *ctx,
1391 const struct referral *reflist,
1392 size_t referral_count)
1394 char *refpath = NULL;
1395 bool insert_comma = false;
1396 char *msdfs_link = NULL;
1399 /* Form the msdfs_link contents */
1400 msdfs_link = talloc_strdup(ctx, "msdfs:");
1401 if (msdfs_link == NULL) {
1405 for( i= 0; i < referral_count; i++) {
1406 refpath = talloc_strdup(ctx, reflist[i].alternate_path);
1408 if (refpath == NULL) {
1412 /* Alternate paths always use Windows separators. */
1413 trim_char(refpath, '\\', '\\');
1414 if (*refpath == '\0') {
1416 insert_comma = false;
1420 if (i > 0 && insert_comma) {
1421 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1425 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1430 if (msdfs_link == NULL) {
1434 if (!insert_comma) {
1435 insert_comma = true;
1438 TALLOC_FREE(refpath);
1445 TALLOC_FREE(refpath);
1446 TALLOC_FREE(msdfs_link);
1450 bool create_msdfs_link(const struct junction_map *jucn,
1451 struct auth_session_info *session_info)
1453 TALLOC_CTX *frame = talloc_stackframe();
1455 connection_struct *conn;
1456 struct smb_filename *smb_fname = NULL;
1457 struct smb_filename *parent_fname = NULL;
1458 struct smb_filename *at_fname = NULL;
1463 ok = junction_to_local_path_tos(jucn, session_info, &path, &conn);
1468 if (!CAN_WRITE(conn)) {
1469 const struct loadparm_substitution *lp_sub =
1470 loadparm_s3_global_substitution();
1471 int snum = lp_servicenumber(jucn->service_name);
1473 DBG_WARNING("Can't create DFS entry on read-only share %s\n",
1474 lp_servicename(frame, lp_sub, snum));
1478 smb_fname = synthetic_smb_fname(frame,
1484 if (smb_fname == NULL) {
1488 status = parent_pathref(frame,
1493 if (!NT_STATUS_IS_OK(status)) {
1497 status = SMB_VFS_CREATE_DFS_PATHAT(conn,
1500 jucn->referral_list,
1501 jucn->referral_count);
1502 if (!NT_STATUS_IS_OK(status)) {
1503 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1504 int retval = SMB_VFS_UNLINKAT(conn,
1512 status = SMB_VFS_CREATE_DFS_PATHAT(conn,
1515 jucn->referral_list,
1516 jucn->referral_count);
1517 if (!NT_STATUS_IS_OK(status)) {
1518 DBG_WARNING("SMB_VFS_CREATE_DFS_PATHAT failed "
1533 bool remove_msdfs_link(const struct junction_map *jucn,
1534 struct auth_session_info *session_info)
1536 TALLOC_CTX *frame = talloc_stackframe();
1538 connection_struct *conn;
1540 struct smb_filename *smb_fname;
1541 struct smb_filename *parent_fname = NULL;
1542 struct smb_filename *at_fname = NULL;
1547 ok = junction_to_local_path_tos(jucn, session_info, &path, &conn);
1553 if (!CAN_WRITE(conn)) {
1554 const struct loadparm_substitution *lp_sub =
1555 loadparm_s3_global_substitution();
1556 int snum = lp_servicenumber(jucn->service_name);
1558 DBG_WARNING("Can't remove DFS entry on read-only share %s\n",
1559 lp_servicename(frame, lp_sub, snum));
1564 smb_fname = synthetic_smb_fname(frame,
1570 if (smb_fname == NULL) {
1576 status = parent_pathref(frame,
1581 if (!NT_STATUS_IS_OK(status)) {
1586 retval = SMB_VFS_UNLINKAT(conn,
1598 /*********************************************************************
1599 Return the number of DFS links at the root of this share.
1600 *********************************************************************/
1602 static size_t count_dfs_links(TALLOC_CTX *ctx,
1603 struct auth_session_info *session_info,
1606 TALLOC_CTX *frame = talloc_stackframe();
1607 const struct loadparm_substitution *lp_sub =
1608 loadparm_s3_global_substitution();
1610 const char *dname = NULL;
1611 char *talloced = NULL;
1612 const char *connect_path = lp_path(frame, lp_sub, snum);
1613 const char *msdfs_proxy = lp_msdfs_proxy(frame, lp_sub, snum);
1614 struct conn_struct_tos *c = NULL;
1615 connection_struct *conn = NULL;
1617 struct smb_filename *smb_fname = NULL;
1618 struct smb_Dir *dir_hnd = NULL;
1621 if(*connect_path == '\0') {
1627 * Fake up a connection struct for the VFS layer.
1630 status = create_conn_struct_tos_cwd(global_messaging_context(),
1635 if (!NT_STATUS_IS_OK(status)) {
1636 DEBUG(3, ("create_conn_struct failed: %s\n",
1637 nt_errstr(status)));
1643 /* Count a link for the msdfs root - convention */
1646 /* No more links if this is an msdfs proxy. */
1647 if (*msdfs_proxy != '\0') {
1651 smb_fname = synthetic_smb_fname(frame,
1657 if (smb_fname == NULL) {
1661 /* Now enumerate all dfs links */
1662 dir_hnd = OpenDir(frame, conn, smb_fname, NULL, 0);
1663 if (dir_hnd == NULL) {
1667 while ((dname = ReadDirName(dir_hnd, &offset, NULL, &talloced))
1670 struct smb_filename *smb_dname =
1671 synthetic_smb_fname(frame,
1677 if (smb_dname == NULL) {
1680 if (is_msdfs_link(dir_hnd_fetch_fsp(dir_hnd), smb_dname)) {
1681 if (cnt + 1 < cnt) {
1687 TALLOC_FREE(talloced);
1688 TALLOC_FREE(smb_dname);
1696 /*********************************************************************
1697 *********************************************************************/
1699 static int form_junctions(TALLOC_CTX *ctx,
1700 struct auth_session_info *session_info,
1702 struct junction_map *jucn,
1705 TALLOC_CTX *frame = talloc_stackframe();
1706 const struct loadparm_substitution *lp_sub =
1707 loadparm_s3_global_substitution();
1709 const char *dname = NULL;
1710 char *talloced = NULL;
1711 const char *connect_path = lp_path(frame, lp_sub, snum);
1712 char *service_name = lp_servicename(frame, lp_sub, snum);
1713 const char *msdfs_proxy = lp_msdfs_proxy(frame, lp_sub, snum);
1714 struct conn_struct_tos *c = NULL;
1715 connection_struct *conn = NULL;
1716 struct referral *ref = NULL;
1717 struct smb_filename *smb_fname = NULL;
1718 struct smb_Dir *dir_hnd = NULL;
1722 if (jn_remain == 0) {
1727 if(*connect_path == '\0') {
1733 * Fake up a connection struct for the VFS layer.
1736 status = create_conn_struct_tos_cwd(global_messaging_context(),
1741 if (!NT_STATUS_IS_OK(status)) {
1742 DEBUG(3, ("create_conn_struct failed: %s\n",
1743 nt_errstr(status)));
1749 /* form a junction for the msdfs root - convention
1750 DO NOT REMOVE THIS: NT clients will not work with us
1751 if this is not present
1753 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1754 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1755 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1758 jucn[cnt].comment = "";
1759 jucn[cnt].referral_count = 1;
1761 ref = jucn[cnt].referral_list = talloc_zero(ctx, struct referral);
1762 if (jucn[cnt].referral_list == NULL) {
1767 ref->ttl = REFERRAL_TTL;
1768 if (*msdfs_proxy != '\0') {
1769 ref->alternate_path = talloc_strdup(ctx,
1772 ref->alternate_path = talloc_asprintf(ctx,
1774 get_local_machine_name(),
1778 if (!ref->alternate_path) {
1783 /* Don't enumerate if we're an msdfs proxy. */
1784 if (*msdfs_proxy != '\0') {
1788 smb_fname = synthetic_smb_fname(frame,
1794 if (smb_fname == NULL) {
1798 /* Now enumerate all dfs links */
1799 dir_hnd = OpenDir(frame, conn, smb_fname, NULL, 0);
1800 if (dir_hnd == NULL) {
1804 while ((dname = ReadDirName(dir_hnd, &offset, NULL, &talloced))
1807 struct smb_filename *smb_dname = NULL;
1809 if (cnt >= jn_remain) {
1810 DEBUG(2, ("form_junctions: ran out of MSDFS "
1812 TALLOC_FREE(talloced);
1815 smb_dname = synthetic_smb_fname(talloc_tos(),
1821 if (smb_dname == NULL) {
1822 TALLOC_FREE(talloced);
1826 status = SMB_VFS_READ_DFS_PATHAT(conn,
1830 &jucn[cnt].referral_list,
1831 &jucn[cnt].referral_count);
1833 if (NT_STATUS_IS_OK(status)) {
1834 jucn[cnt].service_name = talloc_strdup(ctx,
1836 jucn[cnt].volume_name = talloc_strdup(ctx, dname);
1837 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1838 TALLOC_FREE(talloced);
1841 jucn[cnt].comment = "";
1844 TALLOC_FREE(talloced);
1845 TALLOC_FREE(smb_dname);
1853 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx,
1854 struct auth_session_info *session_info,
1857 struct junction_map *jn = NULL;
1859 size_t jn_count = 0;
1863 if(!lp_host_msdfs()) {
1867 /* Ensure all the usershares are loaded. */
1869 load_registry_shares();
1870 sharecount = load_usershare_shares(NULL, connections_snum_used);
1873 for(i=0;i < sharecount;i++) {
1874 if(lp_msdfs_root(i)) {
1875 jn_count += count_dfs_links(ctx, session_info, i);
1878 if (jn_count == 0) {
1881 jn = talloc_array(ctx, struct junction_map, jn_count);
1885 for(i=0; i < sharecount; i++) {
1886 if (*p_num_jn >= jn_count) {
1889 if(lp_msdfs_root(i)) {
1890 *p_num_jn += form_junctions(ctx,
1894 jn_count - *p_num_jn);