2 Unix SMB/Netbios implementation.
4 MSDFS services for Samba
5 Copyright (C) Shirish Kalele 2000
6 Copyright (C) Jeremy Allison 2007
7 Copyright (C) Robin McCorkell 2015
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #define DBGC_CLASS DBGC_MSDFS
26 #include "system/filesys.h"
27 #include "smbd/smbd.h"
28 #include "smbd/globals.h"
31 #include "../auth/auth_util.h"
32 #include "lib/param/loadparm.h"
33 #include "libcli/security/security.h"
34 #include "librpc/gen_ndr/ndr_dfsblobs.h"
35 #include "lib/tsocket/tsocket.h"
36 #include "lib/pthreadpool/pthreadpool_tevent.h"
38 /**********************************************************************
39 Parse a DFS pathname of the form \hostname\service\reqpath
40 into the dfs_path structure.
41 If POSIX pathnames is true, the pathname may also be of the
42 form /hostname/service/reqpath.
43 We cope with either here.
45 Unfortunately, due to broken clients who might set the
46 SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
47 send a local path, we have to cope with that too....
49 If conn != NULL then ensure the provided service is
50 the one pointed to by the connection.
52 This version does everything using pointers within one copy of the
53 pathname string, talloced on the struct dfs_path pointer (which
54 must be talloced). This may be too clever to live....
56 **********************************************************************/
58 static NTSTATUS parse_dfs_path(connection_struct *conn,
61 bool allow_broken_path,
62 struct dfs_path *pdp, /* MUST BE TALLOCED */
63 bool *ppath_contains_wcard)
69 NTSTATUS status = NT_STATUS_OK;
75 * This is the only talloc we should need to do
76 * on the struct dfs_path. All the pointers inside
77 * it should point to offsets within this string.
80 pathname_local = talloc_strdup(pdp, pathname);
81 if (!pathname_local) {
82 return NT_STATUS_NO_MEMORY;
84 /* Get a pointer to the terminating '\0' */
85 eos_ptr = &pathname_local[strlen(pathname_local)];
86 p = temp = pathname_local;
89 * Non-broken DFS paths *must* start with the
90 * path separator. For Windows this is always '\\',
91 * for posix paths this is always '/'.
94 if (*pathname == '/') {
95 pdp->posix_path = true;
98 pdp->posix_path = false;
102 if (allow_broken_path && (*pathname != sepchar)) {
103 DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
104 pathname, sepchar ));
106 * Possibly client sent a local path by mistake.
107 * Try and convert to a local path.
108 * Note that this is an SMB1-only fallback
109 * to cope with known broken SMB1 clients.
112 pdp->hostname = eos_ptr; /* "" */
113 pdp->servicename = eos_ptr; /* "" */
115 /* We've got no info about separators. */
116 pdp->posix_path = lp_posix_pathnames();
118 DEBUG(10,("parse_dfs_path: trying to convert %s to a "
125 * Safe to use on talloc'ed string as it only shrinks.
126 * It also doesn't affect the eos_ptr.
128 trim_char(temp,sepchar,sepchar);
130 DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
134 /* Parse out hostname. */
135 p = strchr_m(temp,sepchar);
137 DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
140 * Possibly client sent a local path by mistake.
141 * Try and convert to a local path.
144 pdp->hostname = eos_ptr; /* "" */
145 pdp->servicename = eos_ptr; /* "" */
148 DEBUG(10,("parse_dfs_path: trying to convert %s "
154 pdp->hostname = temp;
156 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
158 /* Parse out servicename. */
160 p = strchr_m(servicename,sepchar);
165 /* Is this really our servicename ? */
166 if (conn && !( strequal(servicename, lp_servicename(talloc_tos(), SNUM(conn)))
167 || (strequal(servicename, HOMES_NAME)
168 && strequal(lp_servicename(talloc_tos(), SNUM(conn)),
169 get_current_username()) )) ) {
170 DEBUG(10,("parse_dfs_path: %s is not our servicename\n",
174 * Possibly client sent a local path by mistake.
175 * Try and convert to a local path.
178 pdp->hostname = eos_ptr; /* "" */
179 pdp->servicename = eos_ptr; /* "" */
181 /* Repair the path - replace the sepchar's
184 *servicename = sepchar;
190 DEBUG(10,("parse_dfs_path: trying to convert %s "
196 pdp->servicename = servicename;
198 DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
201 /* Client sent self referral \server\share. */
202 pdp->reqpath = eos_ptr; /* "" */
210 *ppath_contains_wcard = False;
214 /* Rest is reqpath. */
215 if (pdp->posix_path) {
216 status = check_path_syntax_posix(pdp->reqpath);
219 status = check_path_syntax_wcard(pdp->reqpath,
220 ppath_contains_wcard);
222 status = check_path_syntax(pdp->reqpath);
226 if (!NT_STATUS_IS_OK(status)) {
227 DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
228 p, nt_errstr(status) ));
232 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
236 /********************************************************
237 Fake up a connection struct for the VFS layer, for use in
238 applications (such as the python bindings), that do not want the
239 global working directory changed under them.
241 SMB_VFS_CONNECT requires root privileges.
242 *********************************************************/
244 static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx,
245 struct messaging_context *msg,
246 connection_struct **pconn,
249 const struct auth_session_info *session_info)
251 connection_struct *conn;
253 const char *vfs_user;
254 struct smbd_server_connection *sconn;
255 const char *servicename = lp_const_servicename(snum);
256 const struct security_unix_token *unix_token = NULL;
257 struct tevent_context *user_ev_ctx = NULL;
258 struct pthreadpool_tevent *user_tp_chdir_safe = NULL;
259 struct pthreadpool_tevent *root_tp_chdir_safe = NULL;
262 sconn = talloc_zero(ctx, struct smbd_server_connection);
264 return NT_STATUS_NO_MEMORY;
267 sconn->raw_ev_ctx = samba_tevent_context_init(sconn);
268 if (sconn->raw_ev_ctx == NULL) {
270 return NT_STATUS_NO_MEMORY;
273 sconn->root_ev_ctx = smbd_impersonate_root_create(sconn->raw_ev_ctx);
274 if (sconn->root_ev_ctx == NULL) {
276 return NT_STATUS_NO_MEMORY;
278 sconn->guest_ev_ctx = smbd_impersonate_guest_create(sconn->raw_ev_ctx);
279 if (sconn->guest_ev_ctx == NULL) {
281 return NT_STATUS_NO_MEMORY;
285 * We only provide sync threadpools.
287 ret = pthreadpool_tevent_init(sconn, 0, &sconn->sync_thread_pool);
290 return NT_STATUS_NO_MEMORY;
292 sconn->raw_thread_pool = sconn->sync_thread_pool;
294 sconn->msg_ctx = msg;
296 conn = conn_new(sconn);
299 return NT_STATUS_NO_MEMORY;
302 /* Now we have conn, we need to make sconn a child of conn,
303 * for a proper talloc tree */
304 talloc_steal(conn, sconn);
306 if (snum == -1 && servicename == NULL) {
307 servicename = "Unknown Service (snum == -1)";
310 connpath = talloc_strdup(conn, path);
313 return NT_STATUS_NO_MEMORY;
315 connpath = talloc_string_sub(conn,
321 return NT_STATUS_NO_MEMORY;
324 /* needed for smbd_vfs_init() */
326 conn->params->service = snum;
327 conn->cnum = TID_FIELD_INVALID;
329 if (session_info != NULL) {
330 conn->session_info = copy_session_info(conn, session_info);
331 if (conn->session_info == NULL) {
332 DEBUG(0, ("copy_serverinfo failed\n"));
334 return NT_STATUS_NO_MEMORY;
336 unix_token = conn->session_info->unix_token;
337 /* unix_info could be NULL in session_info */
338 if (conn->session_info->unix_info != NULL) {
339 vfs_user = conn->session_info->unix_info->unix_name;
341 vfs_user = get_current_username();
344 /* use current authenticated user in absence of session_info */
345 vfs_user = get_current_username();
348 if (unix_token == NULL) {
349 unix_token = get_current_utok(conn);
353 * The impersonation has to be done by the caller
354 * of create_conn_struct_tos[_cwd]().
356 * Note: the context can't be changed anyway
357 * as we're using our own tevent_context
358 * and not a global one were other requests
359 * could change the current unix token.
361 * We just use a wrapper tevent_context in order
362 * to avoid crashes because TALLOC_FREE(conn->user_ev_ctx)
363 * would also remove sconn->raw_ev_ctx.
365 user_ev_ctx = smbd_impersonate_debug_create(sconn->raw_ev_ctx,
366 "FAKE impersonation",
368 if (user_ev_ctx == NULL) {
370 return NT_STATUS_NO_MEMORY;
372 SMB_ASSERT(talloc_reparent(sconn->raw_ev_ctx, conn, user_ev_ctx));
374 user_tp_chdir_safe = smbd_impersonate_tp_current_create(conn,
375 sconn->sync_thread_pool,
378 true, /* chdir_safe */
380 if (user_tp_chdir_safe == NULL) {
382 return NT_STATUS_NO_MEMORY;
385 root_tp_chdir_safe = smbd_impersonate_tp_become_create(conn,
386 sconn->sync_thread_pool,
387 true, /* chdir_safe */
390 if (root_tp_chdir_safe == NULL) {
392 return NT_STATUS_NO_MEMORY;
396 * We only use the chdir_safe wrappers
397 * for everything in order to keep
400 conn->user_vfs_evg = smb_vfs_ev_glue_create(conn,
409 if (conn->user_vfs_evg == NULL) {
411 return NT_STATUS_NO_MEMORY;
414 SMB_ASSERT(talloc_reparent(conn, conn->user_vfs_evg, user_ev_ctx));
415 SMB_ASSERT(talloc_reparent(conn, conn->user_vfs_evg, user_tp_chdir_safe));
416 SMB_ASSERT(talloc_reparent(conn, conn->user_vfs_evg, root_tp_chdir_safe));
418 conn->user_ev_ctx = smb_vfs_ev_glue_ev_ctx(conn->user_vfs_evg);
419 if (conn->user_ev_ctx == NULL) {
421 return NT_STATUS_INTERNAL_ERROR;
424 set_conn_connectpath(conn, connpath);
427 * New code to check if there's a share security descriptor
428 * added from NT server manager. This is done after the
429 * smb.conf checks are done as we need a uid and token. JRA.
432 if (conn->session_info) {
433 share_access_check(conn->session_info->security_token,
435 MAXIMUM_ALLOWED_ACCESS,
436 &conn->share_access);
438 if ((conn->share_access & FILE_WRITE_DATA) == 0) {
439 if ((conn->share_access & FILE_READ_DATA) == 0) {
440 /* No access, read or write. */
441 DEBUG(3,("create_conn_struct: connection to %s "
442 "denied due to security "
446 return NT_STATUS_ACCESS_DENIED;
448 conn->read_only = true;
452 conn->share_access = 0;
453 conn->read_only = true;
456 if (!smbd_vfs_init(conn)) {
457 NTSTATUS status = map_nt_error_from_unix(errno);
458 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
463 /* this must be the first filesystem operation that we do */
464 if (SMB_VFS_CONNECT(conn, servicename, vfs_user) < 0) {
465 DEBUG(0,("VFS connect failed!\n"));
467 return NT_STATUS_UNSUCCESSFUL;
470 talloc_free(conn->origpath);
471 conn->origpath = talloc_strdup(conn, conn->connectpath);
472 if (conn->origpath == NULL) {
474 return NT_STATUS_NO_MEMORY;
477 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
478 conn->tcon_done = true;
479 *pconn = talloc_move(ctx, &conn);
484 static int conn_struct_tos_destructor(struct conn_struct_tos *c)
486 if (c->oldcwd_fname != NULL) {
487 vfs_ChDir(c->conn, c->oldcwd_fname);
488 TALLOC_FREE(c->oldcwd_fname);
490 SMB_VFS_DISCONNECT(c->conn);
495 /********************************************************
496 Fake up a connection struct for the VFS layer, for use in
497 applications (such as the python bindings), that do not want the
498 global working directory changed under them.
500 SMB_VFS_CONNECT requires root privileges.
501 This temporary uses become_root() and unbecome_root().
503 But further impersonation has to be cone by the caller.
504 *********************************************************/
505 NTSTATUS create_conn_struct_tos(struct messaging_context *msg,
508 const struct auth_session_info *session_info,
509 struct conn_struct_tos **_c)
511 struct conn_struct_tos *c = NULL;
516 c = talloc_zero(talloc_tos(), struct conn_struct_tos);
518 return NT_STATUS_NO_MEMORY;
522 status = create_conn_struct_as_root(c,
529 if (!NT_STATUS_IS_OK(status)) {
534 talloc_set_destructor(c, conn_struct_tos_destructor);
540 /********************************************************
541 Fake up a connection struct for the VFS layer.
542 Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
544 See also the comment for create_conn_struct_tos() above!
546 The CWD change is reverted by the destructor of
547 conn_struct_tos when the current talloc_tos() is destroyed.
548 *********************************************************/
549 NTSTATUS create_conn_struct_tos_cwd(struct messaging_context *msg,
552 const struct auth_session_info *session_info,
553 struct conn_struct_tos **_c)
555 struct conn_struct_tos *c = NULL;
556 struct smb_filename smb_fname_connectpath = {0};
561 status = create_conn_struct_tos(msg,
566 if (!NT_STATUS_IS_OK(status)) {
571 * Windows seems to insist on doing trans2getdfsreferral() calls on
572 * the IPC$ share as the anonymous user. If we try to chdir as that
573 * user we will fail.... WTF ? JRA.
576 c->oldcwd_fname = vfs_GetWd(c, c->conn);
577 if (c->oldcwd_fname == NULL) {
578 status = map_nt_error_from_unix(errno);
579 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
584 smb_fname_connectpath = (struct smb_filename) {
585 .base_name = c->conn->connectpath
588 if (vfs_ChDir(c->conn, &smb_fname_connectpath) != 0) {
589 status = map_nt_error_from_unix(errno);
590 DBG_NOTICE("Can't ChDir to new conn path %s. "
592 c->conn->connectpath, strerror(errno));
593 TALLOC_FREE(c->oldcwd_fname);
602 static void shuffle_strlist(char **list, int count)
608 for (i = count; i > 1; i--) {
609 r = generate_random() % i;
617 /**********************************************************************
618 Parse the contents of a symlink to verify if it is an msdfs referral
619 A valid referral is of the form:
621 msdfs:server1\share1,server2\share2
622 msdfs:server1\share1\pathname,server2\share2\pathname
623 msdfs:server1/share1,server2/share2
624 msdfs:server1/share1/pathname,server2/share2/pathname.
626 Note that the alternate paths returned here must be of the canonicalized
630 \server\share\path\to\file,
632 even in posix path mode. This is because we have no knowledge if the
633 server we're referring to understands posix paths.
634 **********************************************************************/
636 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
639 struct referral **preflist,
644 char **alt_path = NULL;
646 struct referral *reflist;
649 temp = talloc_strdup(ctx, target);
653 prot = strtok_r(temp, ":", &saveptr);
655 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
659 alt_path = talloc_array(ctx, char *, MAX_REFERRAL_COUNT);
664 /* parse out the alternate paths */
665 while((count<MAX_REFERRAL_COUNT) &&
666 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
670 /* shuffle alternate paths */
671 if (lp_msdfs_shuffle_referrals(snum)) {
672 shuffle_strlist(alt_path, count);
675 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
678 reflist = *preflist = talloc_zero_array(ctx,
679 struct referral, count);
680 if(reflist == NULL) {
681 TALLOC_FREE(alt_path);
685 reflist = *preflist = NULL;
688 for(i=0;i<count;i++) {
691 /* Canonicalize link target.
692 * Replace all /'s in the path by a \ */
693 string_replace(alt_path[i], '/', '\\');
695 /* Remove leading '\\'s */
697 while (*p && (*p == '\\')) {
701 reflist[i].alternate_path = talloc_asprintf(ctx,
704 if (!reflist[i].alternate_path) {
708 reflist[i].proximity = 0;
709 reflist[i].ttl = REFERRAL_TTL;
710 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
711 reflist[i].alternate_path));
716 TALLOC_FREE(alt_path);
720 /**********************************************************************
721 Returns true if the unix path is a valid msdfs symlink and also
722 returns the target string from inside the link.
723 **********************************************************************/
725 static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
726 connection_struct *conn,
727 struct smb_filename *smb_fname,
728 char **pp_link_target)
730 int referral_len = 0;
731 #if defined(HAVE_BROKEN_READLINK)
732 char link_target_buf[PATH_MAX];
734 char link_target_buf[7];
737 char *link_target = NULL;
739 if (pp_link_target) {
741 link_target = talloc_array(ctx, char, bufsize);
745 *pp_link_target = link_target;
747 bufsize = sizeof(link_target_buf);
748 link_target = link_target_buf;
751 if (SMB_VFS_LSTAT(conn, smb_fname) != 0) {
752 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
753 smb_fname->base_name));
756 if (!S_ISLNK(smb_fname->st.st_ex_mode)) {
757 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
758 smb_fname->base_name));
762 referral_len = SMB_VFS_READLINK(conn, smb_fname,
763 link_target, bufsize - 1);
764 if (referral_len == -1) {
765 DEBUG(0,("is_msdfs_link_read_target: Error reading "
766 "msdfs link %s: %s\n",
767 smb_fname->base_name, strerror(errno)));
770 link_target[referral_len] = '\0';
772 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n", smb_fname->base_name,
775 if (!strnequal(link_target, "msdfs:", 6)) {
782 if (link_target != link_target_buf) {
783 TALLOC_FREE(link_target);
788 /**********************************************************************
789 Returns true if the unix path is a valid msdfs symlink.
790 **********************************************************************/
792 bool is_msdfs_link(connection_struct *conn,
793 struct smb_filename *smb_fname)
795 return is_msdfs_link_internal(talloc_tos(),
801 /*****************************************************************
802 Used by other functions to decide if a dfs path is remote,
803 and to get the list of referred locations for that remote path.
805 search_flag: For findfirsts, dfs links themselves are not
806 redirected, but paths beyond the links are. For normal smb calls,
807 even dfs links need to be redirected.
809 consumedcntp: how much of the dfs path is being redirected. the client
810 should try the remaining path on the redirected server.
812 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
813 link redirect are in targetpath.
814 *****************************************************************/
816 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
817 connection_struct *conn,
818 const char *dfspath, /* Incoming complete dfs path */
819 const struct dfs_path *pdp, /* Parsed out
820 server+share+extrapath. */
823 char **pp_targetpath)
828 struct smb_filename *smb_fname = NULL;
829 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
832 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
833 conn->connectpath, pdp->reqpath));
836 * Note the unix path conversion here we're doing we
837 * throw away. We're looking for a symlink for a dfs
838 * resolution, if we don't find it we'll do another
839 * unix_convert later in the codepath.
842 status = unix_convert(ctx, conn, pdp->reqpath, &smb_fname,
845 if (!NT_STATUS_IS_OK(status)) {
846 if (!NT_STATUS_EQUAL(status,
847 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
850 if (smb_fname == NULL || smb_fname->base_name == NULL) {
855 /* Optimization - check if we can redirect the whole path. */
857 if (is_msdfs_link_internal(ctx, conn, smb_fname, pp_targetpath)) {
858 /* XX_ALLOW_WCARD_XXX is called from search functions. */
860 (UCF_COND_ALLOW_WCARD_LCOMP|
861 UCF_ALWAYS_ALLOW_WCARD_LCOMP)) {
862 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
863 "for dfs link %s.\n", dfspath));
864 status = NT_STATUS_OK;
868 DEBUG(6,("dfs_path_lookup: %s resolves to a "
869 "valid dfs link %s.\n", dfspath,
870 pp_targetpath ? *pp_targetpath : ""));
873 *consumedcntp = strlen(dfspath);
875 status = NT_STATUS_PATH_NOT_COVERED;
879 /* Prepare to test only for '/' components in the given path,
880 * so if a Windows path replace all '\\' characters with '/'.
881 * For a POSIX DFS path we know all separators are already '/'. */
883 canon_dfspath = talloc_strdup(ctx, dfspath);
884 if (!canon_dfspath) {
885 status = NT_STATUS_NO_MEMORY;
888 if (!pdp->posix_path) {
889 string_replace(canon_dfspath, '\\', '/');
893 * localpath comes out of unix_convert, so it has
894 * no trailing backslash. Make sure that canon_dfspath hasn't either.
895 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
898 trim_char(canon_dfspath,0,'/');
901 * Redirect if any component in the path is a link.
902 * We do this by walking backwards through the
903 * local path, chopping off the last component
904 * in both the local path and the canonicalized
905 * DFS path. If we hit a DFS link then we're done.
908 p = strrchr_m(smb_fname->base_name, '/');
910 q = strrchr_m(canon_dfspath, '/');
919 if (is_msdfs_link_internal(ctx, conn,
920 smb_fname, pp_targetpath)) {
921 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
922 "parent %s is dfs link\n", dfspath,
923 smb_fname_str_dbg(smb_fname)));
926 *consumedcntp = strlen(canon_dfspath);
927 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
933 status = NT_STATUS_PATH_NOT_COVERED;
937 /* Step back on the filesystem. */
938 p = strrchr_m(smb_fname->base_name, '/');
941 /* And in the canonicalized dfs path. */
942 q = strrchr_m(canon_dfspath, '/');
946 status = NT_STATUS_OK;
948 TALLOC_FREE(smb_fname);
952 /*****************************************************************
953 Decides if a dfs pathname should be redirected or not.
954 If not, the pathname is converted to a tcon-relative local unix path
956 search_wcard_flag: this flag performs 2 functions both related
957 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
960 This function can return NT_STATUS_OK, meaning use the returned path as-is
961 (mapped into a local path).
962 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
963 any other NT_STATUS error which is a genuine error to be
964 returned to the client.
965 *****************************************************************/
967 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
968 connection_struct *conn,
971 bool allow_broken_path,
973 bool *ppath_contains_wcard)
976 bool search_wcard_flag = (ucf_flags &
977 (UCF_COND_ALLOW_WCARD_LCOMP|UCF_ALWAYS_ALLOW_WCARD_LCOMP));
978 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
981 return NT_STATUS_NO_MEMORY;
984 status = parse_dfs_path(conn, path_in, search_wcard_flag,
985 allow_broken_path, pdp,
986 ppath_contains_wcard);
987 if (!NT_STATUS_IS_OK(status)) {
992 if (pdp->reqpath[0] == '\0') {
994 *pp_path_out = talloc_strdup(ctx, "");
996 return NT_STATUS_NO_MEMORY;
998 DEBUG(5,("dfs_redirect: self-referral.\n"));
1002 /* If dfs pathname for a non-dfs share, convert to tcon-relative
1003 path and return OK */
1005 if (!lp_msdfs_root(SNUM(conn))) {
1006 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
1008 if (!*pp_path_out) {
1009 return NT_STATUS_NO_MEMORY;
1011 return NT_STATUS_OK;
1014 /* If it looked like a local path (zero hostname/servicename)
1015 * just treat as a tcon-relative path. */
1017 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
1018 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
1020 if (!*pp_path_out) {
1021 return NT_STATUS_NO_MEMORY;
1023 return NT_STATUS_OK;
1026 if (!( strequal(pdp->servicename, lp_servicename(talloc_tos(), SNUM(conn)))
1027 || (strequal(pdp->servicename, HOMES_NAME)
1028 && strequal(lp_servicename(talloc_tos(), SNUM(conn)),
1029 conn->session_info->unix_info->sanitized_username) )) ) {
1031 /* The given sharename doesn't match this connection. */
1034 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1037 status = dfs_path_lookup(ctx, conn, path_in, pdp,
1038 ucf_flags, NULL, NULL);
1039 if (!NT_STATUS_IS_OK(status)) {
1040 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
1041 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
1043 DEBUG(10,("dfs_redirect: dfs_path_lookup "
1044 "failed for %s with %s\n",
1045 path_in, nt_errstr(status) ));
1050 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
1052 /* Form non-dfs tcon-relative path */
1053 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
1055 if (!*pp_path_out) {
1056 return NT_STATUS_NO_MEMORY;
1059 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
1063 return NT_STATUS_OK;
1066 /**********************************************************************
1067 Return a self referral.
1068 **********************************************************************/
1070 static NTSTATUS self_ref(TALLOC_CTX *ctx,
1071 const char *dfs_path,
1072 struct junction_map *jucn,
1074 bool *self_referralp)
1076 struct referral *ref;
1078 *self_referralp = True;
1080 jucn->referral_count = 1;
1081 if((ref = talloc_zero(ctx, struct referral)) == NULL) {
1082 return NT_STATUS_NO_MEMORY;
1085 ref->alternate_path = talloc_strdup(ctx, dfs_path);
1086 if (!ref->alternate_path) {
1088 return NT_STATUS_NO_MEMORY;
1091 ref->ttl = REFERRAL_TTL;
1092 jucn->referral_list = ref;
1093 *consumedcntp = strlen(dfs_path);
1094 return NT_STATUS_OK;
1097 /**********************************************************************
1098 Gets valid referrals for a dfs path and fills up the
1099 junction_map structure.
1100 **********************************************************************/
1102 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
1103 const char *dfs_path,
1104 const struct tsocket_address *remote_address,
1105 const struct tsocket_address *local_address,
1106 bool allow_broken_path,
1107 struct junction_map *jucn,
1109 bool *self_referralp)
1111 TALLOC_CTX *frame = talloc_stackframe();
1112 struct conn_struct_tos *c = NULL;
1113 struct connection_struct *conn = NULL;
1114 char *targetpath = NULL;
1116 NTSTATUS status = NT_STATUS_NOT_FOUND;
1118 struct dfs_path *pdp = talloc_zero(frame, struct dfs_path);
1122 return NT_STATUS_NO_MEMORY;
1125 *self_referralp = False;
1127 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1129 if (!NT_STATUS_IS_OK(status)) {
1134 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1135 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1136 if (!jucn->service_name || !jucn->volume_name) {
1138 return NT_STATUS_NO_MEMORY;
1141 /* Verify the share is a dfs root */
1142 snum = lp_servicenumber(jucn->service_name);
1144 char *service_name = NULL;
1145 if ((snum = find_service(ctx, jucn->service_name, &service_name)) < 0) {
1147 return NT_STATUS_NOT_FOUND;
1149 if (!service_name) {
1151 return NT_STATUS_NO_MEMORY;
1153 TALLOC_FREE(jucn->service_name);
1154 jucn->service_name = talloc_strdup(ctx, service_name);
1155 if (!jucn->service_name) {
1157 return NT_STATUS_NO_MEMORY;
1161 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(talloc_tos(), snum) == '\0')) {
1162 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
1164 pdp->servicename, dfs_path));
1166 return NT_STATUS_NOT_FOUND;
1170 * Self referrals are tested with a anonymous IPC connection and
1171 * a GET_DFS_REFERRAL call to \\server\share. (which means
1172 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
1173 * into the directory and will fail if it cannot (as the anonymous
1174 * user). Cope with this.
1177 if (pdp->reqpath[0] == '\0') {
1179 struct referral *ref;
1182 if (*lp_msdfs_proxy(talloc_tos(), snum) == '\0') {
1184 return self_ref(ctx,
1192 * It's an msdfs proxy share. Redirect to
1193 * the configured target share.
1196 tmp = talloc_asprintf(frame, "msdfs:%s",
1197 lp_msdfs_proxy(frame, snum));
1200 return NT_STATUS_NO_MEMORY;
1203 if (!parse_msdfs_symlink(ctx, snum, tmp, &ref, &refcount)) {
1205 return NT_STATUS_INVALID_PARAMETER;
1207 jucn->referral_count = refcount;
1208 jucn->referral_list = ref;
1209 *consumedcntp = strlen(dfs_path);
1211 return NT_STATUS_OK;
1214 status = create_conn_struct_tos_cwd(global_messaging_context(),
1216 lp_path(frame, snum),
1219 if (!NT_STATUS_IS_OK(status)) {
1228 * The remote and local address should be passed down to
1229 * create_conn_struct_cwd.
1231 if (conn->sconn->remote_address == NULL) {
1232 conn->sconn->remote_address =
1233 tsocket_address_copy(remote_address, conn->sconn);
1234 if (conn->sconn->remote_address == NULL) {
1236 return NT_STATUS_NO_MEMORY;
1239 if (conn->sconn->local_address == NULL) {
1240 conn->sconn->local_address =
1241 tsocket_address_copy(local_address, conn->sconn);
1242 if (conn->sconn->local_address == NULL) {
1244 return NT_STATUS_NO_MEMORY;
1248 /* If this is a DFS path dfs_lookup should return
1249 * NT_STATUS_PATH_NOT_COVERED. */
1251 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
1252 0, consumedcntp, &targetpath);
1254 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
1255 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
1257 if (NT_STATUS_IS_OK(status)) {
1259 * We are in an error path here (we
1260 * know it's not a DFS path), but
1261 * dfs_path_lookup() can return
1262 * NT_STATUS_OK. Ensure we always
1263 * return a valid error code.
1265 * #9588 - ACLs are not inherited to directories
1268 status = NT_STATUS_NOT_FOUND;
1273 /* We know this is a valid dfs link. Parse the targetpath. */
1274 if (!parse_msdfs_symlink(ctx, snum, targetpath,
1275 &jucn->referral_list,
1276 &jucn->referral_count)) {
1277 DEBUG(3,("get_referred_path: failed to parse symlink "
1278 "target %s\n", targetpath ));
1279 status = NT_STATUS_NOT_FOUND;
1283 status = NT_STATUS_OK;
1289 /******************************************************************
1290 Set up the DFS referral for the dfs pathname. This call returns
1291 the amount of the path covered by this server, and where the
1292 client should be redirected to. This is the meat of the
1293 TRANS2_GET_DFS_REFERRAL call.
1294 ******************************************************************/
1296 int setup_dfs_referral(connection_struct *orig_conn,
1297 const char *dfs_path,
1298 int max_referral_level,
1299 char **ppdata, NTSTATUS *pstatus)
1301 char *pdata = *ppdata;
1303 struct dfs_GetDFSReferral *r;
1304 DATA_BLOB blob = data_blob_null;
1306 enum ndr_err_code ndr_err;
1308 r = talloc_zero(talloc_tos(), struct dfs_GetDFSReferral);
1310 *pstatus = NT_STATUS_NO_MEMORY;
1314 r->in.req.max_referral_level = max_referral_level;
1315 r->in.req.servername = talloc_strdup(r, dfs_path);
1316 if (r->in.req.servername == NULL) {
1318 *pstatus = NT_STATUS_NO_MEMORY;
1322 status = SMB_VFS_GET_DFS_REFERRALS(orig_conn, r);
1323 if (!NT_STATUS_IS_OK(status)) {
1329 ndr_err = ndr_push_struct_blob(&blob, r,
1331 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1332 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1334 *pstatus = NT_STATUS_INVALID_PARAMETER;
1338 pdata = (char *)SMB_REALLOC(pdata, blob.length);
1341 DEBUG(0,("referral setup:"
1342 "malloc failed for Realloc!\n"));
1346 reply_size = blob.length;
1347 memcpy(pdata, blob.data, blob.length);
1350 *pstatus = NT_STATUS_OK;
1354 /**********************************************************************
1355 The following functions are called by the NETDFS RPC pipe functions
1356 **********************************************************************/
1358 /*********************************************************************
1359 Creates a junction structure from a DFS pathname
1360 **********************************************************************/
1362 bool create_junction(TALLOC_CTX *ctx,
1363 const char *dfs_path,
1364 bool allow_broken_path,
1365 struct junction_map *jucn)
1369 struct dfs_path *pdp = talloc(ctx,struct dfs_path);
1375 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1377 if (!NT_STATUS_IS_OK(status)) {
1381 /* check if path is dfs : validate first token */
1382 if (!is_myname_or_ipaddr(pdp->hostname)) {
1383 DEBUG(4,("create_junction: Invalid hostname %s "
1385 pdp->hostname, dfs_path));
1390 /* Check for a non-DFS share */
1391 snum = lp_servicenumber(pdp->servicename);
1393 if(snum < 0 || !lp_msdfs_root(snum)) {
1394 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1400 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1401 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1402 jucn->comment = lp_comment(ctx, snum);
1405 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1411 /**********************************************************************
1412 Forms a valid Unix pathname from the junction
1413 **********************************************************************/
1415 static bool junction_to_local_path_tos(const struct junction_map *jucn,
1417 connection_struct **conn_out)
1419 struct conn_struct_tos *c = NULL;
1421 char *path_out = NULL;
1424 snum = lp_servicenumber(jucn->service_name);
1428 status = create_conn_struct_tos_cwd(global_messaging_context(),
1430 lp_path(talloc_tos(), snum),
1433 if (!NT_STATUS_IS_OK(status)) {
1437 path_out = talloc_asprintf(c,
1439 lp_path(talloc_tos(), snum),
1441 if (path_out == NULL) {
1445 *pp_path_out = path_out;
1446 *conn_out = c->conn;
1450 bool create_msdfs_link(const struct junction_map *jucn)
1452 TALLOC_CTX *frame = talloc_stackframe();
1454 char *msdfs_link = NULL;
1455 connection_struct *conn;
1457 bool insert_comma = False;
1459 struct smb_filename *smb_fname = NULL;
1462 ok = junction_to_local_path_tos(jucn, &path, &conn);
1468 /* Form the msdfs_link contents */
1469 msdfs_link = talloc_strdup(conn, "msdfs:");
1473 for(i=0; i<jucn->referral_count; i++) {
1474 char *refpath = jucn->referral_list[i].alternate_path;
1476 /* Alternate paths always use Windows separators. */
1477 trim_char(refpath, '\\', '\\');
1478 if(*refpath == '\0') {
1480 insert_comma = False;
1484 if (i > 0 && insert_comma) {
1485 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1489 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1497 if (!insert_comma) {
1498 insert_comma = True;
1502 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1505 smb_fname = synthetic_smb_fname(frame,
1510 if (smb_fname == NULL) {
1515 if(SMB_VFS_SYMLINK(conn, msdfs_link, smb_fname) < 0) {
1516 if (errno == EEXIST) {
1517 if(SMB_VFS_UNLINK(conn, smb_fname)!=0) {
1518 TALLOC_FREE(smb_fname);
1522 if (SMB_VFS_SYMLINK(conn, msdfs_link, smb_fname) < 0) {
1523 DEBUG(1,("create_msdfs_link: symlink failed "
1524 "%s -> %s\nError: %s\n",
1525 path, msdfs_link, strerror(errno)));
1537 bool remove_msdfs_link(const struct junction_map *jucn)
1539 TALLOC_CTX *frame = talloc_stackframe();
1541 connection_struct *conn;
1543 struct smb_filename *smb_fname;
1546 ok = junction_to_local_path_tos(jucn, &path, &conn);
1552 smb_fname = synthetic_smb_fname(frame,
1557 if (smb_fname == NULL) {
1563 if( SMB_VFS_UNLINK(conn, smb_fname) == 0 ) {
1571 /*********************************************************************
1572 Return the number of DFS links at the root of this share.
1573 *********************************************************************/
1575 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1577 TALLOC_CTX *frame = talloc_stackframe();
1580 const char *dname = NULL;
1581 char *talloced = NULL;
1582 const char *connect_path = lp_path(frame, snum);
1583 const char *msdfs_proxy = lp_msdfs_proxy(frame, snum);
1584 struct conn_struct_tos *c = NULL;
1585 connection_struct *conn = NULL;
1587 struct smb_filename *smb_fname = NULL;
1589 if(*connect_path == '\0') {
1595 * Fake up a connection struct for the VFS layer.
1598 status = create_conn_struct_tos_cwd(global_messaging_context(),
1603 if (!NT_STATUS_IS_OK(status)) {
1604 DEBUG(3, ("create_conn_struct failed: %s\n",
1605 nt_errstr(status)));
1611 /* Count a link for the msdfs root - convention */
1614 /* No more links if this is an msdfs proxy. */
1615 if (*msdfs_proxy != '\0') {
1619 smb_fname = synthetic_smb_fname(frame,
1624 if (smb_fname == NULL) {
1628 /* Now enumerate all dfs links */
1629 dirp = SMB_VFS_OPENDIR(conn, smb_fname, NULL, 0);
1634 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1636 struct smb_filename *smb_dname =
1637 synthetic_smb_fname(frame,
1642 if (smb_dname == NULL) {
1645 if (is_msdfs_link(conn, smb_dname)) {
1648 TALLOC_FREE(talloced);
1649 TALLOC_FREE(smb_dname);
1652 SMB_VFS_CLOSEDIR(conn,dirp);
1659 /*********************************************************************
1660 *********************************************************************/
1662 static int form_junctions(TALLOC_CTX *ctx,
1664 struct junction_map *jucn,
1667 TALLOC_CTX *frame = talloc_stackframe();
1670 const char *dname = NULL;
1671 char *talloced = NULL;
1672 const char *connect_path = lp_path(frame, snum);
1673 char *service_name = lp_servicename(frame, snum);
1674 const char *msdfs_proxy = lp_msdfs_proxy(frame, snum);
1675 struct conn_struct_tos *c = NULL;
1676 connection_struct *conn = NULL;
1677 struct referral *ref = NULL;
1678 struct smb_filename *smb_fname = NULL;
1681 if (jn_remain == 0) {
1686 if(*connect_path == '\0') {
1692 * Fake up a connection struct for the VFS layer.
1695 status = create_conn_struct_tos_cwd(global_messaging_context(),
1700 if (!NT_STATUS_IS_OK(status)) {
1701 DEBUG(3, ("create_conn_struct failed: %s\n",
1702 nt_errstr(status)));
1708 /* form a junction for the msdfs root - convention
1709 DO NOT REMOVE THIS: NT clients will not work with us
1710 if this is not present
1712 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1713 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1714 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1717 jucn[cnt].comment = "";
1718 jucn[cnt].referral_count = 1;
1720 ref = jucn[cnt].referral_list = talloc_zero(ctx, struct referral);
1721 if (jucn[cnt].referral_list == NULL) {
1726 ref->ttl = REFERRAL_TTL;
1727 if (*msdfs_proxy != '\0') {
1728 ref->alternate_path = talloc_strdup(ctx,
1731 ref->alternate_path = talloc_asprintf(ctx,
1733 get_local_machine_name(),
1737 if (!ref->alternate_path) {
1742 /* Don't enumerate if we're an msdfs proxy. */
1743 if (*msdfs_proxy != '\0') {
1747 smb_fname = synthetic_smb_fname(frame,
1752 if (smb_fname == NULL) {
1756 /* Now enumerate all dfs links */
1757 dirp = SMB_VFS_OPENDIR(conn, smb_fname, NULL, 0);
1762 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1764 char *link_target = NULL;
1765 struct smb_filename *smb_dname = NULL;
1767 if (cnt >= jn_remain) {
1768 DEBUG(2, ("form_junctions: ran out of MSDFS "
1770 TALLOC_FREE(talloced);
1773 smb_dname = synthetic_smb_fname(talloc_tos(),
1778 if (smb_dname == NULL) {
1779 TALLOC_FREE(talloced);
1782 if (is_msdfs_link_internal(ctx,
1784 smb_dname, &link_target)) {
1785 if (parse_msdfs_symlink(ctx, snum,
1787 &jucn[cnt].referral_list,
1788 &jucn[cnt].referral_count)) {
1790 jucn[cnt].service_name = talloc_strdup(ctx,
1792 jucn[cnt].volume_name = talloc_strdup(ctx,
1794 if (!jucn[cnt].service_name ||
1795 !jucn[cnt].volume_name) {
1796 TALLOC_FREE(talloced);
1799 jucn[cnt].comment = "";
1802 TALLOC_FREE(link_target);
1804 TALLOC_FREE(talloced);
1805 TALLOC_FREE(smb_dname);
1811 SMB_VFS_CLOSEDIR(conn,dirp);
1818 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1820 struct junction_map *jn = NULL;
1822 size_t jn_count = 0;
1826 if(!lp_host_msdfs()) {
1830 /* Ensure all the usershares are loaded. */
1832 load_registry_shares();
1833 sharecount = load_usershare_shares(NULL, connections_snum_used);
1836 for(i=0;i < sharecount;i++) {
1837 if(lp_msdfs_root(i)) {
1838 jn_count += count_dfs_links(ctx, i);
1841 if (jn_count == 0) {
1844 jn = talloc_array(ctx, struct junction_map, jn_count);
1848 for(i=0; i < sharecount; i++) {
1849 if (*p_num_jn >= jn_count) {
1852 if(lp_msdfs_root(i)) {
1853 *p_num_jn += form_junctions(ctx, i,
1855 jn_count - *p_num_jn);
1861 /******************************************************************************
1862 Core function to resolve a dfs pathname possibly containing a wildcard. If
1863 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1864 detected during dfs resolution.
1865 ******************************************************************************/
1867 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1868 connection_struct *conn,
1869 const char *name_in,
1871 bool allow_broken_path,
1873 bool *ppath_contains_wcard)
1875 bool path_contains_wcard = false;
1876 NTSTATUS status = NT_STATUS_OK;
1878 status = dfs_redirect(ctx,
1884 &path_contains_wcard);
1886 if (NT_STATUS_IS_OK(status) &&
1887 ppath_contains_wcard != NULL &&
1888 path_contains_wcard) {
1889 *ppath_contains_wcard = path_contains_wcard;