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 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;
260 sconn->raw_ev_ctx = samba_tevent_context_init(sconn);
261 if (sconn->raw_ev_ctx == NULL) {
263 return NT_STATUS_NO_MEMORY;
266 sconn->ev_ctx = sconn->raw_ev_ctx;
267 sconn->root_ev_ctx = sconn->raw_ev_ctx;
268 sconn->guest_ev_ctx = sconn->raw_ev_ctx;
269 sconn->msg_ctx = msg;
271 conn = conn_new(sconn);
274 return NT_STATUS_NO_MEMORY;
277 /* Now we have conn, we need to make sconn a child of conn,
278 * for a proper talloc tree */
279 talloc_steal(conn, sconn);
281 if (snum == -1 && servicename == NULL) {
282 servicename = "Unknown Service (snum == -1)";
285 connpath = talloc_strdup(conn, path);
288 return NT_STATUS_NO_MEMORY;
290 connpath = talloc_string_sub(conn,
296 return NT_STATUS_NO_MEMORY;
299 /* needed for smbd_vfs_init() */
301 conn->params->service = snum;
302 conn->cnum = TID_FIELD_INVALID;
304 if (session_info != NULL) {
305 conn->session_info = copy_session_info(conn, session_info);
306 if (conn->session_info == NULL) {
307 DEBUG(0, ("copy_serverinfo failed\n"));
309 return NT_STATUS_NO_MEMORY;
311 vfs_user = conn->session_info->unix_info->unix_name;
313 /* use current authenticated user in absence of session_info */
314 vfs_user = get_current_username();
317 set_conn_connectpath(conn, connpath);
320 * New code to check if there's a share security descriptor
321 * added from NT server manager. This is done after the
322 * smb.conf checks are done as we need a uid and token. JRA.
325 if (conn->session_info) {
326 share_access_check(conn->session_info->security_token,
328 MAXIMUM_ALLOWED_ACCESS,
329 &conn->share_access);
331 if ((conn->share_access & FILE_WRITE_DATA) == 0) {
332 if ((conn->share_access & FILE_READ_DATA) == 0) {
333 /* No access, read or write. */
334 DEBUG(3,("create_conn_struct: connection to %s "
335 "denied due to security "
339 return NT_STATUS_ACCESS_DENIED;
341 conn->read_only = true;
345 conn->share_access = 0;
346 conn->read_only = true;
349 if (!smbd_vfs_init(conn)) {
350 NTSTATUS status = map_nt_error_from_unix(errno);
351 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
356 /* this must be the first filesystem operation that we do */
357 if (SMB_VFS_CONNECT(conn, servicename, vfs_user) < 0) {
358 DEBUG(0,("VFS connect failed!\n"));
360 return NT_STATUS_UNSUCCESSFUL;
363 talloc_free(conn->origpath);
364 conn->origpath = talloc_strdup(conn, conn->connectpath);
365 if (conn->origpath == NULL) {
367 return NT_STATUS_NO_MEMORY;
370 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
371 conn->tcon_done = true;
372 *pconn = talloc_move(ctx, &conn);
377 static int conn_struct_tos_destructor(struct conn_struct_tos *c)
379 if (c->oldcwd_fname != NULL) {
380 vfs_ChDir(c->conn, c->oldcwd_fname);
381 TALLOC_FREE(c->oldcwd_fname);
383 SMB_VFS_DISCONNECT(c->conn);
388 /********************************************************
389 Fake up a connection struct for the VFS layer, for use in
390 applications (such as the python bindings), that do not want the
391 global working directory changed under them.
393 SMB_VFS_CONNECT requires root privileges.
394 This temporary uses become_root() and unbecome_root().
396 But further impersonation has to be cone by the caller.
397 *********************************************************/
398 NTSTATUS create_conn_struct_tos(struct messaging_context *msg,
401 const struct auth_session_info *session_info,
402 struct conn_struct_tos **_c)
404 struct conn_struct_tos *c = NULL;
409 c = talloc_zero(talloc_tos(), struct conn_struct_tos);
411 return NT_STATUS_NO_MEMORY;
415 status = create_conn_struct_as_root(c,
422 if (!NT_STATUS_IS_OK(status)) {
427 talloc_set_destructor(c, conn_struct_tos_destructor);
433 /********************************************************
434 Fake up a connection struct for the VFS layer.
435 Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
437 See also the comment for create_conn_struct_tos() above!
439 The CWD change is reverted by the destructor of
440 conn_struct_tos when the current talloc_tos() is destroyed.
441 *********************************************************/
442 NTSTATUS create_conn_struct_tos_cwd(struct messaging_context *msg,
445 const struct auth_session_info *session_info,
446 struct conn_struct_tos **_c)
448 struct conn_struct_tos *c = NULL;
449 struct smb_filename smb_fname_connectpath = {0};
454 status = create_conn_struct_tos(msg,
459 if (!NT_STATUS_IS_OK(status)) {
464 * Windows seems to insist on doing trans2getdfsreferral() calls on
465 * the IPC$ share as the anonymous user. If we try to chdir as that
466 * user we will fail.... WTF ? JRA.
469 c->oldcwd_fname = vfs_GetWd(c, c->conn);
470 if (c->oldcwd_fname == NULL) {
471 status = map_nt_error_from_unix(errno);
472 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
477 smb_fname_connectpath = (struct smb_filename) {
478 .base_name = c->conn->connectpath
481 if (vfs_ChDir(c->conn, &smb_fname_connectpath) != 0) {
482 status = map_nt_error_from_unix(errno);
483 DBG_NOTICE("Can't ChDir to new conn path %s. "
485 c->conn->connectpath, strerror(errno));
486 TALLOC_FREE(c->oldcwd_fname);
495 static void shuffle_strlist(char **list, int count)
501 for (i = count; i > 1; i--) {
502 r = generate_random() % i;
510 /**********************************************************************
511 Parse the contents of a symlink to verify if it is an msdfs referral
512 A valid referral is of the form:
514 msdfs:server1\share1,server2\share2
515 msdfs:server1\share1\pathname,server2\share2\pathname
516 msdfs:server1/share1,server2/share2
517 msdfs:server1/share1/pathname,server2/share2/pathname.
519 Note that the alternate paths returned here must be of the canonicalized
523 \server\share\path\to\file,
525 even in posix path mode. This is because we have no knowledge if the
526 server we're referring to understands posix paths.
527 **********************************************************************/
529 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
532 struct referral **preflist,
537 char **alt_path = NULL;
539 struct referral *reflist;
542 temp = talloc_strdup(ctx, target);
546 prot = strtok_r(temp, ":", &saveptr);
548 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
552 alt_path = talloc_array(ctx, char *, MAX_REFERRAL_COUNT);
557 /* parse out the alternate paths */
558 while((count<MAX_REFERRAL_COUNT) &&
559 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
563 /* shuffle alternate paths */
564 if (lp_msdfs_shuffle_referrals(snum)) {
565 shuffle_strlist(alt_path, count);
568 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
571 reflist = *preflist = talloc_zero_array(ctx,
572 struct referral, count);
573 if(reflist == NULL) {
574 TALLOC_FREE(alt_path);
578 reflist = *preflist = NULL;
581 for(i=0;i<count;i++) {
584 /* Canonicalize link target.
585 * Replace all /'s in the path by a \ */
586 string_replace(alt_path[i], '/', '\\');
588 /* Remove leading '\\'s */
590 while (*p && (*p == '\\')) {
594 reflist[i].alternate_path = talloc_asprintf(ctx,
597 if (!reflist[i].alternate_path) {
601 reflist[i].proximity = 0;
602 reflist[i].ttl = REFERRAL_TTL;
603 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
604 reflist[i].alternate_path));
609 TALLOC_FREE(alt_path);
613 /**********************************************************************
614 Returns true if the unix path is a valid msdfs symlink and also
615 returns the target string from inside the link.
616 **********************************************************************/
618 static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
619 connection_struct *conn,
620 struct smb_filename *smb_fname,
621 char **pp_link_target)
623 int referral_len = 0;
624 #if defined(HAVE_BROKEN_READLINK)
625 char link_target_buf[PATH_MAX];
627 char link_target_buf[7];
630 char *link_target = NULL;
632 if (pp_link_target) {
634 link_target = talloc_array(ctx, char, bufsize);
638 *pp_link_target = link_target;
640 bufsize = sizeof(link_target_buf);
641 link_target = link_target_buf;
644 if (SMB_VFS_LSTAT(conn, smb_fname) != 0) {
645 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
646 smb_fname->base_name));
649 if (!S_ISLNK(smb_fname->st.st_ex_mode)) {
650 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
651 smb_fname->base_name));
655 referral_len = SMB_VFS_READLINK(conn, smb_fname,
656 link_target, bufsize - 1);
657 if (referral_len == -1) {
658 DEBUG(0,("is_msdfs_link_read_target: Error reading "
659 "msdfs link %s: %s\n",
660 smb_fname->base_name, strerror(errno)));
663 link_target[referral_len] = '\0';
665 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n", smb_fname->base_name,
668 if (!strnequal(link_target, "msdfs:", 6)) {
675 if (link_target != link_target_buf) {
676 TALLOC_FREE(link_target);
681 /**********************************************************************
682 Returns true if the unix path is a valid msdfs symlink.
683 **********************************************************************/
685 bool is_msdfs_link(connection_struct *conn,
686 struct smb_filename *smb_fname)
688 return is_msdfs_link_internal(talloc_tos(),
694 /*****************************************************************
695 Used by other functions to decide if a dfs path is remote,
696 and to get the list of referred locations for that remote path.
698 search_flag: For findfirsts, dfs links themselves are not
699 redirected, but paths beyond the links are. For normal smb calls,
700 even dfs links need to be redirected.
702 consumedcntp: how much of the dfs path is being redirected. the client
703 should try the remaining path on the redirected server.
705 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
706 link redirect are in targetpath.
707 *****************************************************************/
709 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
710 connection_struct *conn,
711 const char *dfspath, /* Incoming complete dfs path */
712 const struct dfs_path *pdp, /* Parsed out
713 server+share+extrapath. */
716 char **pp_targetpath)
721 struct smb_filename *smb_fname = NULL;
722 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
725 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
726 conn->connectpath, pdp->reqpath));
729 * Note the unix path conversion here we're doing we
730 * throw away. We're looking for a symlink for a dfs
731 * resolution, if we don't find it we'll do another
732 * unix_convert later in the codepath.
735 status = unix_convert(ctx, conn, pdp->reqpath, &smb_fname,
738 if (!NT_STATUS_IS_OK(status)) {
739 if (!NT_STATUS_EQUAL(status,
740 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
743 if (smb_fname == NULL || smb_fname->base_name == NULL) {
748 /* Optimization - check if we can redirect the whole path. */
750 if (is_msdfs_link_internal(ctx, conn, smb_fname, pp_targetpath)) {
751 /* XX_ALLOW_WCARD_XXX is called from search functions. */
753 (UCF_COND_ALLOW_WCARD_LCOMP|
754 UCF_ALWAYS_ALLOW_WCARD_LCOMP)) {
755 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
756 "for dfs link %s.\n", dfspath));
757 status = NT_STATUS_OK;
761 DEBUG(6,("dfs_path_lookup: %s resolves to a "
762 "valid dfs link %s.\n", dfspath,
763 pp_targetpath ? *pp_targetpath : ""));
766 *consumedcntp = strlen(dfspath);
768 status = NT_STATUS_PATH_NOT_COVERED;
772 /* Prepare to test only for '/' components in the given path,
773 * so if a Windows path replace all '\\' characters with '/'.
774 * For a POSIX DFS path we know all separators are already '/'. */
776 canon_dfspath = talloc_strdup(ctx, dfspath);
777 if (!canon_dfspath) {
778 status = NT_STATUS_NO_MEMORY;
781 if (!pdp->posix_path) {
782 string_replace(canon_dfspath, '\\', '/');
786 * localpath comes out of unix_convert, so it has
787 * no trailing backslash. Make sure that canon_dfspath hasn't either.
788 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
791 trim_char(canon_dfspath,0,'/');
794 * Redirect if any component in the path is a link.
795 * We do this by walking backwards through the
796 * local path, chopping off the last component
797 * in both the local path and the canonicalized
798 * DFS path. If we hit a DFS link then we're done.
801 p = strrchr_m(smb_fname->base_name, '/');
803 q = strrchr_m(canon_dfspath, '/');
812 if (is_msdfs_link_internal(ctx, conn,
813 smb_fname, pp_targetpath)) {
814 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
815 "parent %s is dfs link\n", dfspath,
816 smb_fname_str_dbg(smb_fname)));
819 *consumedcntp = strlen(canon_dfspath);
820 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
826 status = NT_STATUS_PATH_NOT_COVERED;
830 /* Step back on the filesystem. */
831 p = strrchr_m(smb_fname->base_name, '/');
834 /* And in the canonicalized dfs path. */
835 q = strrchr_m(canon_dfspath, '/');
839 status = NT_STATUS_OK;
841 TALLOC_FREE(smb_fname);
845 /*****************************************************************
846 Decides if a dfs pathname should be redirected or not.
847 If not, the pathname is converted to a tcon-relative local unix path
849 search_wcard_flag: this flag performs 2 functions both related
850 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
853 This function can return NT_STATUS_OK, meaning use the returned path as-is
854 (mapped into a local path).
855 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
856 any other NT_STATUS error which is a genuine error to be
857 returned to the client.
858 *****************************************************************/
860 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
861 connection_struct *conn,
864 bool allow_broken_path,
866 bool *ppath_contains_wcard)
869 bool search_wcard_flag = (ucf_flags &
870 (UCF_COND_ALLOW_WCARD_LCOMP|UCF_ALWAYS_ALLOW_WCARD_LCOMP));
871 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
874 return NT_STATUS_NO_MEMORY;
877 status = parse_dfs_path(conn, path_in, search_wcard_flag,
878 allow_broken_path, pdp,
879 ppath_contains_wcard);
880 if (!NT_STATUS_IS_OK(status)) {
885 if (pdp->reqpath[0] == '\0') {
887 *pp_path_out = talloc_strdup(ctx, "");
889 return NT_STATUS_NO_MEMORY;
891 DEBUG(5,("dfs_redirect: self-referral.\n"));
895 /* If dfs pathname for a non-dfs share, convert to tcon-relative
896 path and return OK */
898 if (!lp_msdfs_root(SNUM(conn))) {
899 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
902 return NT_STATUS_NO_MEMORY;
907 /* If it looked like a local path (zero hostname/servicename)
908 * just treat as a tcon-relative path. */
910 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
911 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
914 return NT_STATUS_NO_MEMORY;
919 if (!( strequal(pdp->servicename, lp_servicename(talloc_tos(), SNUM(conn)))
920 || (strequal(pdp->servicename, HOMES_NAME)
921 && strequal(lp_servicename(talloc_tos(), SNUM(conn)),
922 conn->session_info->unix_info->sanitized_username) )) ) {
924 /* The given sharename doesn't match this connection. */
927 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
930 status = dfs_path_lookup(ctx, conn, path_in, pdp,
931 ucf_flags, NULL, NULL);
932 if (!NT_STATUS_IS_OK(status)) {
933 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
934 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
936 DEBUG(10,("dfs_redirect: dfs_path_lookup "
937 "failed for %s with %s\n",
938 path_in, nt_errstr(status) ));
943 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
945 /* Form non-dfs tcon-relative path */
946 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
949 return NT_STATUS_NO_MEMORY;
952 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
959 /**********************************************************************
960 Return a self referral.
961 **********************************************************************/
963 static NTSTATUS self_ref(TALLOC_CTX *ctx,
964 const char *dfs_path,
965 struct junction_map *jucn,
967 bool *self_referralp)
969 struct referral *ref;
971 *self_referralp = True;
973 jucn->referral_count = 1;
974 if((ref = talloc_zero(ctx, struct referral)) == NULL) {
975 return NT_STATUS_NO_MEMORY;
978 ref->alternate_path = talloc_strdup(ctx, dfs_path);
979 if (!ref->alternate_path) {
981 return NT_STATUS_NO_MEMORY;
984 ref->ttl = REFERRAL_TTL;
985 jucn->referral_list = ref;
986 *consumedcntp = strlen(dfs_path);
990 /**********************************************************************
991 Gets valid referrals for a dfs path and fills up the
992 junction_map structure.
993 **********************************************************************/
995 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
996 const char *dfs_path,
997 const struct tsocket_address *remote_address,
998 const struct tsocket_address *local_address,
999 bool allow_broken_path,
1000 struct junction_map *jucn,
1002 bool *self_referralp)
1004 TALLOC_CTX *frame = talloc_stackframe();
1005 struct conn_struct_tos *c = NULL;
1006 struct connection_struct *conn = NULL;
1007 char *targetpath = NULL;
1009 NTSTATUS status = NT_STATUS_NOT_FOUND;
1011 struct dfs_path *pdp = talloc_zero(frame, struct dfs_path);
1015 return NT_STATUS_NO_MEMORY;
1018 *self_referralp = False;
1020 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1022 if (!NT_STATUS_IS_OK(status)) {
1027 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1028 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1029 if (!jucn->service_name || !jucn->volume_name) {
1031 return NT_STATUS_NO_MEMORY;
1034 /* Verify the share is a dfs root */
1035 snum = lp_servicenumber(jucn->service_name);
1037 char *service_name = NULL;
1038 if ((snum = find_service(ctx, jucn->service_name, &service_name)) < 0) {
1040 return NT_STATUS_NOT_FOUND;
1042 if (!service_name) {
1044 return NT_STATUS_NO_MEMORY;
1046 TALLOC_FREE(jucn->service_name);
1047 jucn->service_name = talloc_strdup(ctx, service_name);
1048 if (!jucn->service_name) {
1050 return NT_STATUS_NO_MEMORY;
1054 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(talloc_tos(), snum) == '\0')) {
1055 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
1057 pdp->servicename, dfs_path));
1059 return NT_STATUS_NOT_FOUND;
1063 * Self referrals are tested with a anonymous IPC connection and
1064 * a GET_DFS_REFERRAL call to \\server\share. (which means
1065 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
1066 * into the directory and will fail if it cannot (as the anonymous
1067 * user). Cope with this.
1070 if (pdp->reqpath[0] == '\0') {
1072 struct referral *ref;
1075 if (*lp_msdfs_proxy(talloc_tos(), snum) == '\0') {
1077 return self_ref(ctx,
1085 * It's an msdfs proxy share. Redirect to
1086 * the configured target share.
1089 tmp = talloc_asprintf(frame, "msdfs:%s",
1090 lp_msdfs_proxy(frame, snum));
1093 return NT_STATUS_NO_MEMORY;
1096 if (!parse_msdfs_symlink(ctx, snum, tmp, &ref, &refcount)) {
1098 return NT_STATUS_INVALID_PARAMETER;
1100 jucn->referral_count = refcount;
1101 jucn->referral_list = ref;
1102 *consumedcntp = strlen(dfs_path);
1104 return NT_STATUS_OK;
1107 status = create_conn_struct_tos_cwd(server_messaging_context(),
1109 lp_path(frame, snum),
1112 if (!NT_STATUS_IS_OK(status)) {
1121 * The remote and local address should be passed down to
1122 * create_conn_struct_cwd.
1124 if (conn->sconn->remote_address == NULL) {
1125 conn->sconn->remote_address =
1126 tsocket_address_copy(remote_address, conn->sconn);
1127 if (conn->sconn->remote_address == NULL) {
1129 return NT_STATUS_NO_MEMORY;
1132 if (conn->sconn->local_address == NULL) {
1133 conn->sconn->local_address =
1134 tsocket_address_copy(local_address, conn->sconn);
1135 if (conn->sconn->local_address == NULL) {
1137 return NT_STATUS_NO_MEMORY;
1141 /* If this is a DFS path dfs_lookup should return
1142 * NT_STATUS_PATH_NOT_COVERED. */
1144 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
1145 0, consumedcntp, &targetpath);
1147 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
1148 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
1150 if (NT_STATUS_IS_OK(status)) {
1152 * We are in an error path here (we
1153 * know it's not a DFS path), but
1154 * dfs_path_lookup() can return
1155 * NT_STATUS_OK. Ensure we always
1156 * return a valid error code.
1158 * #9588 - ACLs are not inherited to directories
1161 status = NT_STATUS_NOT_FOUND;
1166 /* We know this is a valid dfs link. Parse the targetpath. */
1167 if (!parse_msdfs_symlink(ctx, snum, targetpath,
1168 &jucn->referral_list,
1169 &jucn->referral_count)) {
1170 DEBUG(3,("get_referred_path: failed to parse symlink "
1171 "target %s\n", targetpath ));
1172 status = NT_STATUS_NOT_FOUND;
1176 status = NT_STATUS_OK;
1182 /******************************************************************
1183 Set up the DFS referral for the dfs pathname. This call returns
1184 the amount of the path covered by this server, and where the
1185 client should be redirected to. This is the meat of the
1186 TRANS2_GET_DFS_REFERRAL call.
1187 ******************************************************************/
1189 int setup_dfs_referral(connection_struct *orig_conn,
1190 const char *dfs_path,
1191 int max_referral_level,
1192 char **ppdata, NTSTATUS *pstatus)
1194 char *pdata = *ppdata;
1196 struct dfs_GetDFSReferral *r;
1197 DATA_BLOB blob = data_blob_null;
1199 enum ndr_err_code ndr_err;
1201 r = talloc_zero(talloc_tos(), struct dfs_GetDFSReferral);
1203 *pstatus = NT_STATUS_NO_MEMORY;
1207 r->in.req.max_referral_level = max_referral_level;
1208 r->in.req.servername = talloc_strdup(r, dfs_path);
1209 if (r->in.req.servername == NULL) {
1211 *pstatus = NT_STATUS_NO_MEMORY;
1215 status = SMB_VFS_GET_DFS_REFERRALS(orig_conn, r);
1216 if (!NT_STATUS_IS_OK(status)) {
1222 ndr_err = ndr_push_struct_blob(&blob, r,
1224 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1225 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1227 *pstatus = NT_STATUS_INVALID_PARAMETER;
1231 pdata = (char *)SMB_REALLOC(pdata, blob.length);
1234 DEBUG(0,("referral setup:"
1235 "malloc failed for Realloc!\n"));
1239 reply_size = blob.length;
1240 memcpy(pdata, blob.data, blob.length);
1243 *pstatus = NT_STATUS_OK;
1247 /**********************************************************************
1248 The following functions are called by the NETDFS RPC pipe functions
1249 **********************************************************************/
1251 /*********************************************************************
1252 Creates a junction structure from a DFS pathname
1253 **********************************************************************/
1255 bool create_junction(TALLOC_CTX *ctx,
1256 const char *dfs_path,
1257 bool allow_broken_path,
1258 struct junction_map *jucn)
1262 struct dfs_path *pdp = talloc(ctx,struct dfs_path);
1268 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1270 if (!NT_STATUS_IS_OK(status)) {
1274 /* check if path is dfs : validate first token */
1275 if (!is_myname_or_ipaddr(pdp->hostname)) {
1276 DEBUG(4,("create_junction: Invalid hostname %s "
1278 pdp->hostname, dfs_path));
1283 /* Check for a non-DFS share */
1284 snum = lp_servicenumber(pdp->servicename);
1286 if(snum < 0 || !lp_msdfs_root(snum)) {
1287 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1293 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1294 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1295 jucn->comment = lp_comment(ctx, snum);
1298 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1304 /**********************************************************************
1305 Forms a valid Unix pathname from the junction
1306 **********************************************************************/
1308 static bool junction_to_local_path_tos(const struct junction_map *jucn,
1310 connection_struct **conn_out)
1312 struct conn_struct_tos *c = NULL;
1314 char *path_out = NULL;
1317 snum = lp_servicenumber(jucn->service_name);
1321 status = create_conn_struct_tos_cwd(server_messaging_context(),
1323 lp_path(talloc_tos(), snum),
1326 if (!NT_STATUS_IS_OK(status)) {
1330 path_out = talloc_asprintf(c,
1332 lp_path(talloc_tos(), snum),
1334 if (path_out == NULL) {
1338 *pp_path_out = path_out;
1339 *conn_out = c->conn;
1343 bool create_msdfs_link(const struct junction_map *jucn)
1345 TALLOC_CTX *frame = talloc_stackframe();
1347 char *msdfs_link = NULL;
1348 connection_struct *conn;
1350 bool insert_comma = False;
1352 struct smb_filename *smb_fname = NULL;
1355 ok = junction_to_local_path_tos(jucn, &path, &conn);
1361 /* Form the msdfs_link contents */
1362 msdfs_link = talloc_strdup(conn, "msdfs:");
1366 for(i=0; i<jucn->referral_count; i++) {
1367 char *refpath = jucn->referral_list[i].alternate_path;
1369 /* Alternate paths always use Windows separators. */
1370 trim_char(refpath, '\\', '\\');
1371 if(*refpath == '\0') {
1373 insert_comma = False;
1377 if (i > 0 && insert_comma) {
1378 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1382 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1390 if (!insert_comma) {
1391 insert_comma = True;
1395 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1398 smb_fname = synthetic_smb_fname(frame,
1403 if (smb_fname == NULL) {
1408 if(SMB_VFS_SYMLINK(conn, msdfs_link, smb_fname) < 0) {
1409 if (errno == EEXIST) {
1410 if(SMB_VFS_UNLINK(conn, smb_fname)!=0) {
1411 TALLOC_FREE(smb_fname);
1415 if (SMB_VFS_SYMLINK(conn, msdfs_link, smb_fname) < 0) {
1416 DEBUG(1,("create_msdfs_link: symlink failed "
1417 "%s -> %s\nError: %s\n",
1418 path, msdfs_link, strerror(errno)));
1430 bool remove_msdfs_link(const struct junction_map *jucn)
1432 TALLOC_CTX *frame = talloc_stackframe();
1434 connection_struct *conn;
1436 struct smb_filename *smb_fname;
1439 ok = junction_to_local_path_tos(jucn, &path, &conn);
1445 smb_fname = synthetic_smb_fname(frame,
1450 if (smb_fname == NULL) {
1456 if( SMB_VFS_UNLINK(conn, smb_fname) == 0 ) {
1464 /*********************************************************************
1465 Return the number of DFS links at the root of this share.
1466 *********************************************************************/
1468 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1470 TALLOC_CTX *frame = talloc_stackframe();
1473 const char *dname = NULL;
1474 char *talloced = NULL;
1475 const char *connect_path = lp_path(frame, snum);
1476 const char *msdfs_proxy = lp_msdfs_proxy(frame, snum);
1477 struct conn_struct_tos *c = NULL;
1478 connection_struct *conn = NULL;
1480 struct smb_filename *smb_fname = NULL;
1482 if(*connect_path == '\0') {
1488 * Fake up a connection struct for the VFS layer.
1491 status = create_conn_struct_tos_cwd(server_messaging_context(),
1496 if (!NT_STATUS_IS_OK(status)) {
1497 DEBUG(3, ("create_conn_struct failed: %s\n",
1498 nt_errstr(status)));
1504 /* Count a link for the msdfs root - convention */
1507 /* No more links if this is an msdfs proxy. */
1508 if (*msdfs_proxy != '\0') {
1512 smb_fname = synthetic_smb_fname(frame,
1517 if (smb_fname == NULL) {
1521 /* Now enumerate all dfs links */
1522 dirp = SMB_VFS_OPENDIR(conn, smb_fname, NULL, 0);
1527 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1529 struct smb_filename *smb_dname =
1530 synthetic_smb_fname(frame,
1535 if (smb_dname == NULL) {
1538 if (is_msdfs_link(conn, smb_dname)) {
1541 TALLOC_FREE(talloced);
1542 TALLOC_FREE(smb_dname);
1545 SMB_VFS_CLOSEDIR(conn,dirp);
1552 /*********************************************************************
1553 *********************************************************************/
1555 static int form_junctions(TALLOC_CTX *ctx,
1557 struct junction_map *jucn,
1560 TALLOC_CTX *frame = talloc_stackframe();
1563 const char *dname = NULL;
1564 char *talloced = NULL;
1565 const char *connect_path = lp_path(frame, snum);
1566 char *service_name = lp_servicename(frame, snum);
1567 const char *msdfs_proxy = lp_msdfs_proxy(frame, snum);
1568 struct conn_struct_tos *c = NULL;
1569 connection_struct *conn = NULL;
1570 struct referral *ref = NULL;
1571 struct smb_filename *smb_fname = NULL;
1574 if (jn_remain == 0) {
1579 if(*connect_path == '\0') {
1585 * Fake up a connection struct for the VFS layer.
1588 status = create_conn_struct_tos_cwd(server_messaging_context(),
1593 if (!NT_STATUS_IS_OK(status)) {
1594 DEBUG(3, ("create_conn_struct failed: %s\n",
1595 nt_errstr(status)));
1601 /* form a junction for the msdfs root - convention
1602 DO NOT REMOVE THIS: NT clients will not work with us
1603 if this is not present
1605 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1606 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1607 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1610 jucn[cnt].comment = "";
1611 jucn[cnt].referral_count = 1;
1613 ref = jucn[cnt].referral_list = talloc_zero(ctx, struct referral);
1614 if (jucn[cnt].referral_list == NULL) {
1619 ref->ttl = REFERRAL_TTL;
1620 if (*msdfs_proxy != '\0') {
1621 ref->alternate_path = talloc_strdup(ctx,
1624 ref->alternate_path = talloc_asprintf(ctx,
1626 get_local_machine_name(),
1630 if (!ref->alternate_path) {
1635 /* Don't enumerate if we're an msdfs proxy. */
1636 if (*msdfs_proxy != '\0') {
1640 smb_fname = synthetic_smb_fname(frame,
1645 if (smb_fname == NULL) {
1649 /* Now enumerate all dfs links */
1650 dirp = SMB_VFS_OPENDIR(conn, smb_fname, NULL, 0);
1655 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1657 char *link_target = NULL;
1658 struct smb_filename *smb_dname = NULL;
1660 if (cnt >= jn_remain) {
1661 DEBUG(2, ("form_junctions: ran out of MSDFS "
1663 TALLOC_FREE(talloced);
1666 smb_dname = synthetic_smb_fname(talloc_tos(),
1671 if (smb_dname == NULL) {
1672 TALLOC_FREE(talloced);
1675 if (is_msdfs_link_internal(ctx,
1677 smb_dname, &link_target)) {
1678 if (parse_msdfs_symlink(ctx, snum,
1680 &jucn[cnt].referral_list,
1681 &jucn[cnt].referral_count)) {
1683 jucn[cnt].service_name = talloc_strdup(ctx,
1685 jucn[cnt].volume_name = talloc_strdup(ctx,
1687 if (!jucn[cnt].service_name ||
1688 !jucn[cnt].volume_name) {
1689 TALLOC_FREE(talloced);
1692 jucn[cnt].comment = "";
1695 TALLOC_FREE(link_target);
1697 TALLOC_FREE(talloced);
1698 TALLOC_FREE(smb_dname);
1704 SMB_VFS_CLOSEDIR(conn,dirp);
1711 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1713 struct junction_map *jn = NULL;
1715 size_t jn_count = 0;
1719 if(!lp_host_msdfs()) {
1723 /* Ensure all the usershares are loaded. */
1725 load_registry_shares();
1726 sharecount = load_usershare_shares(NULL, connections_snum_used);
1729 for(i=0;i < sharecount;i++) {
1730 if(lp_msdfs_root(i)) {
1731 jn_count += count_dfs_links(ctx, i);
1734 if (jn_count == 0) {
1737 jn = talloc_array(ctx, struct junction_map, jn_count);
1741 for(i=0; i < sharecount; i++) {
1742 if (*p_num_jn >= jn_count) {
1745 if(lp_msdfs_root(i)) {
1746 *p_num_jn += form_junctions(ctx, i,
1748 jn_count - *p_num_jn);
1754 /******************************************************************************
1755 Core function to resolve a dfs pathname possibly containing a wildcard. If
1756 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1757 detected during dfs resolution.
1758 ******************************************************************************/
1760 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1761 connection_struct *conn,
1762 const char *name_in,
1764 bool allow_broken_path,
1766 bool *ppath_contains_wcard)
1768 bool path_contains_wcard = false;
1769 NTSTATUS status = NT_STATUS_OK;
1771 status = dfs_redirect(ctx,
1777 &path_contains_wcard);
1779 if (NT_STATUS_IS_OK(status) &&
1780 ppath_contains_wcard != NULL &&
1781 path_contains_wcard) {
1782 *ppath_contains_wcard = path_contains_wcard;