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"
35 /**********************************************************************
36 Parse a DFS pathname of the form \hostname\service\reqpath
37 into the dfs_path structure.
38 If POSIX pathnames is true, the pathname may also be of the
39 form /hostname/service/reqpath.
40 We cope with either here.
42 Unfortunately, due to broken clients who might set the
43 SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
44 send a local path, we have to cope with that too....
46 If conn != NULL then ensure the provided service is
47 the one pointed to by the connection.
49 This version does everything using pointers within one copy of the
50 pathname string, talloced on the struct dfs_path pointer (which
51 must be talloced). This may be too clever to live....
53 **********************************************************************/
55 static NTSTATUS parse_dfs_path(connection_struct *conn,
58 bool allow_broken_path,
59 struct dfs_path *pdp, /* MUST BE TALLOCED */
60 bool *ppath_contains_wcard)
66 NTSTATUS status = NT_STATUS_OK;
72 * This is the only talloc we should need to do
73 * on the struct dfs_path. All the pointers inside
74 * it should point to offsets within this string.
77 pathname_local = talloc_strdup(pdp, pathname);
78 if (!pathname_local) {
79 return NT_STATUS_NO_MEMORY;
81 /* Get a pointer to the terminating '\0' */
82 eos_ptr = &pathname_local[strlen(pathname_local)];
83 p = temp = pathname_local;
86 * Non-broken DFS paths *must* start with the
87 * path separator. For Windows this is always '\\',
88 * for posix paths this is always '/'.
91 if (*pathname == '/') {
92 pdp->posix_path = true;
95 pdp->posix_path = false;
99 if (allow_broken_path && (*pathname != sepchar)) {
100 DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
101 pathname, sepchar ));
103 * Possibly client sent a local path by mistake.
104 * Try and convert to a local path.
105 * Note that this is an SMB1-only fallback
106 * to cope with known broken SMB1 clients.
109 pdp->hostname = eos_ptr; /* "" */
110 pdp->servicename = eos_ptr; /* "" */
112 /* We've got no info about separators. */
113 pdp->posix_path = lp_posix_pathnames();
115 DEBUG(10,("parse_dfs_path: trying to convert %s to a "
122 * Safe to use on talloc'ed string as it only shrinks.
123 * It also doesn't affect the eos_ptr.
125 trim_char(temp,sepchar,sepchar);
127 DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
131 /* Parse out hostname. */
132 p = strchr_m(temp,sepchar);
134 DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
137 * Possibly client sent a local path by mistake.
138 * Try and convert to a local path.
141 pdp->hostname = eos_ptr; /* "" */
142 pdp->servicename = eos_ptr; /* "" */
145 DEBUG(10,("parse_dfs_path: trying to convert %s "
151 pdp->hostname = temp;
153 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
155 /* Parse out servicename. */
157 p = strchr_m(servicename,sepchar);
162 /* Is this really our servicename ? */
163 if (conn && !( strequal(servicename, lp_servicename(talloc_tos(), SNUM(conn)))
164 || (strequal(servicename, HOMES_NAME)
165 && strequal(lp_servicename(talloc_tos(), SNUM(conn)),
166 get_current_username()) )) ) {
167 DEBUG(10,("parse_dfs_path: %s is not our servicename\n",
171 * Possibly client sent a local path by mistake.
172 * Try and convert to a local path.
175 pdp->hostname = eos_ptr; /* "" */
176 pdp->servicename = eos_ptr; /* "" */
178 /* Repair the path - replace the sepchar's
181 *servicename = sepchar;
187 DEBUG(10,("parse_dfs_path: trying to convert %s "
193 pdp->servicename = servicename;
195 DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
198 /* Client sent self referral \server\share. */
199 pdp->reqpath = eos_ptr; /* "" */
207 *ppath_contains_wcard = False;
211 /* Rest is reqpath. */
212 if (pdp->posix_path) {
213 status = check_path_syntax_posix(pdp->reqpath);
216 status = check_path_syntax_wcard(pdp->reqpath,
217 ppath_contains_wcard);
219 status = check_path_syntax(pdp->reqpath);
223 if (!NT_STATUS_IS_OK(status)) {
224 DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
225 p, nt_errstr(status) ));
229 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
233 /********************************************************
234 Fake up a connection struct for the VFS layer, for use in
235 applications (such as the python bindings), that do not want the
236 global working directory changed under them.
238 SMB_VFS_CONNECT requires root privileges.
239 *********************************************************/
241 static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx,
242 struct tevent_context *ev,
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;
261 sconn->msg_ctx = msg;
263 conn = conn_new(sconn);
266 return NT_STATUS_NO_MEMORY;
269 /* Now we have conn, we need to make sconn a child of conn,
270 * for a proper talloc tree */
271 talloc_steal(conn, sconn);
273 if (snum == -1 && servicename == NULL) {
274 servicename = "Unknown Service (snum == -1)";
277 connpath = talloc_strdup(conn, path);
280 return NT_STATUS_NO_MEMORY;
282 connpath = talloc_string_sub(conn,
288 return NT_STATUS_NO_MEMORY;
291 /* needed for smbd_vfs_init() */
293 conn->params->service = snum;
294 conn->cnum = TID_FIELD_INVALID;
296 if (session_info != NULL) {
297 conn->session_info = copy_session_info(conn, session_info);
298 if (conn->session_info == NULL) {
299 DEBUG(0, ("copy_serverinfo failed\n"));
301 return NT_STATUS_NO_MEMORY;
303 vfs_user = conn->session_info->unix_info->unix_name;
305 /* use current authenticated user in absence of session_info */
306 vfs_user = get_current_username();
309 set_conn_connectpath(conn, connpath);
312 * New code to check if there's a share security descriptor
313 * added from NT server manager. This is done after the
314 * smb.conf checks are done as we need a uid and token. JRA.
317 if (conn->session_info) {
318 share_access_check(conn->session_info->security_token,
320 MAXIMUM_ALLOWED_ACCESS,
321 &conn->share_access);
323 if ((conn->share_access & FILE_WRITE_DATA) == 0) {
324 if ((conn->share_access & FILE_READ_DATA) == 0) {
325 /* No access, read or write. */
326 DEBUG(3,("create_conn_struct: connection to %s "
327 "denied due to security "
331 return NT_STATUS_ACCESS_DENIED;
333 conn->read_only = true;
337 conn->share_access = 0;
338 conn->read_only = true;
341 if (!smbd_vfs_init(conn)) {
342 NTSTATUS status = map_nt_error_from_unix(errno);
343 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
348 /* this must be the first filesystem operation that we do */
349 if (SMB_VFS_CONNECT(conn, servicename, vfs_user) < 0) {
350 DEBUG(0,("VFS connect failed!\n"));
352 return NT_STATUS_UNSUCCESSFUL;
355 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
361 /********************************************************
362 Fake up a connection struct for the VFS layer, for use in
363 applications (such as the python bindings), that do not want the
364 global working directory changed under them.
366 SMB_VFS_CONNECT requires root privileges.
367 *********************************************************/
369 NTSTATUS create_conn_struct(TALLOC_CTX *ctx,
370 struct tevent_context *ev,
371 struct messaging_context *msg,
372 connection_struct **pconn,
375 const struct auth_session_info *session_info)
379 status = create_conn_struct_as_root(ctx, ev,
388 /********************************************************
389 Fake up a connection struct for the VFS layer.
390 Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
392 The old working directory is returned on *poldcwd, allocated on ctx.
393 *********************************************************/
395 NTSTATUS create_conn_struct_cwd(TALLOC_CTX *ctx,
396 struct tevent_context *ev,
397 struct messaging_context *msg,
398 connection_struct **pconn,
401 const struct auth_session_info *session_info,
404 connection_struct *conn;
407 NTSTATUS status = create_conn_struct(ctx, ev,
411 if (!NT_STATUS_IS_OK(status)) {
416 * Windows seems to insist on doing trans2getdfsreferral() calls on
417 * the IPC$ share as the anonymous user. If we try to chdir as that
418 * user we will fail.... WTF ? JRA.
421 oldcwd = vfs_GetWd(ctx, conn);
422 if (oldcwd == NULL) {
423 status = map_nt_error_from_unix(errno);
424 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
429 if (vfs_ChDir(conn,conn->connectpath) != 0) {
430 status = map_nt_error_from_unix(errno);
431 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
433 conn->connectpath, strerror(errno) ));
444 static void shuffle_strlist(char **list, int count)
450 for (i = count; i > 1; i--) {
451 r = generate_random() % i;
459 /**********************************************************************
460 Parse the contents of a symlink to verify if it is an msdfs referral
461 A valid referral is of the form:
463 msdfs:server1\share1,server2\share2
464 msdfs:server1\share1\pathname,server2\share2\pathname
465 msdfs:server1/share1,server2/share2
466 msdfs:server1/share1/pathname,server2/share2/pathname.
468 Note that the alternate paths returned here must be of the canonicalized
472 \server\share\path\to\file,
474 even in posix path mode. This is because we have no knowledge if the
475 server we're referring to understands posix paths.
476 **********************************************************************/
478 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
481 struct referral **preflist,
486 char **alt_path = NULL;
488 struct referral *reflist;
491 temp = talloc_strdup(ctx, target);
495 prot = strtok_r(temp, ":", &saveptr);
497 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
501 alt_path = talloc_array(ctx, char *, MAX_REFERRAL_COUNT);
506 /* parse out the alternate paths */
507 while((count<MAX_REFERRAL_COUNT) &&
508 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
512 /* shuffle alternate paths */
513 if (lp_msdfs_shuffle_referrals(snum)) {
514 shuffle_strlist(alt_path, count);
517 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
520 reflist = *preflist = talloc_zero_array(ctx,
521 struct referral, count);
522 if(reflist == NULL) {
523 TALLOC_FREE(alt_path);
527 reflist = *preflist = NULL;
530 for(i=0;i<count;i++) {
533 /* Canonicalize link target.
534 * Replace all /'s in the path by a \ */
535 string_replace(alt_path[i], '/', '\\');
537 /* Remove leading '\\'s */
539 while (*p && (*p == '\\')) {
543 reflist[i].alternate_path = talloc_asprintf(ctx,
546 if (!reflist[i].alternate_path) {
550 reflist[i].proximity = 0;
551 reflist[i].ttl = REFERRAL_TTL;
552 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
553 reflist[i].alternate_path));
558 TALLOC_FREE(alt_path);
562 /**********************************************************************
563 Returns true if the unix path is a valid msdfs symlink and also
564 returns the target string from inside the link.
565 **********************************************************************/
567 static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
568 connection_struct *conn,
570 char **pp_link_target,
571 SMB_STRUCT_STAT *sbufp)
573 int referral_len = 0;
574 #if defined(HAVE_BROKEN_READLINK)
575 char link_target_buf[PATH_MAX];
577 char link_target_buf[7];
580 char *link_target = NULL;
581 struct smb_filename smb_fname;
583 if (pp_link_target) {
585 link_target = talloc_array(ctx, char, bufsize);
589 *pp_link_target = link_target;
591 bufsize = sizeof(link_target_buf);
592 link_target = link_target_buf;
595 ZERO_STRUCT(smb_fname);
596 smb_fname.base_name = discard_const_p(char, path);
598 if (SMB_VFS_LSTAT(conn, &smb_fname) != 0) {
599 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
603 if (!S_ISLNK(smb_fname.st.st_ex_mode)) {
604 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
609 *sbufp = smb_fname.st;
612 referral_len = SMB_VFS_READLINK(conn, path, link_target, bufsize - 1);
613 if (referral_len == -1) {
614 DEBUG(0,("is_msdfs_link_read_target: Error reading "
615 "msdfs link %s: %s\n",
616 path, strerror(errno)));
619 link_target[referral_len] = '\0';
621 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path,
624 if (!strnequal(link_target, "msdfs:", 6)) {
631 if (link_target != link_target_buf) {
632 TALLOC_FREE(link_target);
637 /**********************************************************************
638 Returns true if the unix path is a valid msdfs symlink.
639 **********************************************************************/
641 bool is_msdfs_link(connection_struct *conn,
643 SMB_STRUCT_STAT *sbufp)
645 return is_msdfs_link_internal(talloc_tos(),
652 /*****************************************************************
653 Used by other functions to decide if a dfs path is remote,
654 and to get the list of referred locations for that remote path.
656 search_flag: For findfirsts, dfs links themselves are not
657 redirected, but paths beyond the links are. For normal smb calls,
658 even dfs links need to be redirected.
660 consumedcntp: how much of the dfs path is being redirected. the client
661 should try the remaining path on the redirected server.
663 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
664 link redirect are in targetpath.
665 *****************************************************************/
667 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
668 connection_struct *conn,
669 const char *dfspath, /* Incoming complete dfs path */
670 const struct dfs_path *pdp, /* Parsed out
671 server+share+extrapath. */
672 bool search_flag, /* Called from a findfirst ? */
674 char **pp_targetpath)
679 struct smb_filename *smb_fname = NULL;
680 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
683 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
684 conn->connectpath, pdp->reqpath));
687 * Note the unix path conversion here we're doing we
688 * throw away. We're looking for a symlink for a dfs
689 * resolution, if we don't find it we'll do another
690 * unix_convert later in the codepath.
693 status = unix_convert(ctx, conn, pdp->reqpath, &smb_fname,
694 search_flag ? UCF_ALWAYS_ALLOW_WCARD_LCOMP : 0);
696 if (!NT_STATUS_IS_OK(status)) {
697 if (!NT_STATUS_EQUAL(status,
698 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
701 if (smb_fname == NULL || smb_fname->base_name == NULL) {
706 /* Optimization - check if we can redirect the whole path. */
708 if (is_msdfs_link_internal(ctx, conn, smb_fname->base_name,
709 pp_targetpath, NULL)) {
711 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
712 "for dfs link %s.\n", dfspath));
713 status = NT_STATUS_OK;
717 DEBUG(6,("dfs_path_lookup: %s resolves to a "
718 "valid dfs link %s.\n", dfspath,
719 pp_targetpath ? *pp_targetpath : ""));
722 *consumedcntp = strlen(dfspath);
724 status = NT_STATUS_PATH_NOT_COVERED;
728 /* Prepare to test only for '/' components in the given path,
729 * so if a Windows path replace all '\\' characters with '/'.
730 * For a POSIX DFS path we know all separators are already '/'. */
732 canon_dfspath = talloc_strdup(ctx, dfspath);
733 if (!canon_dfspath) {
734 status = NT_STATUS_NO_MEMORY;
737 if (!pdp->posix_path) {
738 string_replace(canon_dfspath, '\\', '/');
742 * localpath comes out of unix_convert, so it has
743 * no trailing backslash. Make sure that canon_dfspath hasn't either.
744 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
747 trim_char(canon_dfspath,0,'/');
750 * Redirect if any component in the path is a link.
751 * We do this by walking backwards through the
752 * local path, chopping off the last component
753 * in both the local path and the canonicalized
754 * DFS path. If we hit a DFS link then we're done.
757 p = strrchr_m(smb_fname->base_name, '/');
759 q = strrchr_m(canon_dfspath, '/');
768 if (is_msdfs_link_internal(ctx, conn,
769 smb_fname->base_name, pp_targetpath,
771 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
772 "parent %s is dfs link\n", dfspath,
773 smb_fname_str_dbg(smb_fname)));
776 *consumedcntp = strlen(canon_dfspath);
777 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
783 status = NT_STATUS_PATH_NOT_COVERED;
787 /* Step back on the filesystem. */
788 p = strrchr_m(smb_fname->base_name, '/');
791 /* And in the canonicalized dfs path. */
792 q = strrchr_m(canon_dfspath, '/');
796 status = NT_STATUS_OK;
798 TALLOC_FREE(smb_fname);
802 /*****************************************************************
803 Decides if a dfs pathname should be redirected or not.
804 If not, the pathname is converted to a tcon-relative local unix path
806 search_wcard_flag: this flag performs 2 functions both related
807 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
810 This function can return NT_STATUS_OK, meaning use the returned path as-is
811 (mapped into a local path).
812 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
813 any other NT_STATUS error which is a genuine error to be
814 returned to the client.
815 *****************************************************************/
817 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
818 connection_struct *conn,
821 bool allow_broken_path,
823 bool *ppath_contains_wcard)
826 bool search_wcard_flag = (ucf_flags &
827 (UCF_COND_ALLOW_WCARD_LCOMP|UCF_ALWAYS_ALLOW_WCARD_LCOMP));
828 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
831 return NT_STATUS_NO_MEMORY;
834 status = parse_dfs_path(conn, path_in, search_wcard_flag,
835 allow_broken_path, pdp,
836 ppath_contains_wcard);
837 if (!NT_STATUS_IS_OK(status)) {
842 if (pdp->reqpath[0] == '\0') {
844 *pp_path_out = talloc_strdup(ctx, "");
846 return NT_STATUS_NO_MEMORY;
848 DEBUG(5,("dfs_redirect: self-referral.\n"));
852 /* If dfs pathname for a non-dfs share, convert to tcon-relative
853 path and return OK */
855 if (!lp_msdfs_root(SNUM(conn))) {
856 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
859 return NT_STATUS_NO_MEMORY;
864 /* If it looked like a local path (zero hostname/servicename)
865 * just treat as a tcon-relative path. */
867 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
868 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
871 return NT_STATUS_NO_MEMORY;
876 if (!( strequal(pdp->servicename, lp_servicename(talloc_tos(), SNUM(conn)))
877 || (strequal(pdp->servicename, HOMES_NAME)
878 && strequal(lp_servicename(talloc_tos(), SNUM(conn)),
879 conn->session_info->unix_info->sanitized_username) )) ) {
881 /* The given sharename doesn't match this connection. */
884 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
887 status = dfs_path_lookup(ctx, conn, path_in, pdp,
888 search_wcard_flag, NULL, NULL);
889 if (!NT_STATUS_IS_OK(status)) {
890 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
891 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
893 DEBUG(10,("dfs_redirect: dfs_path_lookup "
894 "failed for %s with %s\n",
895 path_in, nt_errstr(status) ));
900 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
902 /* Form non-dfs tcon-relative path */
903 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
906 return NT_STATUS_NO_MEMORY;
909 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
916 /**********************************************************************
917 Return a self referral.
918 **********************************************************************/
920 static NTSTATUS self_ref(TALLOC_CTX *ctx,
921 const char *dfs_path,
922 struct junction_map *jucn,
924 bool *self_referralp)
926 struct referral *ref;
928 *self_referralp = True;
930 jucn->referral_count = 1;
931 if((ref = talloc_zero(ctx, struct referral)) == NULL) {
932 return NT_STATUS_NO_MEMORY;
935 ref->alternate_path = talloc_strdup(ctx, dfs_path);
936 if (!ref->alternate_path) {
938 return NT_STATUS_NO_MEMORY;
941 ref->ttl = REFERRAL_TTL;
942 jucn->referral_list = ref;
943 *consumedcntp = strlen(dfs_path);
947 /**********************************************************************
948 Gets valid referrals for a dfs path and fills up the
949 junction_map structure.
950 **********************************************************************/
952 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
953 const char *dfs_path,
954 bool allow_broken_path,
955 struct junction_map *jucn,
957 bool *self_referralp)
959 struct connection_struct *conn;
960 char *targetpath = NULL;
962 NTSTATUS status = NT_STATUS_NOT_FOUND;
964 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
968 return NT_STATUS_NO_MEMORY;
971 *self_referralp = False;
973 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
975 if (!NT_STATUS_IS_OK(status)) {
979 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
980 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
981 if (!jucn->service_name || !jucn->volume_name) {
983 return NT_STATUS_NO_MEMORY;
986 /* Verify the share is a dfs root */
987 snum = lp_servicenumber(jucn->service_name);
989 char *service_name = NULL;
990 if ((snum = find_service(ctx, jucn->service_name, &service_name)) < 0) {
991 return NT_STATUS_NOT_FOUND;
994 return NT_STATUS_NO_MEMORY;
996 TALLOC_FREE(jucn->service_name);
997 jucn->service_name = talloc_strdup(ctx, service_name);
998 if (!jucn->service_name) {
1000 return NT_STATUS_NO_MEMORY;
1004 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(talloc_tos(), snum) == '\0')) {
1005 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
1007 pdp->servicename, dfs_path));
1009 return NT_STATUS_NOT_FOUND;
1013 * Self referrals are tested with a anonymous IPC connection and
1014 * a GET_DFS_REFERRAL call to \\server\share. (which means
1015 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
1016 * into the directory and will fail if it cannot (as the anonymous
1017 * user). Cope with this.
1020 if (pdp->reqpath[0] == '\0') {
1022 struct referral *ref;
1025 if (*lp_msdfs_proxy(talloc_tos(), snum) == '\0') {
1027 return self_ref(ctx,
1035 * It's an msdfs proxy share. Redirect to
1036 * the configured target share.
1039 tmp = talloc_asprintf(talloc_tos(), "msdfs:%s",
1040 lp_msdfs_proxy(talloc_tos(), snum));
1043 return NT_STATUS_NO_MEMORY;
1046 if (!parse_msdfs_symlink(ctx, snum, tmp, &ref, &refcount)) {
1049 return NT_STATUS_INVALID_PARAMETER;
1052 jucn->referral_count = refcount;
1053 jucn->referral_list = ref;
1054 *consumedcntp = strlen(dfs_path);
1056 return NT_STATUS_OK;
1059 status = create_conn_struct_cwd(ctx,
1060 server_event_context(),
1061 server_messaging_context(),
1063 lp_path(talloc_tos(), snum), NULL, &oldpath);
1064 if (!NT_STATUS_IS_OK(status)) {
1069 /* If this is a DFS path dfs_lookup should return
1070 * NT_STATUS_PATH_NOT_COVERED. */
1072 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
1073 False, consumedcntp, &targetpath);
1075 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
1076 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
1078 if (NT_STATUS_IS_OK(status)) {
1080 * We are in an error path here (we
1081 * know it's not a DFS path), but
1082 * dfs_path_lookup() can return
1083 * NT_STATUS_OK. Ensure we always
1084 * return a valid error code.
1086 * #9588 - ACLs are not inherited to directories
1089 status = NT_STATUS_NOT_FOUND;
1094 /* We know this is a valid dfs link. Parse the targetpath. */
1095 if (!parse_msdfs_symlink(ctx, snum, targetpath,
1096 &jucn->referral_list,
1097 &jucn->referral_count)) {
1098 DEBUG(3,("get_referred_path: failed to parse symlink "
1099 "target %s\n", targetpath ));
1100 status = NT_STATUS_NOT_FOUND;
1104 status = NT_STATUS_OK;
1106 vfs_ChDir(conn, oldpath);
1107 SMB_VFS_DISCONNECT(conn);
1113 /******************************************************************
1114 Set up the DFS referral for the dfs pathname. This call returns
1115 the amount of the path covered by this server, and where the
1116 client should be redirected to. This is the meat of the
1117 TRANS2_GET_DFS_REFERRAL call.
1118 ******************************************************************/
1120 int setup_dfs_referral(connection_struct *orig_conn,
1121 const char *dfs_path,
1122 int max_referral_level,
1123 char **ppdata, NTSTATUS *pstatus)
1125 char *pdata = *ppdata;
1127 struct dfs_GetDFSReferral *r;
1128 DATA_BLOB blob = data_blob_null;
1130 enum ndr_err_code ndr_err;
1132 r = talloc_zero(talloc_tos(), struct dfs_GetDFSReferral);
1134 *pstatus = NT_STATUS_NO_MEMORY;
1138 r->in.req.max_referral_level = max_referral_level;
1139 r->in.req.servername = talloc_strdup(r, dfs_path);
1140 if (r->in.req.servername == NULL) {
1142 *pstatus = NT_STATUS_NO_MEMORY;
1146 status = SMB_VFS_GET_DFS_REFERRALS(orig_conn, r);
1147 if (!NT_STATUS_IS_OK(status)) {
1153 ndr_err = ndr_push_struct_blob(&blob, r,
1155 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1156 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1158 *pstatus = NT_STATUS_INVALID_PARAMETER;
1162 pdata = (char *)SMB_REALLOC(pdata, blob.length);
1165 DEBUG(0,("referral setup:"
1166 "malloc failed for Realloc!\n"));
1170 reply_size = blob.length;
1171 memcpy(pdata, blob.data, blob.length);
1174 *pstatus = NT_STATUS_OK;
1178 /**********************************************************************
1179 The following functions are called by the NETDFS RPC pipe functions
1180 **********************************************************************/
1182 /*********************************************************************
1183 Creates a junction structure from a DFS pathname
1184 **********************************************************************/
1186 bool create_junction(TALLOC_CTX *ctx,
1187 const char *dfs_path,
1188 bool allow_broken_path,
1189 struct junction_map *jucn)
1193 struct dfs_path *pdp = talloc(ctx,struct dfs_path);
1199 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1201 if (!NT_STATUS_IS_OK(status)) {
1205 /* check if path is dfs : validate first token */
1206 if (!is_myname_or_ipaddr(pdp->hostname)) {
1207 DEBUG(4,("create_junction: Invalid hostname %s "
1209 pdp->hostname, dfs_path));
1214 /* Check for a non-DFS share */
1215 snum = lp_servicenumber(pdp->servicename);
1217 if(snum < 0 || !lp_msdfs_root(snum)) {
1218 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1224 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1225 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1226 jucn->comment = lp_comment(ctx, snum);
1229 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1235 /**********************************************************************
1236 Forms a valid Unix pathname from the junction
1237 **********************************************************************/
1239 static bool junction_to_local_path(const struct junction_map *jucn,
1241 connection_struct **conn_out,
1247 snum = lp_servicenumber(jucn->service_name);
1251 status = create_conn_struct_cwd(talloc_tos(),
1252 server_event_context(),
1253 server_messaging_context(),
1255 snum, lp_path(talloc_tos(), snum), NULL, oldpath);
1256 if (!NT_STATUS_IS_OK(status)) {
1260 *pp_path_out = talloc_asprintf(*conn_out,
1262 lp_path(talloc_tos(), snum),
1264 if (!*pp_path_out) {
1265 vfs_ChDir(*conn_out, *oldpath);
1266 SMB_VFS_DISCONNECT(*conn_out);
1267 conn_free(*conn_out);
1273 bool create_msdfs_link(const struct junction_map *jucn)
1277 char *msdfs_link = NULL;
1278 connection_struct *conn;
1280 bool insert_comma = False;
1283 if(!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1287 /* Form the msdfs_link contents */
1288 msdfs_link = talloc_strdup(conn, "msdfs:");
1292 for(i=0; i<jucn->referral_count; i++) {
1293 char *refpath = jucn->referral_list[i].alternate_path;
1295 /* Alternate paths always use Windows separators. */
1296 trim_char(refpath, '\\', '\\');
1297 if(*refpath == '\0') {
1299 insert_comma = False;
1303 if (i > 0 && insert_comma) {
1304 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1308 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1316 if (!insert_comma) {
1317 insert_comma = True;
1321 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1324 if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1325 if (errno == EEXIST) {
1326 struct smb_filename *smb_fname;
1328 smb_fname = synthetic_smb_fname(talloc_tos(),
1333 if (smb_fname == NULL) {
1338 if(SMB_VFS_UNLINK(conn, smb_fname)!=0) {
1339 TALLOC_FREE(smb_fname);
1342 TALLOC_FREE(smb_fname);
1344 if (SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1345 DEBUG(1,("create_msdfs_link: symlink failed "
1346 "%s -> %s\nError: %s\n",
1347 path, msdfs_link, strerror(errno)));
1355 vfs_ChDir(conn, cwd);
1356 SMB_VFS_DISCONNECT(conn);
1361 bool remove_msdfs_link(const struct junction_map *jucn)
1365 connection_struct *conn;
1367 struct smb_filename *smb_fname;
1369 if (!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1373 smb_fname = synthetic_smb_fname(talloc_tos(),
1378 if (smb_fname == NULL) {
1383 if( SMB_VFS_UNLINK(conn, smb_fname) == 0 ) {
1387 TALLOC_FREE(smb_fname);
1388 vfs_ChDir(conn, cwd);
1389 SMB_VFS_DISCONNECT(conn);
1394 /*********************************************************************
1395 Return the number of DFS links at the root of this share.
1396 *********************************************************************/
1398 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1402 const char *dname = NULL;
1403 char *talloced = NULL;
1404 const char *connect_path = lp_path(talloc_tos(), snum);
1405 const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum);
1406 connection_struct *conn;
1409 struct smb_filename *smb_fname = NULL;
1411 if(*connect_path == '\0') {
1416 * Fake up a connection struct for the VFS layer.
1419 status = create_conn_struct_cwd(talloc_tos(),
1420 server_event_context(),
1421 server_messaging_context(),
1423 snum, connect_path, NULL, &cwd);
1424 if (!NT_STATUS_IS_OK(status)) {
1425 DEBUG(3, ("create_conn_struct failed: %s\n",
1426 nt_errstr(status)));
1430 /* Count a link for the msdfs root - convention */
1433 /* No more links if this is an msdfs proxy. */
1434 if (*msdfs_proxy != '\0') {
1438 smb_fname = synthetic_smb_fname(talloc_tos(),
1443 if (smb_fname == NULL) {
1447 /* Now enumerate all dfs links */
1448 dirp = SMB_VFS_OPENDIR(conn, smb_fname, NULL, 0);
1453 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1455 if (is_msdfs_link(conn,
1460 TALLOC_FREE(talloced);
1463 SMB_VFS_CLOSEDIR(conn,dirp);
1466 TALLOC_FREE(smb_fname);
1467 vfs_ChDir(conn, cwd);
1468 SMB_VFS_DISCONNECT(conn);
1473 /*********************************************************************
1474 *********************************************************************/
1476 static int form_junctions(TALLOC_CTX *ctx,
1478 struct junction_map *jucn,
1483 const char *dname = NULL;
1484 char *talloced = NULL;
1485 const char *connect_path = lp_path(talloc_tos(), snum);
1486 char *service_name = lp_servicename(talloc_tos(), snum);
1487 const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum);
1488 connection_struct *conn;
1489 struct referral *ref = NULL;
1491 struct smb_filename *smb_fname = NULL;
1494 if (jn_remain == 0) {
1498 if(*connect_path == '\0') {
1503 * Fake up a connection struct for the VFS layer.
1506 status = create_conn_struct_cwd(ctx,
1507 server_event_context(),
1508 server_messaging_context(),
1509 &conn, snum, connect_path, NULL,
1511 if (!NT_STATUS_IS_OK(status)) {
1512 DEBUG(3, ("create_conn_struct failed: %s\n",
1513 nt_errstr(status)));
1517 /* form a junction for the msdfs root - convention
1518 DO NOT REMOVE THIS: NT clients will not work with us
1519 if this is not present
1521 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1522 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1523 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1526 jucn[cnt].comment = "";
1527 jucn[cnt].referral_count = 1;
1529 ref = jucn[cnt].referral_list = talloc_zero(ctx, struct referral);
1530 if (jucn[cnt].referral_list == NULL) {
1535 ref->ttl = REFERRAL_TTL;
1536 if (*msdfs_proxy != '\0') {
1537 ref->alternate_path = talloc_strdup(ctx,
1540 ref->alternate_path = talloc_asprintf(ctx,
1542 get_local_machine_name(),
1546 if (!ref->alternate_path) {
1551 /* Don't enumerate if we're an msdfs proxy. */
1552 if (*msdfs_proxy != '\0') {
1556 smb_fname = synthetic_smb_fname(talloc_tos(),
1561 if (smb_fname == NULL) {
1565 /* Now enumerate all dfs links */
1566 dirp = SMB_VFS_OPENDIR(conn, smb_fname, NULL, 0);
1571 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1573 char *link_target = NULL;
1574 if (cnt >= jn_remain) {
1575 DEBUG(2, ("form_junctions: ran out of MSDFS "
1577 TALLOC_FREE(talloced);
1580 if (is_msdfs_link_internal(ctx,
1582 dname, &link_target,
1584 if (parse_msdfs_symlink(ctx, snum,
1586 &jucn[cnt].referral_list,
1587 &jucn[cnt].referral_count)) {
1589 jucn[cnt].service_name = talloc_strdup(ctx,
1591 jucn[cnt].volume_name = talloc_strdup(ctx,
1593 if (!jucn[cnt].service_name ||
1594 !jucn[cnt].volume_name) {
1595 TALLOC_FREE(talloced);
1598 jucn[cnt].comment = "";
1601 TALLOC_FREE(link_target);
1603 TALLOC_FREE(talloced);
1609 SMB_VFS_CLOSEDIR(conn,dirp);
1612 TALLOC_FREE(smb_fname);
1613 vfs_ChDir(conn, cwd);
1618 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1620 struct junction_map *jn = NULL;
1622 size_t jn_count = 0;
1626 if(!lp_host_msdfs()) {
1630 /* Ensure all the usershares are loaded. */
1632 load_registry_shares();
1633 sharecount = load_usershare_shares(NULL, connections_snum_used);
1636 for(i=0;i < sharecount;i++) {
1637 if(lp_msdfs_root(i)) {
1638 jn_count += count_dfs_links(ctx, i);
1641 if (jn_count == 0) {
1644 jn = talloc_array(ctx, struct junction_map, jn_count);
1648 for(i=0; i < sharecount; i++) {
1649 if (*p_num_jn >= jn_count) {
1652 if(lp_msdfs_root(i)) {
1653 *p_num_jn += form_junctions(ctx, i,
1655 jn_count - *p_num_jn);
1661 /******************************************************************************
1662 Core function to resolve a dfs pathname possibly containing a wildcard. If
1663 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1664 detected during dfs resolution.
1665 ******************************************************************************/
1667 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1668 connection_struct *conn,
1670 const char *name_in,
1672 bool allow_broken_path,
1674 bool *ppath_contains_wcard)
1676 bool path_contains_wcard;
1677 NTSTATUS status = NT_STATUS_OK;
1679 if (dfs_pathnames) {
1680 status = dfs_redirect(ctx,
1686 &path_contains_wcard);
1688 if (NT_STATUS_IS_OK(status) && ppath_contains_wcard != NULL) {
1689 *ppath_contains_wcard = path_contains_wcard;
1693 * Cheat and just return a copy of the in ptr.
1694 * Once srvstr_get_path() uses talloc it'll
1695 * be a talloced ptr anyway.
1697 *pp_name_out = discard_const_p(char, name_in);