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,
820 bool search_wcard_flag,
821 bool allow_broken_path,
823 bool *ppath_contains_wcard)
826 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
829 return NT_STATUS_NO_MEMORY;
832 status = parse_dfs_path(conn, path_in, search_wcard_flag,
833 allow_broken_path, pdp,
834 ppath_contains_wcard);
835 if (!NT_STATUS_IS_OK(status)) {
840 if (pdp->reqpath[0] == '\0') {
842 *pp_path_out = talloc_strdup(ctx, "");
844 return NT_STATUS_NO_MEMORY;
846 DEBUG(5,("dfs_redirect: self-referral.\n"));
850 /* If dfs pathname for a non-dfs share, convert to tcon-relative
851 path and return OK */
853 if (!lp_msdfs_root(SNUM(conn))) {
854 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
857 return NT_STATUS_NO_MEMORY;
862 /* If it looked like a local path (zero hostname/servicename)
863 * just treat as a tcon-relative path. */
865 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
866 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
869 return NT_STATUS_NO_MEMORY;
874 if (!( strequal(pdp->servicename, lp_servicename(talloc_tos(), SNUM(conn)))
875 || (strequal(pdp->servicename, HOMES_NAME)
876 && strequal(lp_servicename(talloc_tos(), SNUM(conn)),
877 conn->session_info->unix_info->sanitized_username) )) ) {
879 /* The given sharename doesn't match this connection. */
882 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
885 status = dfs_path_lookup(ctx, conn, path_in, pdp,
886 search_wcard_flag, NULL, NULL);
887 if (!NT_STATUS_IS_OK(status)) {
888 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
889 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
891 DEBUG(10,("dfs_redirect: dfs_path_lookup "
892 "failed for %s with %s\n",
893 path_in, nt_errstr(status) ));
898 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
900 /* Form non-dfs tcon-relative path */
901 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
904 return NT_STATUS_NO_MEMORY;
907 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
914 /**********************************************************************
915 Return a self referral.
916 **********************************************************************/
918 static NTSTATUS self_ref(TALLOC_CTX *ctx,
919 const char *dfs_path,
920 struct junction_map *jucn,
922 bool *self_referralp)
924 struct referral *ref;
926 *self_referralp = True;
928 jucn->referral_count = 1;
929 if((ref = talloc_zero(ctx, struct referral)) == NULL) {
930 return NT_STATUS_NO_MEMORY;
933 ref->alternate_path = talloc_strdup(ctx, dfs_path);
934 if (!ref->alternate_path) {
936 return NT_STATUS_NO_MEMORY;
939 ref->ttl = REFERRAL_TTL;
940 jucn->referral_list = ref;
941 *consumedcntp = strlen(dfs_path);
945 /**********************************************************************
946 Gets valid referrals for a dfs path and fills up the
947 junction_map structure.
948 **********************************************************************/
950 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
951 const char *dfs_path,
952 bool allow_broken_path,
953 struct junction_map *jucn,
955 bool *self_referralp)
957 struct connection_struct *conn;
958 char *targetpath = NULL;
960 NTSTATUS status = NT_STATUS_NOT_FOUND;
962 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
966 return NT_STATUS_NO_MEMORY;
969 *self_referralp = False;
971 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
973 if (!NT_STATUS_IS_OK(status)) {
977 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
978 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
979 if (!jucn->service_name || !jucn->volume_name) {
981 return NT_STATUS_NO_MEMORY;
984 /* Verify the share is a dfs root */
985 snum = lp_servicenumber(jucn->service_name);
987 char *service_name = NULL;
988 if ((snum = find_service(ctx, jucn->service_name, &service_name)) < 0) {
989 return NT_STATUS_NOT_FOUND;
992 return NT_STATUS_NO_MEMORY;
994 TALLOC_FREE(jucn->service_name);
995 jucn->service_name = talloc_strdup(ctx, service_name);
996 if (!jucn->service_name) {
998 return NT_STATUS_NO_MEMORY;
1002 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(talloc_tos(), snum) == '\0')) {
1003 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
1005 pdp->servicename, dfs_path));
1007 return NT_STATUS_NOT_FOUND;
1011 * Self referrals are tested with a anonymous IPC connection and
1012 * a GET_DFS_REFERRAL call to \\server\share. (which means
1013 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
1014 * into the directory and will fail if it cannot (as the anonymous
1015 * user). Cope with this.
1018 if (pdp->reqpath[0] == '\0') {
1020 struct referral *ref;
1023 if (*lp_msdfs_proxy(talloc_tos(), snum) == '\0') {
1025 return self_ref(ctx,
1033 * It's an msdfs proxy share. Redirect to
1034 * the configured target share.
1037 tmp = talloc_asprintf(talloc_tos(), "msdfs:%s",
1038 lp_msdfs_proxy(talloc_tos(), snum));
1041 return NT_STATUS_NO_MEMORY;
1044 if (!parse_msdfs_symlink(ctx, snum, tmp, &ref, &refcount)) {
1047 return NT_STATUS_INVALID_PARAMETER;
1050 jucn->referral_count = refcount;
1051 jucn->referral_list = ref;
1052 *consumedcntp = strlen(dfs_path);
1054 return NT_STATUS_OK;
1057 status = create_conn_struct_cwd(ctx,
1058 server_event_context(),
1059 server_messaging_context(),
1061 lp_path(talloc_tos(), snum), NULL, &oldpath);
1062 if (!NT_STATUS_IS_OK(status)) {
1067 /* If this is a DFS path dfs_lookup should return
1068 * NT_STATUS_PATH_NOT_COVERED. */
1070 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
1071 False, consumedcntp, &targetpath);
1073 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
1074 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
1076 if (NT_STATUS_IS_OK(status)) {
1078 * We are in an error path here (we
1079 * know it's not a DFS path), but
1080 * dfs_path_lookup() can return
1081 * NT_STATUS_OK. Ensure we always
1082 * return a valid error code.
1084 * #9588 - ACLs are not inherited to directories
1087 status = NT_STATUS_NOT_FOUND;
1092 /* We know this is a valid dfs link. Parse the targetpath. */
1093 if (!parse_msdfs_symlink(ctx, snum, targetpath,
1094 &jucn->referral_list,
1095 &jucn->referral_count)) {
1096 DEBUG(3,("get_referred_path: failed to parse symlink "
1097 "target %s\n", targetpath ));
1098 status = NT_STATUS_NOT_FOUND;
1102 status = NT_STATUS_OK;
1104 vfs_ChDir(conn, oldpath);
1105 SMB_VFS_DISCONNECT(conn);
1111 /******************************************************************
1112 Set up the DFS referral for the dfs pathname. This call returns
1113 the amount of the path covered by this server, and where the
1114 client should be redirected to. This is the meat of the
1115 TRANS2_GET_DFS_REFERRAL call.
1116 ******************************************************************/
1118 int setup_dfs_referral(connection_struct *orig_conn,
1119 const char *dfs_path,
1120 int max_referral_level,
1121 char **ppdata, NTSTATUS *pstatus)
1123 char *pdata = *ppdata;
1125 struct dfs_GetDFSReferral *r;
1126 DATA_BLOB blob = data_blob_null;
1128 enum ndr_err_code ndr_err;
1130 r = talloc_zero(talloc_tos(), struct dfs_GetDFSReferral);
1132 *pstatus = NT_STATUS_NO_MEMORY;
1136 r->in.req.max_referral_level = max_referral_level;
1137 r->in.req.servername = talloc_strdup(r, dfs_path);
1138 if (r->in.req.servername == NULL) {
1140 *pstatus = NT_STATUS_NO_MEMORY;
1144 status = SMB_VFS_GET_DFS_REFERRALS(orig_conn, r);
1145 if (!NT_STATUS_IS_OK(status)) {
1151 ndr_err = ndr_push_struct_blob(&blob, r,
1153 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1154 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1156 *pstatus = NT_STATUS_INVALID_PARAMETER;
1160 pdata = (char *)SMB_REALLOC(pdata, blob.length);
1163 DEBUG(0,("referral setup:"
1164 "malloc failed for Realloc!\n"));
1168 reply_size = blob.length;
1169 memcpy(pdata, blob.data, blob.length);
1172 *pstatus = NT_STATUS_OK;
1176 /**********************************************************************
1177 The following functions are called by the NETDFS RPC pipe functions
1178 **********************************************************************/
1180 /*********************************************************************
1181 Creates a junction structure from a DFS pathname
1182 **********************************************************************/
1184 bool create_junction(TALLOC_CTX *ctx,
1185 const char *dfs_path,
1186 bool allow_broken_path,
1187 struct junction_map *jucn)
1191 struct dfs_path *pdp = talloc(ctx,struct dfs_path);
1197 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1199 if (!NT_STATUS_IS_OK(status)) {
1203 /* check if path is dfs : validate first token */
1204 if (!is_myname_or_ipaddr(pdp->hostname)) {
1205 DEBUG(4,("create_junction: Invalid hostname %s "
1207 pdp->hostname, dfs_path));
1212 /* Check for a non-DFS share */
1213 snum = lp_servicenumber(pdp->servicename);
1215 if(snum < 0 || !lp_msdfs_root(snum)) {
1216 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1222 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1223 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1224 jucn->comment = lp_comment(ctx, snum);
1227 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1233 /**********************************************************************
1234 Forms a valid Unix pathname from the junction
1235 **********************************************************************/
1237 static bool junction_to_local_path(const struct junction_map *jucn,
1239 connection_struct **conn_out,
1245 snum = lp_servicenumber(jucn->service_name);
1249 status = create_conn_struct_cwd(talloc_tos(),
1250 server_event_context(),
1251 server_messaging_context(),
1253 snum, lp_path(talloc_tos(), snum), NULL, oldpath);
1254 if (!NT_STATUS_IS_OK(status)) {
1258 *pp_path_out = talloc_asprintf(*conn_out,
1260 lp_path(talloc_tos(), snum),
1262 if (!*pp_path_out) {
1263 vfs_ChDir(*conn_out, *oldpath);
1264 SMB_VFS_DISCONNECT(*conn_out);
1265 conn_free(*conn_out);
1271 bool create_msdfs_link(const struct junction_map *jucn)
1275 char *msdfs_link = NULL;
1276 connection_struct *conn;
1278 bool insert_comma = False;
1281 if(!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1285 /* Form the msdfs_link contents */
1286 msdfs_link = talloc_strdup(conn, "msdfs:");
1290 for(i=0; i<jucn->referral_count; i++) {
1291 char *refpath = jucn->referral_list[i].alternate_path;
1293 /* Alternate paths always use Windows separators. */
1294 trim_char(refpath, '\\', '\\');
1295 if(*refpath == '\0') {
1297 insert_comma = False;
1301 if (i > 0 && insert_comma) {
1302 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1306 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1314 if (!insert_comma) {
1315 insert_comma = True;
1319 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1322 if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1323 if (errno == EEXIST) {
1324 struct smb_filename *smb_fname;
1326 smb_fname = synthetic_smb_fname(talloc_tos(),
1331 if (smb_fname == NULL) {
1336 if(SMB_VFS_UNLINK(conn, smb_fname)!=0) {
1337 TALLOC_FREE(smb_fname);
1340 TALLOC_FREE(smb_fname);
1342 if (SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1343 DEBUG(1,("create_msdfs_link: symlink failed "
1344 "%s -> %s\nError: %s\n",
1345 path, msdfs_link, strerror(errno)));
1353 vfs_ChDir(conn, cwd);
1354 SMB_VFS_DISCONNECT(conn);
1359 bool remove_msdfs_link(const struct junction_map *jucn)
1363 connection_struct *conn;
1365 struct smb_filename *smb_fname;
1367 if (!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1371 smb_fname = synthetic_smb_fname(talloc_tos(),
1376 if (smb_fname == NULL) {
1381 if( SMB_VFS_UNLINK(conn, smb_fname) == 0 ) {
1385 TALLOC_FREE(smb_fname);
1386 vfs_ChDir(conn, cwd);
1387 SMB_VFS_DISCONNECT(conn);
1392 /*********************************************************************
1393 Return the number of DFS links at the root of this share.
1394 *********************************************************************/
1396 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1400 const char *dname = NULL;
1401 char *talloced = NULL;
1402 const char *connect_path = lp_path(talloc_tos(), snum);
1403 const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum);
1404 connection_struct *conn;
1407 struct smb_filename *smb_fname = NULL;
1409 if(*connect_path == '\0') {
1414 * Fake up a connection struct for the VFS layer.
1417 status = create_conn_struct_cwd(talloc_tos(),
1418 server_event_context(),
1419 server_messaging_context(),
1421 snum, connect_path, NULL, &cwd);
1422 if (!NT_STATUS_IS_OK(status)) {
1423 DEBUG(3, ("create_conn_struct failed: %s\n",
1424 nt_errstr(status)));
1428 /* Count a link for the msdfs root - convention */
1431 /* No more links if this is an msdfs proxy. */
1432 if (*msdfs_proxy != '\0') {
1436 smb_fname = synthetic_smb_fname(talloc_tos(),
1441 if (smb_fname == NULL) {
1445 /* Now enumerate all dfs links */
1446 dirp = SMB_VFS_OPENDIR(conn, smb_fname, NULL, 0);
1451 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1453 if (is_msdfs_link(conn,
1458 TALLOC_FREE(talloced);
1461 SMB_VFS_CLOSEDIR(conn,dirp);
1464 TALLOC_FREE(smb_fname);
1465 vfs_ChDir(conn, cwd);
1466 SMB_VFS_DISCONNECT(conn);
1471 /*********************************************************************
1472 *********************************************************************/
1474 static int form_junctions(TALLOC_CTX *ctx,
1476 struct junction_map *jucn,
1481 const char *dname = NULL;
1482 char *talloced = NULL;
1483 const char *connect_path = lp_path(talloc_tos(), snum);
1484 char *service_name = lp_servicename(talloc_tos(), snum);
1485 const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum);
1486 connection_struct *conn;
1487 struct referral *ref = NULL;
1489 struct smb_filename *smb_fname = NULL;
1492 if (jn_remain == 0) {
1496 if(*connect_path == '\0') {
1501 * Fake up a connection struct for the VFS layer.
1504 status = create_conn_struct_cwd(ctx,
1505 server_event_context(),
1506 server_messaging_context(),
1507 &conn, snum, connect_path, NULL,
1509 if (!NT_STATUS_IS_OK(status)) {
1510 DEBUG(3, ("create_conn_struct failed: %s\n",
1511 nt_errstr(status)));
1515 /* form a junction for the msdfs root - convention
1516 DO NOT REMOVE THIS: NT clients will not work with us
1517 if this is not present
1519 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1520 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1521 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1524 jucn[cnt].comment = "";
1525 jucn[cnt].referral_count = 1;
1527 ref = jucn[cnt].referral_list = talloc_zero(ctx, struct referral);
1528 if (jucn[cnt].referral_list == NULL) {
1533 ref->ttl = REFERRAL_TTL;
1534 if (*msdfs_proxy != '\0') {
1535 ref->alternate_path = talloc_strdup(ctx,
1538 ref->alternate_path = talloc_asprintf(ctx,
1540 get_local_machine_name(),
1544 if (!ref->alternate_path) {
1549 /* Don't enumerate if we're an msdfs proxy. */
1550 if (*msdfs_proxy != '\0') {
1554 smb_fname = synthetic_smb_fname(talloc_tos(),
1559 if (smb_fname == NULL) {
1563 /* Now enumerate all dfs links */
1564 dirp = SMB_VFS_OPENDIR(conn, smb_fname, NULL, 0);
1569 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1571 char *link_target = NULL;
1572 if (cnt >= jn_remain) {
1573 DEBUG(2, ("form_junctions: ran out of MSDFS "
1575 TALLOC_FREE(talloced);
1578 if (is_msdfs_link_internal(ctx,
1580 dname, &link_target,
1582 if (parse_msdfs_symlink(ctx, snum,
1584 &jucn[cnt].referral_list,
1585 &jucn[cnt].referral_count)) {
1587 jucn[cnt].service_name = talloc_strdup(ctx,
1589 jucn[cnt].volume_name = talloc_strdup(ctx,
1591 if (!jucn[cnt].service_name ||
1592 !jucn[cnt].volume_name) {
1593 TALLOC_FREE(talloced);
1596 jucn[cnt].comment = "";
1599 TALLOC_FREE(link_target);
1601 TALLOC_FREE(talloced);
1607 SMB_VFS_CLOSEDIR(conn,dirp);
1610 TALLOC_FREE(smb_fname);
1611 vfs_ChDir(conn, cwd);
1616 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1618 struct junction_map *jn = NULL;
1620 size_t jn_count = 0;
1624 if(!lp_host_msdfs()) {
1628 /* Ensure all the usershares are loaded. */
1630 load_registry_shares();
1631 sharecount = load_usershare_shares(NULL, connections_snum_used);
1634 for(i=0;i < sharecount;i++) {
1635 if(lp_msdfs_root(i)) {
1636 jn_count += count_dfs_links(ctx, i);
1639 if (jn_count == 0) {
1642 jn = talloc_array(ctx, struct junction_map, jn_count);
1646 for(i=0; i < sharecount; i++) {
1647 if (*p_num_jn >= jn_count) {
1650 if(lp_msdfs_root(i)) {
1651 *p_num_jn += form_junctions(ctx, i,
1653 jn_count - *p_num_jn);
1659 /******************************************************************************
1660 Core function to resolve a dfs pathname possibly containing a wildcard. If
1661 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1662 detected during dfs resolution.
1663 ******************************************************************************/
1665 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1666 connection_struct *conn,
1668 const char *name_in,
1670 bool allow_broken_path,
1672 bool *ppath_contains_wcard)
1674 bool path_contains_wcard;
1675 NTSTATUS status = NT_STATUS_OK;
1677 if (dfs_pathnames) {
1678 status = dfs_redirect(ctx,
1684 &path_contains_wcard);
1686 if (NT_STATUS_IS_OK(status) && ppath_contains_wcard != NULL) {
1687 *ppath_contains_wcard = path_contains_wcard;
1691 * Cheat and just return a copy of the in ptr.
1692 * Once srvstr_get_path() uses talloc it'll
1693 * be a talloced ptr anyway.
1695 *pp_name_out = discard_const_p(char, name_in);