2 Unix SMB/Netbios implementation.
4 MSDFS services for Samba
5 Copyright (C) Shirish Kalele 2000
6 Copyright (C) Jeremy Allison 2007
7 Copyright (C) Robin McCorkell 2015
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #define DBGC_CLASS DBGC_MSDFS
26 #include "system/filesys.h"
27 #include "smbd/smbd.h"
28 #include "smbd/globals.h"
31 #include "lib/param/loadparm.h"
32 #include "libcli/security/security.h"
33 #include "librpc/gen_ndr/ndr_dfsblobs.h"
34 #include "lib/tsocket/tsocket.h"
36 /**********************************************************************
37 Parse a DFS pathname of the form \hostname\service\reqpath
38 into the dfs_path structure.
39 If POSIX pathnames is true, the pathname may also be of the
40 form /hostname/service/reqpath.
41 We cope with either here.
43 Unfortunately, due to broken clients who might set the
44 SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
45 send a local path, we have to cope with that too....
47 If conn != NULL then ensure the provided service is
48 the one pointed to by the connection.
50 This version does everything using pointers within one copy of the
51 pathname string, talloced on the struct dfs_path pointer (which
52 must be talloced). This may be too clever to live....
54 **********************************************************************/
56 static NTSTATUS parse_dfs_path(connection_struct *conn,
59 bool allow_broken_path,
60 struct dfs_path *pdp, /* MUST BE TALLOCED */
61 bool *ppath_contains_wcard)
67 NTSTATUS status = NT_STATUS_OK;
73 * This is the only talloc we should need to do
74 * on the struct dfs_path. All the pointers inside
75 * it should point to offsets within this string.
78 pathname_local = talloc_strdup(pdp, pathname);
79 if (!pathname_local) {
80 return NT_STATUS_NO_MEMORY;
82 /* Get a pointer to the terminating '\0' */
83 eos_ptr = &pathname_local[strlen(pathname_local)];
84 p = temp = pathname_local;
87 * Non-broken DFS paths *must* start with the
88 * path separator. For Windows this is always '\\',
89 * for posix paths this is always '/'.
92 if (*pathname == '/') {
93 pdp->posix_path = true;
96 pdp->posix_path = false;
100 if (allow_broken_path && (*pathname != sepchar)) {
101 DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
102 pathname, sepchar ));
104 * Possibly client sent a local path by mistake.
105 * Try and convert to a local path.
106 * Note that this is an SMB1-only fallback
107 * to cope with known broken SMB1 clients.
110 pdp->hostname = eos_ptr; /* "" */
111 pdp->servicename = eos_ptr; /* "" */
113 /* We've got no info about separators. */
114 pdp->posix_path = lp_posix_pathnames();
116 DEBUG(10,("parse_dfs_path: trying to convert %s to a "
123 * Safe to use on talloc'ed string as it only shrinks.
124 * It also doesn't affect the eos_ptr.
126 trim_char(temp,sepchar,sepchar);
128 DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
132 /* Parse out hostname. */
133 p = strchr_m(temp,sepchar);
135 DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
138 * Possibly client sent a local path by mistake.
139 * Try and convert to a local path.
142 pdp->hostname = eos_ptr; /* "" */
143 pdp->servicename = eos_ptr; /* "" */
146 DEBUG(10,("parse_dfs_path: trying to convert %s "
152 pdp->hostname = temp;
154 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
156 /* Parse out servicename. */
158 p = strchr_m(servicename,sepchar);
163 /* Is this really our servicename ? */
164 if (conn && !( strequal(servicename, lp_servicename(talloc_tos(), SNUM(conn)))
165 || (strequal(servicename, HOMES_NAME)
166 && strequal(lp_servicename(talloc_tos(), SNUM(conn)),
167 get_current_username()) )) ) {
168 DEBUG(10,("parse_dfs_path: %s is not our servicename\n",
172 * Possibly client sent a local path by mistake.
173 * Try and convert to a local path.
176 pdp->hostname = eos_ptr; /* "" */
177 pdp->servicename = eos_ptr; /* "" */
179 /* Repair the path - replace the sepchar's
182 *servicename = sepchar;
188 DEBUG(10,("parse_dfs_path: trying to convert %s "
194 pdp->servicename = servicename;
196 DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
199 /* Client sent self referral \server\share. */
200 pdp->reqpath = eos_ptr; /* "" */
208 *ppath_contains_wcard = False;
212 /* Rest is reqpath. */
213 if (pdp->posix_path) {
214 status = check_path_syntax_posix(pdp->reqpath);
217 status = check_path_syntax_wcard(pdp->reqpath,
218 ppath_contains_wcard);
220 status = check_path_syntax(pdp->reqpath);
224 if (!NT_STATUS_IS_OK(status)) {
225 DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
226 p, nt_errstr(status) ));
230 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
234 /********************************************************
235 Fake up a connection struct for the VFS layer, for use in
236 applications (such as the python bindings), that do not want the
237 global working directory changed under them.
239 SMB_VFS_CONNECT requires root privileges.
240 *********************************************************/
242 static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx,
243 struct tevent_context *ev,
244 struct messaging_context *msg,
245 connection_struct **pconn,
248 const struct auth_session_info *session_info)
250 connection_struct *conn;
252 const char *vfs_user;
253 struct smbd_server_connection *sconn;
254 const char *servicename = lp_const_servicename(snum);
256 sconn = talloc_zero(ctx, struct smbd_server_connection);
258 return NT_STATUS_NO_MEMORY;
262 sconn->msg_ctx = msg;
264 conn = conn_new(sconn);
267 return NT_STATUS_NO_MEMORY;
270 /* Now we have conn, we need to make sconn a child of conn,
271 * for a proper talloc tree */
272 talloc_steal(conn, sconn);
274 if (snum == -1 && servicename == NULL) {
275 servicename = "Unknown Service (snum == -1)";
278 connpath = talloc_strdup(conn, path);
281 return NT_STATUS_NO_MEMORY;
283 connpath = talloc_string_sub(conn,
289 return NT_STATUS_NO_MEMORY;
292 /* needed for smbd_vfs_init() */
294 conn->params->service = snum;
295 conn->cnum = TID_FIELD_INVALID;
297 if (session_info != NULL) {
298 conn->session_info = copy_session_info(conn, session_info);
299 if (conn->session_info == NULL) {
300 DEBUG(0, ("copy_serverinfo failed\n"));
302 return NT_STATUS_NO_MEMORY;
304 vfs_user = conn->session_info->unix_info->unix_name;
306 /* use current authenticated user in absence of session_info */
307 vfs_user = get_current_username();
310 set_conn_connectpath(conn, connpath);
313 * New code to check if there's a share security descriptor
314 * added from NT server manager. This is done after the
315 * smb.conf checks are done as we need a uid and token. JRA.
318 if (conn->session_info) {
319 share_access_check(conn->session_info->security_token,
321 MAXIMUM_ALLOWED_ACCESS,
322 &conn->share_access);
324 if ((conn->share_access & FILE_WRITE_DATA) == 0) {
325 if ((conn->share_access & FILE_READ_DATA) == 0) {
326 /* No access, read or write. */
327 DEBUG(3,("create_conn_struct: connection to %s "
328 "denied due to security "
332 return NT_STATUS_ACCESS_DENIED;
334 conn->read_only = true;
338 conn->share_access = 0;
339 conn->read_only = true;
342 if (!smbd_vfs_init(conn)) {
343 NTSTATUS status = map_nt_error_from_unix(errno);
344 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
349 /* this must be the first filesystem operation that we do */
350 if (SMB_VFS_CONNECT(conn, servicename, vfs_user) < 0) {
351 DEBUG(0,("VFS connect failed!\n"));
353 return NT_STATUS_UNSUCCESSFUL;
356 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
362 /********************************************************
363 Fake up a connection struct for the VFS layer, for use in
364 applications (such as the python bindings), that do not want the
365 global working directory changed under them.
367 SMB_VFS_CONNECT requires root privileges.
368 *********************************************************/
370 NTSTATUS create_conn_struct(TALLOC_CTX *ctx,
371 struct tevent_context *ev,
372 struct messaging_context *msg,
373 connection_struct **pconn,
376 const struct auth_session_info *session_info)
380 status = create_conn_struct_as_root(ctx, ev,
389 /********************************************************
390 Fake up a connection struct for the VFS layer.
391 Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
393 The old working directory is returned on *poldcwd, allocated on ctx.
394 *********************************************************/
396 NTSTATUS create_conn_struct_cwd(TALLOC_CTX *ctx,
397 struct tevent_context *ev,
398 struct messaging_context *msg,
399 connection_struct **pconn,
402 const struct auth_session_info *session_info,
403 struct smb_filename **poldcwd_fname)
405 connection_struct *conn;
406 struct smb_filename *oldcwd_fname = NULL;
407 struct smb_filename smb_fname_connectpath = {0};
409 NTSTATUS status = create_conn_struct(ctx, ev,
413 if (!NT_STATUS_IS_OK(status)) {
418 * Windows seems to insist on doing trans2getdfsreferral() calls on
419 * the IPC$ share as the anonymous user. If we try to chdir as that
420 * user we will fail.... WTF ? JRA.
423 oldcwd_fname = vfs_GetWd(ctx, conn);
424 if (oldcwd_fname == NULL) {
425 status = map_nt_error_from_unix(errno);
426 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
431 smb_fname_connectpath = (struct smb_filename) {
432 .base_name = conn->connectpath
435 if (vfs_ChDir(conn, &smb_fname_connectpath) != 0) {
436 status = map_nt_error_from_unix(errno);
437 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
439 conn->connectpath, strerror(errno) ));
440 TALLOC_FREE(oldcwd_fname);
446 *poldcwd_fname = oldcwd_fname;
451 static int conn_struct_tos_destructor(struct conn_struct_tos *c)
453 if (c->oldcwd_fname != NULL) {
454 vfs_ChDir(c->conn, c->oldcwd_fname);
455 TALLOC_FREE(c->oldcwd_fname);
457 SMB_VFS_DISCONNECT(c->conn);
462 /********************************************************
463 Fake up a connection struct for the VFS layer, for use in
464 applications (such as the python bindings), that do not want the
465 global working directory changed under them.
467 SMB_VFS_CONNECT requires root privileges.
468 This temporary uses become_root() and unbecome_root().
470 But further impersonation has to be cone by the caller.
471 *********************************************************/
472 NTSTATUS create_conn_struct_tos(struct messaging_context *msg,
475 const struct auth_session_info *session_info,
476 struct conn_struct_tos **_c)
478 struct conn_struct_tos *c = NULL;
479 struct tevent_context *ev = NULL;
484 c = talloc_zero(talloc_tos(), struct conn_struct_tos);
486 return NT_STATUS_NO_MEMORY;
489 ev = samba_tevent_context_init(c);
492 return NT_STATUS_NO_MEMORY;
495 status = create_conn_struct(c,
502 if (!NT_STATUS_IS_OK(status)) {
506 talloc_steal(c, c->conn);
508 talloc_set_destructor(c, conn_struct_tos_destructor);
514 /********************************************************
515 Fake up a connection struct for the VFS layer.
516 Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
518 See also the comment for create_conn_struct_tos() above!
520 The CWD change is reverted by the destructor of
521 conn_struct_tos when the current talloc_tos() is destroyed.
522 *********************************************************/
523 NTSTATUS create_conn_struct_tos_cwd(struct messaging_context *msg,
526 const struct auth_session_info *session_info,
527 struct conn_struct_tos **_c)
529 struct conn_struct_tos *c = NULL;
530 struct smb_filename smb_fname_connectpath = {0};
535 status = create_conn_struct_tos(msg,
540 if (!NT_STATUS_IS_OK(status)) {
545 * Windows seems to insist on doing trans2getdfsreferral() calls on
546 * the IPC$ share as the anonymous user. If we try to chdir as that
547 * user we will fail.... WTF ? JRA.
550 c->oldcwd_fname = vfs_GetWd(c, c->conn);
551 if (c->oldcwd_fname == NULL) {
552 status = map_nt_error_from_unix(errno);
553 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
558 smb_fname_connectpath = (struct smb_filename) {
559 .base_name = c->conn->connectpath
562 if (vfs_ChDir(c->conn, &smb_fname_connectpath) != 0) {
563 status = map_nt_error_from_unix(errno);
564 DBG_NOTICE("Can't ChDir to new conn path %s. "
566 c->conn->connectpath, strerror(errno));
567 TALLOC_FREE(c->oldcwd_fname);
576 static void shuffle_strlist(char **list, int count)
582 for (i = count; i > 1; i--) {
583 r = generate_random() % i;
591 /**********************************************************************
592 Parse the contents of a symlink to verify if it is an msdfs referral
593 A valid referral is of the form:
595 msdfs:server1\share1,server2\share2
596 msdfs:server1\share1\pathname,server2\share2\pathname
597 msdfs:server1/share1,server2/share2
598 msdfs:server1/share1/pathname,server2/share2/pathname.
600 Note that the alternate paths returned here must be of the canonicalized
604 \server\share\path\to\file,
606 even in posix path mode. This is because we have no knowledge if the
607 server we're referring to understands posix paths.
608 **********************************************************************/
610 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
613 struct referral **preflist,
618 char **alt_path = NULL;
620 struct referral *reflist;
623 temp = talloc_strdup(ctx, target);
627 prot = strtok_r(temp, ":", &saveptr);
629 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
633 alt_path = talloc_array(ctx, char *, MAX_REFERRAL_COUNT);
638 /* parse out the alternate paths */
639 while((count<MAX_REFERRAL_COUNT) &&
640 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
644 /* shuffle alternate paths */
645 if (lp_msdfs_shuffle_referrals(snum)) {
646 shuffle_strlist(alt_path, count);
649 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
652 reflist = *preflist = talloc_zero_array(ctx,
653 struct referral, count);
654 if(reflist == NULL) {
655 TALLOC_FREE(alt_path);
659 reflist = *preflist = NULL;
662 for(i=0;i<count;i++) {
665 /* Canonicalize link target.
666 * Replace all /'s in the path by a \ */
667 string_replace(alt_path[i], '/', '\\');
669 /* Remove leading '\\'s */
671 while (*p && (*p == '\\')) {
675 reflist[i].alternate_path = talloc_asprintf(ctx,
678 if (!reflist[i].alternate_path) {
682 reflist[i].proximity = 0;
683 reflist[i].ttl = REFERRAL_TTL;
684 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
685 reflist[i].alternate_path));
690 TALLOC_FREE(alt_path);
694 /**********************************************************************
695 Returns true if the unix path is a valid msdfs symlink and also
696 returns the target string from inside the link.
697 **********************************************************************/
699 static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
700 connection_struct *conn,
701 struct smb_filename *smb_fname,
702 char **pp_link_target)
704 int referral_len = 0;
705 #if defined(HAVE_BROKEN_READLINK)
706 char link_target_buf[PATH_MAX];
708 char link_target_buf[7];
711 char *link_target = NULL;
713 if (pp_link_target) {
715 link_target = talloc_array(ctx, char, bufsize);
719 *pp_link_target = link_target;
721 bufsize = sizeof(link_target_buf);
722 link_target = link_target_buf;
725 if (SMB_VFS_LSTAT(conn, smb_fname) != 0) {
726 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
727 smb_fname->base_name));
730 if (!S_ISLNK(smb_fname->st.st_ex_mode)) {
731 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
732 smb_fname->base_name));
736 referral_len = SMB_VFS_READLINK(conn, smb_fname,
737 link_target, bufsize - 1);
738 if (referral_len == -1) {
739 DEBUG(0,("is_msdfs_link_read_target: Error reading "
740 "msdfs link %s: %s\n",
741 smb_fname->base_name, strerror(errno)));
744 link_target[referral_len] = '\0';
746 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n", smb_fname->base_name,
749 if (!strnequal(link_target, "msdfs:", 6)) {
756 if (link_target != link_target_buf) {
757 TALLOC_FREE(link_target);
762 /**********************************************************************
763 Returns true if the unix path is a valid msdfs symlink.
764 **********************************************************************/
766 bool is_msdfs_link(connection_struct *conn,
767 struct smb_filename *smb_fname)
769 return is_msdfs_link_internal(talloc_tos(),
775 /*****************************************************************
776 Used by other functions to decide if a dfs path is remote,
777 and to get the list of referred locations for that remote path.
779 search_flag: For findfirsts, dfs links themselves are not
780 redirected, but paths beyond the links are. For normal smb calls,
781 even dfs links need to be redirected.
783 consumedcntp: how much of the dfs path is being redirected. the client
784 should try the remaining path on the redirected server.
786 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
787 link redirect are in targetpath.
788 *****************************************************************/
790 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
791 connection_struct *conn,
792 const char *dfspath, /* Incoming complete dfs path */
793 const struct dfs_path *pdp, /* Parsed out
794 server+share+extrapath. */
797 char **pp_targetpath)
802 struct smb_filename *smb_fname = NULL;
803 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
806 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
807 conn->connectpath, pdp->reqpath));
810 * Note the unix path conversion here we're doing we
811 * throw away. We're looking for a symlink for a dfs
812 * resolution, if we don't find it we'll do another
813 * unix_convert later in the codepath.
816 status = unix_convert(ctx, conn, pdp->reqpath, &smb_fname,
819 if (!NT_STATUS_IS_OK(status)) {
820 if (!NT_STATUS_EQUAL(status,
821 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
824 if (smb_fname == NULL || smb_fname->base_name == NULL) {
829 /* Optimization - check if we can redirect the whole path. */
831 if (is_msdfs_link_internal(ctx, conn, smb_fname, pp_targetpath)) {
832 /* XX_ALLOW_WCARD_XXX is called from search functions. */
834 (UCF_COND_ALLOW_WCARD_LCOMP|
835 UCF_ALWAYS_ALLOW_WCARD_LCOMP)) {
836 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
837 "for dfs link %s.\n", dfspath));
838 status = NT_STATUS_OK;
842 DEBUG(6,("dfs_path_lookup: %s resolves to a "
843 "valid dfs link %s.\n", dfspath,
844 pp_targetpath ? *pp_targetpath : ""));
847 *consumedcntp = strlen(dfspath);
849 status = NT_STATUS_PATH_NOT_COVERED;
853 /* Prepare to test only for '/' components in the given path,
854 * so if a Windows path replace all '\\' characters with '/'.
855 * For a POSIX DFS path we know all separators are already '/'. */
857 canon_dfspath = talloc_strdup(ctx, dfspath);
858 if (!canon_dfspath) {
859 status = NT_STATUS_NO_MEMORY;
862 if (!pdp->posix_path) {
863 string_replace(canon_dfspath, '\\', '/');
867 * localpath comes out of unix_convert, so it has
868 * no trailing backslash. Make sure that canon_dfspath hasn't either.
869 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
872 trim_char(canon_dfspath,0,'/');
875 * Redirect if any component in the path is a link.
876 * We do this by walking backwards through the
877 * local path, chopping off the last component
878 * in both the local path and the canonicalized
879 * DFS path. If we hit a DFS link then we're done.
882 p = strrchr_m(smb_fname->base_name, '/');
884 q = strrchr_m(canon_dfspath, '/');
893 if (is_msdfs_link_internal(ctx, conn,
894 smb_fname, pp_targetpath)) {
895 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
896 "parent %s is dfs link\n", dfspath,
897 smb_fname_str_dbg(smb_fname)));
900 *consumedcntp = strlen(canon_dfspath);
901 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
907 status = NT_STATUS_PATH_NOT_COVERED;
911 /* Step back on the filesystem. */
912 p = strrchr_m(smb_fname->base_name, '/');
915 /* And in the canonicalized dfs path. */
916 q = strrchr_m(canon_dfspath, '/');
920 status = NT_STATUS_OK;
922 TALLOC_FREE(smb_fname);
926 /*****************************************************************
927 Decides if a dfs pathname should be redirected or not.
928 If not, the pathname is converted to a tcon-relative local unix path
930 search_wcard_flag: this flag performs 2 functions both related
931 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
934 This function can return NT_STATUS_OK, meaning use the returned path as-is
935 (mapped into a local path).
936 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
937 any other NT_STATUS error which is a genuine error to be
938 returned to the client.
939 *****************************************************************/
941 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
942 connection_struct *conn,
945 bool allow_broken_path,
947 bool *ppath_contains_wcard)
950 bool search_wcard_flag = (ucf_flags &
951 (UCF_COND_ALLOW_WCARD_LCOMP|UCF_ALWAYS_ALLOW_WCARD_LCOMP));
952 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
955 return NT_STATUS_NO_MEMORY;
958 status = parse_dfs_path(conn, path_in, search_wcard_flag,
959 allow_broken_path, pdp,
960 ppath_contains_wcard);
961 if (!NT_STATUS_IS_OK(status)) {
966 if (pdp->reqpath[0] == '\0') {
968 *pp_path_out = talloc_strdup(ctx, "");
970 return NT_STATUS_NO_MEMORY;
972 DEBUG(5,("dfs_redirect: self-referral.\n"));
976 /* If dfs pathname for a non-dfs share, convert to tcon-relative
977 path and return OK */
979 if (!lp_msdfs_root(SNUM(conn))) {
980 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
983 return NT_STATUS_NO_MEMORY;
988 /* If it looked like a local path (zero hostname/servicename)
989 * just treat as a tcon-relative path. */
991 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
992 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
995 return NT_STATUS_NO_MEMORY;
1000 if (!( strequal(pdp->servicename, lp_servicename(talloc_tos(), SNUM(conn)))
1001 || (strequal(pdp->servicename, HOMES_NAME)
1002 && strequal(lp_servicename(talloc_tos(), SNUM(conn)),
1003 conn->session_info->unix_info->sanitized_username) )) ) {
1005 /* The given sharename doesn't match this connection. */
1008 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1011 status = dfs_path_lookup(ctx, conn, path_in, pdp,
1012 ucf_flags, NULL, NULL);
1013 if (!NT_STATUS_IS_OK(status)) {
1014 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
1015 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
1017 DEBUG(10,("dfs_redirect: dfs_path_lookup "
1018 "failed for %s with %s\n",
1019 path_in, nt_errstr(status) ));
1024 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
1026 /* Form non-dfs tcon-relative path */
1027 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
1029 if (!*pp_path_out) {
1030 return NT_STATUS_NO_MEMORY;
1033 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
1037 return NT_STATUS_OK;
1040 /**********************************************************************
1041 Return a self referral.
1042 **********************************************************************/
1044 static NTSTATUS self_ref(TALLOC_CTX *ctx,
1045 const char *dfs_path,
1046 struct junction_map *jucn,
1048 bool *self_referralp)
1050 struct referral *ref;
1052 *self_referralp = True;
1054 jucn->referral_count = 1;
1055 if((ref = talloc_zero(ctx, struct referral)) == NULL) {
1056 return NT_STATUS_NO_MEMORY;
1059 ref->alternate_path = talloc_strdup(ctx, dfs_path);
1060 if (!ref->alternate_path) {
1062 return NT_STATUS_NO_MEMORY;
1065 ref->ttl = REFERRAL_TTL;
1066 jucn->referral_list = ref;
1067 *consumedcntp = strlen(dfs_path);
1068 return NT_STATUS_OK;
1071 /**********************************************************************
1072 Gets valid referrals for a dfs path and fills up the
1073 junction_map structure.
1074 **********************************************************************/
1076 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
1077 const char *dfs_path,
1078 const struct tsocket_address *remote_address,
1079 const struct tsocket_address *local_address,
1080 bool allow_broken_path,
1081 struct junction_map *jucn,
1083 bool *self_referralp)
1085 struct connection_struct *conn;
1086 char *targetpath = NULL;
1088 NTSTATUS status = NT_STATUS_NOT_FOUND;
1090 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
1091 struct smb_filename *oldcwd_fname = NULL;
1094 return NT_STATUS_NO_MEMORY;
1097 *self_referralp = False;
1099 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1101 if (!NT_STATUS_IS_OK(status)) {
1105 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1106 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1107 if (!jucn->service_name || !jucn->volume_name) {
1109 return NT_STATUS_NO_MEMORY;
1112 /* Verify the share is a dfs root */
1113 snum = lp_servicenumber(jucn->service_name);
1115 char *service_name = NULL;
1116 if ((snum = find_service(ctx, jucn->service_name, &service_name)) < 0) {
1117 return NT_STATUS_NOT_FOUND;
1119 if (!service_name) {
1120 return NT_STATUS_NO_MEMORY;
1122 TALLOC_FREE(jucn->service_name);
1123 jucn->service_name = talloc_strdup(ctx, service_name);
1124 if (!jucn->service_name) {
1126 return NT_STATUS_NO_MEMORY;
1130 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(talloc_tos(), snum) == '\0')) {
1131 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
1133 pdp->servicename, dfs_path));
1135 return NT_STATUS_NOT_FOUND;
1139 * Self referrals are tested with a anonymous IPC connection and
1140 * a GET_DFS_REFERRAL call to \\server\share. (which means
1141 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
1142 * into the directory and will fail if it cannot (as the anonymous
1143 * user). Cope with this.
1146 if (pdp->reqpath[0] == '\0') {
1148 struct referral *ref;
1151 if (*lp_msdfs_proxy(talloc_tos(), snum) == '\0') {
1153 return self_ref(ctx,
1161 * It's an msdfs proxy share. Redirect to
1162 * the configured target share.
1165 tmp = talloc_asprintf(talloc_tos(), "msdfs:%s",
1166 lp_msdfs_proxy(talloc_tos(), snum));
1169 return NT_STATUS_NO_MEMORY;
1172 if (!parse_msdfs_symlink(ctx, snum, tmp, &ref, &refcount)) {
1175 return NT_STATUS_INVALID_PARAMETER;
1178 jucn->referral_count = refcount;
1179 jucn->referral_list = ref;
1180 *consumedcntp = strlen(dfs_path);
1182 return NT_STATUS_OK;
1185 status = create_conn_struct_cwd(ctx,
1186 server_event_context(),
1187 server_messaging_context(),
1190 lp_path(talloc_tos(), snum),
1193 if (!NT_STATUS_IS_OK(status)) {
1201 * The remote and local address should be passed down to
1202 * create_conn_struct_cwd.
1204 if (conn->sconn->remote_address == NULL) {
1205 conn->sconn->remote_address =
1206 tsocket_address_copy(remote_address, conn->sconn);
1207 if (conn->sconn->remote_address == NULL) {
1209 return NT_STATUS_NO_MEMORY;
1212 if (conn->sconn->local_address == NULL) {
1213 conn->sconn->local_address =
1214 tsocket_address_copy(local_address, conn->sconn);
1215 if (conn->sconn->local_address == NULL) {
1217 return NT_STATUS_NO_MEMORY;
1221 /* If this is a DFS path dfs_lookup should return
1222 * NT_STATUS_PATH_NOT_COVERED. */
1224 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
1225 0, consumedcntp, &targetpath);
1227 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
1228 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
1230 if (NT_STATUS_IS_OK(status)) {
1232 * We are in an error path here (we
1233 * know it's not a DFS path), but
1234 * dfs_path_lookup() can return
1235 * NT_STATUS_OK. Ensure we always
1236 * return a valid error code.
1238 * #9588 - ACLs are not inherited to directories
1241 status = NT_STATUS_NOT_FOUND;
1246 /* We know this is a valid dfs link. Parse the targetpath. */
1247 if (!parse_msdfs_symlink(ctx, snum, targetpath,
1248 &jucn->referral_list,
1249 &jucn->referral_count)) {
1250 DEBUG(3,("get_referred_path: failed to parse symlink "
1251 "target %s\n", targetpath ));
1252 status = NT_STATUS_NOT_FOUND;
1256 status = NT_STATUS_OK;
1258 vfs_ChDir(conn, oldcwd_fname);
1259 TALLOC_FREE(oldcwd_fname);
1260 SMB_VFS_DISCONNECT(conn);
1266 /******************************************************************
1267 Set up the DFS referral for the dfs pathname. This call returns
1268 the amount of the path covered by this server, and where the
1269 client should be redirected to. This is the meat of the
1270 TRANS2_GET_DFS_REFERRAL call.
1271 ******************************************************************/
1273 int setup_dfs_referral(connection_struct *orig_conn,
1274 const char *dfs_path,
1275 int max_referral_level,
1276 char **ppdata, NTSTATUS *pstatus)
1278 char *pdata = *ppdata;
1280 struct dfs_GetDFSReferral *r;
1281 DATA_BLOB blob = data_blob_null;
1283 enum ndr_err_code ndr_err;
1285 r = talloc_zero(talloc_tos(), struct dfs_GetDFSReferral);
1287 *pstatus = NT_STATUS_NO_MEMORY;
1291 r->in.req.max_referral_level = max_referral_level;
1292 r->in.req.servername = talloc_strdup(r, dfs_path);
1293 if (r->in.req.servername == NULL) {
1295 *pstatus = NT_STATUS_NO_MEMORY;
1299 status = SMB_VFS_GET_DFS_REFERRALS(orig_conn, r);
1300 if (!NT_STATUS_IS_OK(status)) {
1306 ndr_err = ndr_push_struct_blob(&blob, r,
1308 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1309 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1311 *pstatus = NT_STATUS_INVALID_PARAMETER;
1315 pdata = (char *)SMB_REALLOC(pdata, blob.length);
1318 DEBUG(0,("referral setup:"
1319 "malloc failed for Realloc!\n"));
1323 reply_size = blob.length;
1324 memcpy(pdata, blob.data, blob.length);
1327 *pstatus = NT_STATUS_OK;
1331 /**********************************************************************
1332 The following functions are called by the NETDFS RPC pipe functions
1333 **********************************************************************/
1335 /*********************************************************************
1336 Creates a junction structure from a DFS pathname
1337 **********************************************************************/
1339 bool create_junction(TALLOC_CTX *ctx,
1340 const char *dfs_path,
1341 bool allow_broken_path,
1342 struct junction_map *jucn)
1346 struct dfs_path *pdp = talloc(ctx,struct dfs_path);
1352 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1354 if (!NT_STATUS_IS_OK(status)) {
1358 /* check if path is dfs : validate first token */
1359 if (!is_myname_or_ipaddr(pdp->hostname)) {
1360 DEBUG(4,("create_junction: Invalid hostname %s "
1362 pdp->hostname, dfs_path));
1367 /* Check for a non-DFS share */
1368 snum = lp_servicenumber(pdp->servicename);
1370 if(snum < 0 || !lp_msdfs_root(snum)) {
1371 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1377 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1378 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1379 jucn->comment = lp_comment(ctx, snum);
1382 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1388 /**********************************************************************
1389 Forms a valid Unix pathname from the junction
1390 **********************************************************************/
1392 static bool junction_to_local_path(const struct junction_map *jucn,
1394 connection_struct **conn_out,
1395 struct smb_filename **oldpath_fname)
1400 snum = lp_servicenumber(jucn->service_name);
1404 status = create_conn_struct_cwd(talloc_tos(),
1405 server_event_context(),
1406 server_messaging_context(),
1409 lp_path(talloc_tos(), snum),
1412 if (!NT_STATUS_IS_OK(status)) {
1416 *pp_path_out = talloc_asprintf(*conn_out,
1418 lp_path(talloc_tos(), snum),
1420 if (!*pp_path_out) {
1421 vfs_ChDir(*conn_out, *oldpath_fname);
1422 SMB_VFS_DISCONNECT(*conn_out);
1423 conn_free(*conn_out);
1429 bool create_msdfs_link(const struct junction_map *jucn)
1432 struct smb_filename *cwd_fname = NULL;
1433 char *msdfs_link = NULL;
1434 connection_struct *conn;
1436 bool insert_comma = False;
1438 struct smb_filename *smb_fname = NULL;
1440 if(!junction_to_local_path(jucn, &path, &conn, &cwd_fname)) {
1444 /* Form the msdfs_link contents */
1445 msdfs_link = talloc_strdup(conn, "msdfs:");
1449 for(i=0; i<jucn->referral_count; i++) {
1450 char *refpath = jucn->referral_list[i].alternate_path;
1452 /* Alternate paths always use Windows separators. */
1453 trim_char(refpath, '\\', '\\');
1454 if(*refpath == '\0') {
1456 insert_comma = False;
1460 if (i > 0 && insert_comma) {
1461 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1465 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1473 if (!insert_comma) {
1474 insert_comma = True;
1478 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1481 smb_fname = synthetic_smb_fname(talloc_tos(),
1486 if (smb_fname == NULL) {
1491 if(SMB_VFS_SYMLINK(conn, msdfs_link, smb_fname) < 0) {
1492 if (errno == EEXIST) {
1493 if(SMB_VFS_UNLINK(conn, smb_fname)!=0) {
1494 TALLOC_FREE(smb_fname);
1498 if (SMB_VFS_SYMLINK(conn, msdfs_link, smb_fname) < 0) {
1499 DEBUG(1,("create_msdfs_link: symlink failed "
1500 "%s -> %s\nError: %s\n",
1501 path, msdfs_link, strerror(errno)));
1509 TALLOC_FREE(smb_fname);
1510 vfs_ChDir(conn, cwd_fname);
1511 TALLOC_FREE(cwd_fname);
1512 SMB_VFS_DISCONNECT(conn);
1517 bool remove_msdfs_link(const struct junction_map *jucn)
1520 struct smb_filename *cwd_fname = NULL;
1521 connection_struct *conn;
1523 struct smb_filename *smb_fname;
1525 if (!junction_to_local_path(jucn, &path, &conn, &cwd_fname)) {
1529 smb_fname = synthetic_smb_fname(talloc_tos(),
1534 if (smb_fname == NULL) {
1539 if( SMB_VFS_UNLINK(conn, smb_fname) == 0 ) {
1543 TALLOC_FREE(smb_fname);
1544 vfs_ChDir(conn, cwd_fname);
1545 TALLOC_FREE(cwd_fname);
1546 SMB_VFS_DISCONNECT(conn);
1551 /*********************************************************************
1552 Return the number of DFS links at the root of this share.
1553 *********************************************************************/
1555 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1559 const char *dname = NULL;
1560 char *talloced = NULL;
1561 const char *connect_path = lp_path(talloc_tos(), snum);
1562 const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum);
1563 connection_struct *conn;
1565 struct smb_filename *cwd_fname = NULL;
1566 struct smb_filename *smb_fname = NULL;
1568 if(*connect_path == '\0') {
1573 * Fake up a connection struct for the VFS layer.
1576 status = create_conn_struct_cwd(talloc_tos(),
1577 server_event_context(),
1578 server_messaging_context(),
1584 if (!NT_STATUS_IS_OK(status)) {
1585 DEBUG(3, ("create_conn_struct failed: %s\n",
1586 nt_errstr(status)));
1590 /* Count a link for the msdfs root - convention */
1593 /* No more links if this is an msdfs proxy. */
1594 if (*msdfs_proxy != '\0') {
1598 smb_fname = synthetic_smb_fname(talloc_tos(),
1603 if (smb_fname == NULL) {
1607 /* Now enumerate all dfs links */
1608 dirp = SMB_VFS_OPENDIR(conn, smb_fname, NULL, 0);
1613 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1615 struct smb_filename *smb_dname =
1616 synthetic_smb_fname(talloc_tos(),
1621 if (smb_dname == NULL) {
1624 if (is_msdfs_link(conn, smb_dname)) {
1627 TALLOC_FREE(talloced);
1628 TALLOC_FREE(smb_dname);
1631 SMB_VFS_CLOSEDIR(conn,dirp);
1634 TALLOC_FREE(smb_fname);
1635 vfs_ChDir(conn, cwd_fname);
1636 TALLOC_FREE(cwd_fname);
1637 SMB_VFS_DISCONNECT(conn);
1642 /*********************************************************************
1643 *********************************************************************/
1645 static int form_junctions(TALLOC_CTX *ctx,
1647 struct junction_map *jucn,
1652 const char *dname = NULL;
1653 char *talloced = NULL;
1654 const char *connect_path = lp_path(talloc_tos(), snum);
1655 char *service_name = lp_servicename(talloc_tos(), snum);
1656 const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum);
1657 connection_struct *conn;
1658 struct referral *ref = NULL;
1659 struct smb_filename *cwd_fname = NULL;
1660 struct smb_filename *smb_fname = NULL;
1663 if (jn_remain == 0) {
1667 if(*connect_path == '\0') {
1672 * Fake up a connection struct for the VFS layer.
1675 status = create_conn_struct_cwd(ctx,
1676 server_event_context(),
1677 server_messaging_context(),
1683 if (!NT_STATUS_IS_OK(status)) {
1684 DEBUG(3, ("create_conn_struct failed: %s\n",
1685 nt_errstr(status)));
1689 /* form a junction for the msdfs root - convention
1690 DO NOT REMOVE THIS: NT clients will not work with us
1691 if this is not present
1693 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1694 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1695 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1698 jucn[cnt].comment = "";
1699 jucn[cnt].referral_count = 1;
1701 ref = jucn[cnt].referral_list = talloc_zero(ctx, struct referral);
1702 if (jucn[cnt].referral_list == NULL) {
1707 ref->ttl = REFERRAL_TTL;
1708 if (*msdfs_proxy != '\0') {
1709 ref->alternate_path = talloc_strdup(ctx,
1712 ref->alternate_path = talloc_asprintf(ctx,
1714 get_local_machine_name(),
1718 if (!ref->alternate_path) {
1723 /* Don't enumerate if we're an msdfs proxy. */
1724 if (*msdfs_proxy != '\0') {
1728 smb_fname = synthetic_smb_fname(talloc_tos(),
1733 if (smb_fname == NULL) {
1737 /* Now enumerate all dfs links */
1738 dirp = SMB_VFS_OPENDIR(conn, smb_fname, NULL, 0);
1743 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1745 char *link_target = NULL;
1746 struct smb_filename *smb_dname = NULL;
1748 if (cnt >= jn_remain) {
1749 DEBUG(2, ("form_junctions: ran out of MSDFS "
1751 TALLOC_FREE(talloced);
1754 smb_dname = synthetic_smb_fname(talloc_tos(),
1759 if (smb_dname == NULL) {
1760 TALLOC_FREE(talloced);
1763 if (is_msdfs_link_internal(ctx,
1765 smb_dname, &link_target)) {
1766 if (parse_msdfs_symlink(ctx, snum,
1768 &jucn[cnt].referral_list,
1769 &jucn[cnt].referral_count)) {
1771 jucn[cnt].service_name = talloc_strdup(ctx,
1773 jucn[cnt].volume_name = talloc_strdup(ctx,
1775 if (!jucn[cnt].service_name ||
1776 !jucn[cnt].volume_name) {
1777 TALLOC_FREE(talloced);
1780 jucn[cnt].comment = "";
1783 TALLOC_FREE(link_target);
1785 TALLOC_FREE(talloced);
1786 TALLOC_FREE(smb_dname);
1792 SMB_VFS_CLOSEDIR(conn,dirp);
1795 TALLOC_FREE(smb_fname);
1796 vfs_ChDir(conn, cwd_fname);
1797 TALLOC_FREE(cwd_fname);
1802 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1804 struct junction_map *jn = NULL;
1806 size_t jn_count = 0;
1810 if(!lp_host_msdfs()) {
1814 /* Ensure all the usershares are loaded. */
1816 load_registry_shares();
1817 sharecount = load_usershare_shares(NULL, connections_snum_used);
1820 for(i=0;i < sharecount;i++) {
1821 if(lp_msdfs_root(i)) {
1822 jn_count += count_dfs_links(ctx, i);
1825 if (jn_count == 0) {
1828 jn = talloc_array(ctx, struct junction_map, jn_count);
1832 for(i=0; i < sharecount; i++) {
1833 if (*p_num_jn >= jn_count) {
1836 if(lp_msdfs_root(i)) {
1837 *p_num_jn += form_junctions(ctx, i,
1839 jn_count - *p_num_jn);
1845 /******************************************************************************
1846 Core function to resolve a dfs pathname possibly containing a wildcard. If
1847 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1848 detected during dfs resolution.
1849 ******************************************************************************/
1851 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1852 connection_struct *conn,
1853 const char *name_in,
1855 bool allow_broken_path,
1857 bool *ppath_contains_wcard)
1859 bool path_contains_wcard = false;
1860 NTSTATUS status = NT_STATUS_OK;
1862 status = dfs_redirect(ctx,
1868 &path_contains_wcard);
1870 if (NT_STATUS_IS_OK(status) &&
1871 ppath_contains_wcard != NULL &&
1872 path_contains_wcard) {
1873 *ppath_contains_wcard = path_contains_wcard;