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"
37 /**********************************************************************
38 Parse a DFS pathname of the form \hostname\service\reqpath
39 into the dfs_path structure.
40 If POSIX pathnames is true, the pathname may also be of the
41 form /hostname/service/reqpath.
42 We cope with either here.
44 Unfortunately, due to broken clients who might set the
45 SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
46 send a local path, we have to cope with that too....
48 If conn != NULL then ensure the provided service is
49 the one pointed to by the connection.
51 This version does everything using pointers within one copy of the
52 pathname string, talloced on the struct dfs_path pointer (which
53 must be talloced). This may be too clever to live....
55 **********************************************************************/
57 static NTSTATUS parse_dfs_path(connection_struct *conn,
60 bool allow_broken_path,
61 struct dfs_path *pdp, /* MUST BE TALLOCED */
62 bool *ppath_contains_wcard)
64 const struct loadparm_substitution *lp_sub =
65 loadparm_s3_global_substitution();
70 NTSTATUS status = NT_STATUS_OK;
76 * This is the only talloc we should need to do
77 * on the struct dfs_path. All the pointers inside
78 * it should point to offsets within this string.
81 pathname_local = talloc_strdup(pdp, pathname);
82 if (!pathname_local) {
83 return NT_STATUS_NO_MEMORY;
85 /* Get a pointer to the terminating '\0' */
86 eos_ptr = &pathname_local[strlen(pathname_local)];
87 p = temp = pathname_local;
90 * Non-broken DFS paths *must* start with the
91 * path separator. For Windows this is always '\\',
92 * for posix paths this is always '/'.
95 if (*pathname == '/') {
96 pdp->posix_path = true;
99 pdp->posix_path = false;
103 if (allow_broken_path && (*pathname != sepchar)) {
104 DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
105 pathname, sepchar ));
107 * Possibly client sent a local path by mistake.
108 * Try and convert to a local path.
109 * Note that this is an SMB1-only fallback
110 * to cope with known broken SMB1 clients.
113 pdp->hostname = eos_ptr; /* "" */
114 pdp->servicename = eos_ptr; /* "" */
116 /* We've got no info about separators. */
117 pdp->posix_path = lp_posix_pathnames();
119 DEBUG(10,("parse_dfs_path: trying to convert %s to a "
126 * Safe to use on talloc'ed string as it only shrinks.
127 * It also doesn't affect the eos_ptr.
129 trim_char(temp,sepchar,sepchar);
131 DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
135 /* Parse out hostname. */
136 p = strchr_m(temp,sepchar);
138 DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
141 * Possibly client sent a local path by mistake.
142 * Try and convert to a local path.
145 pdp->hostname = eos_ptr; /* "" */
146 pdp->servicename = eos_ptr; /* "" */
149 DEBUG(10,("parse_dfs_path: trying to convert %s "
155 pdp->hostname = temp;
157 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
159 /* Parse out servicename. */
161 p = strchr_m(servicename,sepchar);
166 /* Is this really our servicename ? */
167 if (conn && !( strequal(servicename, lp_servicename(talloc_tos(), lp_sub, SNUM(conn)))
168 || (strequal(servicename, HOMES_NAME)
169 && strequal(lp_servicename(talloc_tos(), lp_sub, SNUM(conn)),
170 get_current_username()) )) ) {
171 DEBUG(10,("parse_dfs_path: %s is not our servicename\n",
175 * Possibly client sent a local path by mistake.
176 * Try and convert to a local path.
179 pdp->hostname = eos_ptr; /* "" */
180 pdp->servicename = eos_ptr; /* "" */
182 /* Repair the path - replace the sepchar's
185 *servicename = sepchar;
191 DEBUG(10,("parse_dfs_path: trying to convert %s "
197 pdp->servicename = servicename;
199 DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
202 /* Client sent self referral \server\share. */
203 pdp->reqpath = eos_ptr; /* "" */
211 *ppath_contains_wcard = False;
215 /* Rest is reqpath. */
216 if (pdp->posix_path) {
217 status = check_path_syntax_posix(pdp->reqpath);
220 status = check_path_syntax_wcard(pdp->reqpath,
221 ppath_contains_wcard);
223 status = check_path_syntax(pdp->reqpath);
227 if (!NT_STATUS_IS_OK(status)) {
228 DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
229 p, nt_errstr(status) ));
233 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
237 /********************************************************
238 Fake up a connection struct for the VFS layer, for use in
239 applications (such as the python bindings), that do not want the
240 global working directory changed under them.
242 SMB_VFS_CONNECT requires root privileges.
243 *********************************************************/
245 static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx,
246 struct messaging_context *msg,
247 connection_struct **pconn,
250 const struct auth_session_info *session_info)
252 connection_struct *conn;
254 const char *vfs_user;
255 struct smbd_server_connection *sconn;
256 const char *servicename = lp_const_servicename(snum);
259 sconn = talloc_zero(ctx, struct smbd_server_connection);
261 return NT_STATUS_NO_MEMORY;
264 sconn->ev_ctx = samba_tevent_context_init(sconn);
265 if (sconn->ev_ctx == NULL) {
267 return NT_STATUS_NO_MEMORY;
270 sconn->msg_ctx = msg;
272 conn = conn_new(sconn);
275 return NT_STATUS_NO_MEMORY;
278 /* Now we have conn, we need to make sconn a child of conn,
279 * for a proper talloc tree */
280 talloc_steal(conn, sconn);
282 if (snum == -1 && servicename == NULL) {
283 servicename = "Unknown Service (snum == -1)";
286 connpath = talloc_strdup(conn, path);
289 return NT_STATUS_NO_MEMORY;
291 connpath = talloc_string_sub(conn,
297 return NT_STATUS_NO_MEMORY;
300 /* needed for smbd_vfs_init() */
302 conn->params->service = snum;
303 conn->cnum = TID_FIELD_INVALID;
305 SMB_ASSERT(session_info != NULL);
307 conn->session_info = copy_session_info(conn, session_info);
308 if (conn->session_info == NULL) {
309 DBG_ERR("copy_serverinfo failed\n");
311 return NT_STATUS_NO_MEMORY;
314 /* unix_info could be NULL in session_info */
315 if (conn->session_info->unix_info != NULL) {
316 vfs_user = conn->session_info->unix_info->unix_name;
318 vfs_user = get_current_username();
321 set_conn_connectpath(conn, connpath);
324 * New code to check if there's a share security descriptor
325 * added from NT server manager. This is done after the
326 * smb.conf checks are done as we need a uid and token. JRA.
329 share_access_check(conn->session_info->security_token,
331 MAXIMUM_ALLOWED_ACCESS,
332 &conn->share_access);
334 if ((conn->share_access & FILE_WRITE_DATA) == 0) {
335 if ((conn->share_access & FILE_READ_DATA) == 0) {
336 /* No access, read or write. */
337 DBG_WARNING("connection to %s "
338 "denied due to security "
342 return NT_STATUS_ACCESS_DENIED;
344 conn->read_only = true;
347 if (!smbd_vfs_init(conn)) {
348 NTSTATUS status = map_nt_error_from_unix(errno);
349 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
354 /* this must be the first filesystem operation that we do */
355 if (SMB_VFS_CONNECT(conn, servicename, vfs_user) < 0) {
356 DEBUG(0,("VFS connect failed!\n"));
358 return NT_STATUS_UNSUCCESSFUL;
361 ok = canonicalize_connect_path(conn);
363 DBG_ERR("Failed to canonicalize sharepath\n");
365 return NT_STATUS_ACCESS_DENIED;
368 talloc_free(conn->origpath);
369 conn->origpath = talloc_strdup(conn, conn->connectpath);
370 if (conn->origpath == NULL) {
372 return NT_STATUS_NO_MEMORY;
375 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
376 conn->tcon_done = true;
377 *pconn = talloc_move(ctx, &conn);
382 static int conn_struct_tos_destructor(struct conn_struct_tos *c)
384 if (c->oldcwd_fname != NULL) {
385 vfs_ChDir(c->conn, c->oldcwd_fname);
386 TALLOC_FREE(c->oldcwd_fname);
388 SMB_VFS_DISCONNECT(c->conn);
393 /********************************************************
394 Fake up a connection struct for the VFS layer, for use in
395 applications (such as the python bindings), that do not want the
396 global working directory changed under them.
398 SMB_VFS_CONNECT requires root privileges.
399 This temporary uses become_root() and unbecome_root().
401 But further impersonation has to be cone by the caller.
402 *********************************************************/
403 NTSTATUS create_conn_struct_tos(struct messaging_context *msg,
406 const struct auth_session_info *session_info,
407 struct conn_struct_tos **_c)
409 struct conn_struct_tos *c = NULL;
414 c = talloc_zero(talloc_tos(), struct conn_struct_tos);
416 return NT_STATUS_NO_MEMORY;
420 status = create_conn_struct_as_root(c,
427 if (!NT_STATUS_IS_OK(status)) {
432 talloc_set_destructor(c, conn_struct_tos_destructor);
438 /********************************************************
439 Fake up a connection struct for the VFS layer.
440 Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
442 See also the comment for create_conn_struct_tos() above!
444 The CWD change is reverted by the destructor of
445 conn_struct_tos when the current talloc_tos() is destroyed.
446 *********************************************************/
447 NTSTATUS create_conn_struct_tos_cwd(struct messaging_context *msg,
450 const struct auth_session_info *session_info,
451 struct conn_struct_tos **_c)
453 struct conn_struct_tos *c = NULL;
454 struct smb_filename smb_fname_connectpath = {0};
459 status = create_conn_struct_tos(msg,
464 if (!NT_STATUS_IS_OK(status)) {
469 * Windows seems to insist on doing trans2getdfsreferral() calls on
470 * the IPC$ share as the anonymous user. If we try to chdir as that
471 * user we will fail.... WTF ? JRA.
474 c->oldcwd_fname = vfs_GetWd(c, c->conn);
475 if (c->oldcwd_fname == NULL) {
476 status = map_nt_error_from_unix(errno);
477 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
482 smb_fname_connectpath = (struct smb_filename) {
483 .base_name = c->conn->connectpath
486 if (vfs_ChDir(c->conn, &smb_fname_connectpath) != 0) {
487 status = map_nt_error_from_unix(errno);
488 DBG_NOTICE("Can't ChDir to new conn path %s. "
490 c->conn->connectpath, strerror(errno));
491 TALLOC_FREE(c->oldcwd_fname);
500 static void shuffle_strlist(char **list, int count)
506 for (i = count; i > 1; i--) {
507 r = generate_random() % i;
515 /**********************************************************************
516 Parse the contents of a symlink to verify if it is an msdfs referral
517 A valid referral is of the form:
519 msdfs:server1\share1,server2\share2
520 msdfs:server1\share1\pathname,server2\share2\pathname
521 msdfs:server1/share1,server2/share2
522 msdfs:server1/share1/pathname,server2/share2/pathname.
524 Note that the alternate paths returned here must be of the canonicalized
528 \server\share\path\to\file,
530 even in posix path mode. This is because we have no knowledge if the
531 server we're referring to understands posix paths.
532 **********************************************************************/
534 bool parse_msdfs_symlink(TALLOC_CTX *ctx,
535 bool shuffle_referrals,
537 struct referral **ppreflist,
542 char **alt_path = NULL;
544 struct referral *reflist = NULL;
547 temp = talloc_strdup(ctx, target);
551 prot = strtok_r(temp, ":", &saveptr);
553 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
558 alt_path = talloc_array(ctx, char *, MAX_REFERRAL_COUNT);
564 /* parse out the alternate paths */
565 while((count<MAX_REFERRAL_COUNT) &&
566 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
570 /* shuffle alternate paths */
571 if (shuffle_referrals) {
572 shuffle_strlist(alt_path, count);
575 DBG_DEBUG("count=%zu\n", count);
578 reflist = talloc_zero_array(ctx,
579 struct referral, count);
580 if(reflist == NULL) {
582 TALLOC_FREE(alt_path);
589 for(i=0;i<count;i++) {
592 /* Canonicalize link target.
593 * Replace all /'s in the path by a \ */
594 string_replace(alt_path[i], '/', '\\');
596 /* Remove leading '\\'s */
598 while (*p && (*p == '\\')) {
602 reflist[i].alternate_path = talloc_asprintf(reflist,
605 if (!reflist[i].alternate_path) {
607 TALLOC_FREE(alt_path);
608 TALLOC_FREE(reflist);
612 reflist[i].proximity = 0;
613 reflist[i].ttl = REFERRAL_TTL;
614 DBG_DEBUG("Created alt path: %s\n",
615 reflist[i].alternate_path);
618 if (ppreflist != NULL) {
619 *ppreflist = reflist;
621 TALLOC_FREE(reflist);
623 if (prefcount != NULL) {
627 TALLOC_FREE(alt_path);
631 /**********************************************************************
632 Returns true if the unix path is a valid msdfs symlink.
633 **********************************************************************/
635 bool is_msdfs_link(connection_struct *conn,
636 struct smb_filename *smb_fname)
638 NTSTATUS status = SMB_VFS_READ_DFS_PATHAT(conn,
644 return (NT_STATUS_IS_OK(status));
647 /*****************************************************************
648 Used by other functions to decide if a dfs path is remote,
649 and to get the list of referred locations for that remote path.
651 search_flag: For findfirsts, dfs links themselves are not
652 redirected, but paths beyond the links are. For normal smb calls,
653 even dfs links need to be redirected.
655 consumedcntp: how much of the dfs path is being redirected. the client
656 should try the remaining path on the redirected server.
658 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
659 link redirect are in targetpath.
660 *****************************************************************/
662 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
663 connection_struct *conn,
664 const char *dfspath, /* Incoming complete dfs path */
665 const struct dfs_path *pdp, /* Parsed out
666 server+share+extrapath. */
669 struct referral **ppreflist,
670 size_t *preferral_count)
675 struct smb_filename *smb_fname = NULL;
676 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
679 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
680 conn->connectpath, pdp->reqpath));
683 * Note the unix path conversion here we're doing we
684 * throw away. We're looking for a symlink for a dfs
685 * resolution, if we don't find it we'll do another
686 * unix_convert later in the codepath.
689 status = unix_convert(ctx, conn, pdp->reqpath, &smb_fname,
692 if (!NT_STATUS_IS_OK(status)) {
693 if (!NT_STATUS_EQUAL(status,
694 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
697 if (smb_fname == NULL || smb_fname->base_name == NULL) {
702 /* Optimization - check if we can redirect the whole path. */
704 status = SMB_VFS_READ_DFS_PATHAT(conn,
711 if (NT_STATUS_IS_OK(status)) {
712 /* XX_ALLOW_WCARD_XXX is called from search functions. */
714 (UCF_COND_ALLOW_WCARD_LCOMP|
715 UCF_ALWAYS_ALLOW_WCARD_LCOMP)) {
716 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
717 "for dfs link %s.\n", dfspath));
718 status = NT_STATUS_OK;
722 DBG_INFO("%s resolves to a valid dfs link\n",
726 *consumedcntp = strlen(dfspath);
728 status = NT_STATUS_PATH_NOT_COVERED;
732 /* Prepare to test only for '/' components in the given path,
733 * so if a Windows path replace all '\\' characters with '/'.
734 * For a POSIX DFS path we know all separators are already '/'. */
736 canon_dfspath = talloc_strdup(ctx, dfspath);
737 if (!canon_dfspath) {
738 status = NT_STATUS_NO_MEMORY;
741 if (!pdp->posix_path) {
742 string_replace(canon_dfspath, '\\', '/');
746 * localpath comes out of unix_convert, so it has
747 * no trailing backslash. Make sure that canon_dfspath hasn't either.
748 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
751 trim_char(canon_dfspath,0,'/');
754 * Redirect if any component in the path is a link.
755 * We do this by walking backwards through the
756 * local path, chopping off the last component
757 * in both the local path and the canonicalized
758 * DFS path. If we hit a DFS link then we're done.
761 p = strrchr_m(smb_fname->base_name, '/');
763 q = strrchr_m(canon_dfspath, '/');
772 status = SMB_VFS_READ_DFS_PATHAT(conn,
779 if (NT_STATUS_IS_OK(status)) {
780 DBG_INFO("Redirecting %s because "
781 "parent %s is a dfs link\n",
783 smb_fname_str_dbg(smb_fname));
786 *consumedcntp = strlen(canon_dfspath);
787 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
793 status = NT_STATUS_PATH_NOT_COVERED;
797 /* Step back on the filesystem. */
798 p = strrchr_m(smb_fname->base_name, '/');
801 /* And in the canonicalized dfs path. */
802 q = strrchr_m(canon_dfspath, '/');
806 status = NT_STATUS_OK;
809 TALLOC_FREE(smb_fname);
813 /*****************************************************************
814 Decides if a dfs pathname should be redirected or not.
815 If not, the pathname is converted to a tcon-relative local unix path
817 search_wcard_flag: this flag performs 2 functions both related
818 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
821 This function can return NT_STATUS_OK, meaning use the returned path as-is
822 (mapped into a local path).
823 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
824 any other NT_STATUS error which is a genuine error to be
825 returned to the client.
826 *****************************************************************/
828 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
829 connection_struct *conn,
832 bool allow_broken_path,
834 bool *ppath_contains_wcard)
836 const struct loadparm_substitution *lp_sub =
837 loadparm_s3_global_substitution();
839 bool search_wcard_flag = (ucf_flags &
840 (UCF_COND_ALLOW_WCARD_LCOMP|UCF_ALWAYS_ALLOW_WCARD_LCOMP));
841 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
844 return NT_STATUS_NO_MEMORY;
847 status = parse_dfs_path(conn, path_in, search_wcard_flag,
848 allow_broken_path, pdp,
849 ppath_contains_wcard);
850 if (!NT_STATUS_IS_OK(status)) {
855 if (pdp->reqpath[0] == '\0') {
857 *pp_path_out = talloc_strdup(ctx, "");
859 return NT_STATUS_NO_MEMORY;
861 DEBUG(5,("dfs_redirect: self-referral.\n"));
865 /* If dfs pathname for a non-dfs share, convert to tcon-relative
866 path and return OK */
868 if (!lp_msdfs_root(SNUM(conn))) {
869 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
872 return NT_STATUS_NO_MEMORY;
877 /* If it looked like a local path (zero hostname/servicename)
878 * just treat as a tcon-relative path. */
880 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
881 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
884 return NT_STATUS_NO_MEMORY;
889 if (!( strequal(pdp->servicename, lp_servicename(talloc_tos(), lp_sub, SNUM(conn)))
890 || (strequal(pdp->servicename, HOMES_NAME)
891 && strequal(lp_servicename(talloc_tos(), lp_sub, SNUM(conn)),
892 conn->session_info->unix_info->sanitized_username) )) ) {
894 /* The given sharename doesn't match this connection. */
897 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
900 status = dfs_path_lookup(ctx,
905 NULL, /* int *consumedcntp */
906 NULL, /* struct referral **ppreflist */
907 NULL); /* size_t *preferral_count */
908 if (!NT_STATUS_IS_OK(status)) {
909 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
910 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
912 DEBUG(10,("dfs_redirect: dfs_path_lookup "
913 "failed for %s with %s\n",
914 path_in, nt_errstr(status) ));
919 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
921 /* Form non-dfs tcon-relative path */
922 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
925 return NT_STATUS_NO_MEMORY;
928 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
935 /**********************************************************************
936 Return a self referral.
937 **********************************************************************/
939 static NTSTATUS self_ref(TALLOC_CTX *ctx,
940 const char *dfs_path,
941 struct junction_map *jucn,
943 bool *self_referralp)
945 struct referral *ref;
947 *self_referralp = True;
949 jucn->referral_count = 1;
950 if((ref = talloc_zero(ctx, struct referral)) == NULL) {
951 return NT_STATUS_NO_MEMORY;
954 ref->alternate_path = talloc_strdup(ctx, dfs_path);
955 if (!ref->alternate_path) {
957 return NT_STATUS_NO_MEMORY;
960 ref->ttl = REFERRAL_TTL;
961 jucn->referral_list = ref;
962 *consumedcntp = strlen(dfs_path);
966 /**********************************************************************
967 Gets valid referrals for a dfs path and fills up the
968 junction_map structure.
969 **********************************************************************/
971 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
972 struct auth_session_info *session_info,
973 const char *dfs_path,
974 const struct tsocket_address *remote_address,
975 const struct tsocket_address *local_address,
976 bool allow_broken_path,
977 struct junction_map *jucn,
979 bool *self_referralp)
981 TALLOC_CTX *frame = talloc_stackframe();
982 const struct loadparm_substitution *lp_sub =
983 loadparm_s3_global_substitution();
984 struct conn_struct_tos *c = NULL;
985 struct connection_struct *conn = NULL;
987 NTSTATUS status = NT_STATUS_NOT_FOUND;
989 struct dfs_path *pdp = talloc_zero(frame, struct dfs_path);
993 return NT_STATUS_NO_MEMORY;
996 *self_referralp = False;
998 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1000 if (!NT_STATUS_IS_OK(status)) {
1005 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1006 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1007 if (!jucn->service_name || !jucn->volume_name) {
1009 return NT_STATUS_NO_MEMORY;
1012 /* Verify the share is a dfs root */
1013 snum = lp_servicenumber(jucn->service_name);
1015 char *service_name = NULL;
1016 if ((snum = find_service(ctx, jucn->service_name, &service_name)) < 0) {
1018 return NT_STATUS_NOT_FOUND;
1020 if (!service_name) {
1022 return NT_STATUS_NO_MEMORY;
1024 TALLOC_FREE(jucn->service_name);
1025 jucn->service_name = talloc_strdup(ctx, service_name);
1026 if (!jucn->service_name) {
1028 return NT_STATUS_NO_MEMORY;
1032 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(talloc_tos(), lp_sub, snum) == '\0')) {
1033 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
1035 pdp->servicename, dfs_path));
1037 return NT_STATUS_NOT_FOUND;
1041 * Self referrals are tested with a anonymous IPC connection and
1042 * a GET_DFS_REFERRAL call to \\server\share. (which means
1043 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
1044 * into the directory and will fail if it cannot (as the anonymous
1045 * user). Cope with this.
1048 if (pdp->reqpath[0] == '\0') {
1050 struct referral *ref;
1053 if (*lp_msdfs_proxy(talloc_tos(), lp_sub, snum) == '\0') {
1055 return self_ref(ctx,
1063 * It's an msdfs proxy share. Redirect to
1064 * the configured target share.
1067 tmp = talloc_asprintf(frame, "msdfs:%s",
1068 lp_msdfs_proxy(frame, lp_sub, snum));
1071 return NT_STATUS_NO_MEMORY;
1074 if (!parse_msdfs_symlink(ctx,
1075 lp_msdfs_shuffle_referrals(snum),
1080 return NT_STATUS_INVALID_PARAMETER;
1082 jucn->referral_count = refcount;
1083 jucn->referral_list = ref;
1084 *consumedcntp = strlen(dfs_path);
1086 return NT_STATUS_OK;
1089 status = create_conn_struct_tos_cwd(global_messaging_context(),
1091 lp_path(frame, lp_sub, snum),
1094 if (!NT_STATUS_IS_OK(status)) {
1103 * The remote and local address should be passed down to
1104 * create_conn_struct_cwd.
1106 if (conn->sconn->remote_address == NULL) {
1107 conn->sconn->remote_address =
1108 tsocket_address_copy(remote_address, conn->sconn);
1109 if (conn->sconn->remote_address == NULL) {
1111 return NT_STATUS_NO_MEMORY;
1114 if (conn->sconn->local_address == NULL) {
1115 conn->sconn->local_address =
1116 tsocket_address_copy(local_address, conn->sconn);
1117 if (conn->sconn->local_address == NULL) {
1119 return NT_STATUS_NO_MEMORY;
1123 /* If this is a DFS path dfs_lookup should return
1124 * NT_STATUS_PATH_NOT_COVERED. */
1126 status = dfs_path_lookup(ctx,
1132 &jucn->referral_list,
1133 &jucn->referral_count);
1135 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
1136 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
1138 if (NT_STATUS_IS_OK(status)) {
1140 * We are in an error path here (we
1141 * know it's not a DFS path), but
1142 * dfs_path_lookup() can return
1143 * NT_STATUS_OK. Ensure we always
1144 * return a valid error code.
1146 * #9588 - ACLs are not inherited to directories
1149 status = NT_STATUS_NOT_FOUND;
1154 status = NT_STATUS_OK;
1160 /******************************************************************
1161 Set up the DFS referral for the dfs pathname. This call returns
1162 the amount of the path covered by this server, and where the
1163 client should be redirected to. This is the meat of the
1164 TRANS2_GET_DFS_REFERRAL call.
1165 ******************************************************************/
1167 int setup_dfs_referral(connection_struct *orig_conn,
1168 const char *dfs_path,
1169 int max_referral_level,
1170 char **ppdata, NTSTATUS *pstatus)
1172 char *pdata = *ppdata;
1174 struct dfs_GetDFSReferral *r;
1175 DATA_BLOB blob = data_blob_null;
1177 enum ndr_err_code ndr_err;
1179 r = talloc_zero(talloc_tos(), struct dfs_GetDFSReferral);
1181 *pstatus = NT_STATUS_NO_MEMORY;
1185 r->in.req.max_referral_level = max_referral_level;
1186 r->in.req.servername = talloc_strdup(r, dfs_path);
1187 if (r->in.req.servername == NULL) {
1189 *pstatus = NT_STATUS_NO_MEMORY;
1193 status = SMB_VFS_GET_DFS_REFERRALS(orig_conn, r);
1194 if (!NT_STATUS_IS_OK(status)) {
1200 ndr_err = ndr_push_struct_blob(&blob, r,
1202 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1203 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1205 *pstatus = NT_STATUS_INVALID_PARAMETER;
1209 pdata = (char *)SMB_REALLOC(pdata, blob.length);
1212 DEBUG(0,("referral setup:"
1213 "malloc failed for Realloc!\n"));
1217 reply_size = blob.length;
1218 memcpy(pdata, blob.data, blob.length);
1221 *pstatus = NT_STATUS_OK;
1225 /**********************************************************************
1226 The following functions are called by the NETDFS RPC pipe functions
1227 **********************************************************************/
1229 /*********************************************************************
1230 Creates a junction structure from a DFS pathname
1231 **********************************************************************/
1233 bool create_junction(TALLOC_CTX *ctx,
1234 const char *dfs_path,
1235 bool allow_broken_path,
1236 struct junction_map *jucn)
1238 const struct loadparm_substitution *lp_sub =
1239 loadparm_s3_global_substitution();
1242 struct dfs_path *pdp = talloc(ctx,struct dfs_path);
1248 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1250 if (!NT_STATUS_IS_OK(status)) {
1254 /* check if path is dfs : validate first token */
1255 if (!is_myname_or_ipaddr(pdp->hostname)) {
1256 DEBUG(4,("create_junction: Invalid hostname %s "
1258 pdp->hostname, dfs_path));
1263 /* Check for a non-DFS share */
1264 snum = lp_servicenumber(pdp->servicename);
1266 if(snum < 0 || !lp_msdfs_root(snum)) {
1267 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1273 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1274 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1275 jucn->comment = lp_comment(ctx, lp_sub, snum);
1278 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1284 /**********************************************************************
1285 Forms a valid Unix pathname from the junction
1286 **********************************************************************/
1288 static bool junction_to_local_path_tos(const struct junction_map *jucn,
1289 struct auth_session_info *session_info,
1291 connection_struct **conn_out)
1293 const struct loadparm_substitution *lp_sub =
1294 loadparm_s3_global_substitution();
1295 struct conn_struct_tos *c = NULL;
1297 char *path_out = NULL;
1300 snum = lp_servicenumber(jucn->service_name);
1304 status = create_conn_struct_tos_cwd(global_messaging_context(),
1306 lp_path(talloc_tos(), lp_sub, snum),
1309 if (!NT_STATUS_IS_OK(status)) {
1313 path_out = talloc_asprintf(c,
1315 lp_path(talloc_tos(), lp_sub, snum),
1317 if (path_out == NULL) {
1321 *pp_path_out = path_out;
1322 *conn_out = c->conn;
1327 * Create a msdfs string in Samba format we can store
1328 * in a filesystem object (currently a symlink).
1331 char *msdfs_link_string(TALLOC_CTX *ctx,
1332 const struct referral *reflist,
1333 size_t referral_count)
1335 char *refpath = NULL;
1336 bool insert_comma = false;
1337 char *msdfs_link = NULL;
1340 /* Form the msdfs_link contents */
1341 msdfs_link = talloc_strdup(ctx, "msdfs:");
1342 if (msdfs_link == NULL) {
1346 for( i= 0; i < referral_count; i++) {
1347 refpath = talloc_strdup(ctx, reflist[i].alternate_path);
1349 if (refpath == NULL) {
1353 /* Alternate paths always use Windows separators. */
1354 trim_char(refpath, '\\', '\\');
1355 if (*refpath == '\0') {
1357 insert_comma = false;
1361 if (i > 0 && insert_comma) {
1362 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1366 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1371 if (msdfs_link == NULL) {
1375 if (!insert_comma) {
1376 insert_comma = true;
1379 TALLOC_FREE(refpath);
1386 TALLOC_FREE(refpath);
1387 TALLOC_FREE(msdfs_link);
1391 bool create_msdfs_link(const struct junction_map *jucn,
1392 struct auth_session_info *session_info)
1394 TALLOC_CTX *frame = talloc_stackframe();
1396 connection_struct *conn;
1397 struct smb_filename *smb_fname = NULL;
1402 ok = junction_to_local_path_tos(jucn, session_info, &path, &conn);
1407 if (!CAN_WRITE(conn)) {
1408 const struct loadparm_substitution *lp_sub =
1409 loadparm_s3_global_substitution();
1410 int snum = lp_servicenumber(jucn->service_name);
1412 DBG_WARNING("Can't create DFS entry on read-only share %s\n",
1413 lp_servicename(frame, lp_sub, snum));
1417 smb_fname = synthetic_smb_fname(frame,
1423 if (smb_fname == NULL) {
1427 status = SMB_VFS_CREATE_DFS_PATHAT(conn,
1430 jucn->referral_list,
1431 jucn->referral_count);
1432 if (!NT_STATUS_IS_OK(status)) {
1433 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1434 int retval = SMB_VFS_UNLINKAT(conn,
1442 status = SMB_VFS_CREATE_DFS_PATHAT(conn,
1445 jucn->referral_list,
1446 jucn->referral_count);
1447 if (!NT_STATUS_IS_OK(status)) {
1448 DBG_WARNING("SMB_VFS_CREATE_DFS_PATHAT failed "
1463 bool remove_msdfs_link(const struct junction_map *jucn,
1464 struct auth_session_info *session_info)
1466 TALLOC_CTX *frame = talloc_stackframe();
1468 connection_struct *conn;
1470 struct smb_filename *smb_fname;
1474 ok = junction_to_local_path_tos(jucn, session_info, &path, &conn);
1480 if (!CAN_WRITE(conn)) {
1481 const struct loadparm_substitution *lp_sub =
1482 loadparm_s3_global_substitution();
1483 int snum = lp_servicenumber(jucn->service_name);
1485 DBG_WARNING("Can't remove DFS entry on read-only share %s\n",
1486 lp_servicename(frame, lp_sub, snum));
1491 smb_fname = synthetic_smb_fname(frame,
1497 if (smb_fname == NULL) {
1503 retval = SMB_VFS_UNLINKAT(conn,
1515 /*********************************************************************
1516 Return the number of DFS links at the root of this share.
1517 *********************************************************************/
1519 static size_t count_dfs_links(TALLOC_CTX *ctx,
1520 struct auth_session_info *session_info,
1523 TALLOC_CTX *frame = talloc_stackframe();
1524 const struct loadparm_substitution *lp_sub =
1525 loadparm_s3_global_substitution();
1527 const char *dname = NULL;
1528 char *talloced = NULL;
1529 const char *connect_path = lp_path(frame, lp_sub, snum);
1530 const char *msdfs_proxy = lp_msdfs_proxy(frame, lp_sub, snum);
1531 struct conn_struct_tos *c = NULL;
1532 connection_struct *conn = NULL;
1534 struct smb_filename *smb_fname = NULL;
1535 struct smb_Dir *dir_hnd = NULL;
1538 if(*connect_path == '\0') {
1544 * Fake up a connection struct for the VFS layer.
1547 status = create_conn_struct_tos_cwd(global_messaging_context(),
1552 if (!NT_STATUS_IS_OK(status)) {
1553 DEBUG(3, ("create_conn_struct failed: %s\n",
1554 nt_errstr(status)));
1560 /* Count a link for the msdfs root - convention */
1563 /* No more links if this is an msdfs proxy. */
1564 if (*msdfs_proxy != '\0') {
1568 smb_fname = synthetic_smb_fname(frame,
1574 if (smb_fname == NULL) {
1578 /* Now enumerate all dfs links */
1579 dir_hnd = OpenDir(frame, conn, smb_fname, NULL, 0);
1580 if (dir_hnd == NULL) {
1584 while ((dname = ReadDirName(dir_hnd, &offset, NULL, &talloced))
1587 struct smb_filename *smb_dname =
1588 synthetic_smb_fname(frame,
1594 if (smb_dname == NULL) {
1597 if (is_msdfs_link(conn, smb_dname)) {
1598 if (cnt + 1 < cnt) {
1604 TALLOC_FREE(talloced);
1605 TALLOC_FREE(smb_dname);
1613 /*********************************************************************
1614 *********************************************************************/
1616 static int form_junctions(TALLOC_CTX *ctx,
1617 struct auth_session_info *session_info,
1619 struct junction_map *jucn,
1622 TALLOC_CTX *frame = talloc_stackframe();
1623 const struct loadparm_substitution *lp_sub =
1624 loadparm_s3_global_substitution();
1626 const char *dname = NULL;
1627 char *talloced = NULL;
1628 const char *connect_path = lp_path(frame, lp_sub, snum);
1629 char *service_name = lp_servicename(frame, lp_sub, snum);
1630 const char *msdfs_proxy = lp_msdfs_proxy(frame, lp_sub, snum);
1631 struct conn_struct_tos *c = NULL;
1632 connection_struct *conn = NULL;
1633 struct referral *ref = NULL;
1634 struct smb_filename *smb_fname = NULL;
1635 struct smb_Dir *dir_hnd = NULL;
1639 if (jn_remain == 0) {
1644 if(*connect_path == '\0') {
1650 * Fake up a connection struct for the VFS layer.
1653 status = create_conn_struct_tos_cwd(global_messaging_context(),
1658 if (!NT_STATUS_IS_OK(status)) {
1659 DEBUG(3, ("create_conn_struct failed: %s\n",
1660 nt_errstr(status)));
1666 /* form a junction for the msdfs root - convention
1667 DO NOT REMOVE THIS: NT clients will not work with us
1668 if this is not present
1670 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1671 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1672 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1675 jucn[cnt].comment = "";
1676 jucn[cnt].referral_count = 1;
1678 ref = jucn[cnt].referral_list = talloc_zero(ctx, struct referral);
1679 if (jucn[cnt].referral_list == NULL) {
1684 ref->ttl = REFERRAL_TTL;
1685 if (*msdfs_proxy != '\0') {
1686 ref->alternate_path = talloc_strdup(ctx,
1689 ref->alternate_path = talloc_asprintf(ctx,
1691 get_local_machine_name(),
1695 if (!ref->alternate_path) {
1700 /* Don't enumerate if we're an msdfs proxy. */
1701 if (*msdfs_proxy != '\0') {
1705 smb_fname = synthetic_smb_fname(frame,
1711 if (smb_fname == NULL) {
1715 /* Now enumerate all dfs links */
1716 dir_hnd = OpenDir(frame, conn, smb_fname, NULL, 0);
1717 if (dir_hnd == NULL) {
1721 while ((dname = ReadDirName(dir_hnd, &offset, NULL, &talloced))
1724 struct smb_filename *smb_dname = NULL;
1726 if (cnt >= jn_remain) {
1727 DEBUG(2, ("form_junctions: ran out of MSDFS "
1729 TALLOC_FREE(talloced);
1732 smb_dname = synthetic_smb_fname(talloc_tos(),
1738 if (smb_dname == NULL) {
1739 TALLOC_FREE(talloced);
1743 status = SMB_VFS_READ_DFS_PATHAT(conn,
1747 &jucn[cnt].referral_list,
1748 &jucn[cnt].referral_count);
1750 if (NT_STATUS_IS_OK(status)) {
1751 jucn[cnt].service_name = talloc_strdup(ctx,
1753 jucn[cnt].volume_name = talloc_strdup(ctx, dname);
1754 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1755 TALLOC_FREE(talloced);
1758 jucn[cnt].comment = "";
1761 TALLOC_FREE(talloced);
1762 TALLOC_FREE(smb_dname);
1770 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx,
1771 struct auth_session_info *session_info,
1774 struct junction_map *jn = NULL;
1776 size_t jn_count = 0;
1780 if(!lp_host_msdfs()) {
1784 /* Ensure all the usershares are loaded. */
1786 load_registry_shares();
1787 sharecount = load_usershare_shares(NULL, connections_snum_used);
1790 for(i=0;i < sharecount;i++) {
1791 if(lp_msdfs_root(i)) {
1792 jn_count += count_dfs_links(ctx, session_info, i);
1795 if (jn_count == 0) {
1798 jn = talloc_array(ctx, struct junction_map, jn_count);
1802 for(i=0; i < sharecount; i++) {
1803 if (*p_num_jn >= jn_count) {
1806 if(lp_msdfs_root(i)) {
1807 *p_num_jn += form_junctions(ctx,
1811 jn_count - *p_num_jn);
1817 /******************************************************************************
1818 Core function to resolve a dfs pathname possibly containing a wildcard. If
1819 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1820 detected during dfs resolution.
1821 ******************************************************************************/
1823 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1824 connection_struct *conn,
1825 const char *name_in,
1827 bool allow_broken_path,
1829 bool *ppath_contains_wcard)
1831 bool path_contains_wcard = false;
1832 NTSTATUS status = NT_STATUS_OK;
1834 status = dfs_redirect(ctx,
1840 &path_contains_wcard);
1842 if (NT_STATUS_IS_OK(status) &&
1843 ppath_contains_wcard != NULL &&
1844 path_contains_wcard) {
1845 *ppath_contains_wcard = path_contains_wcard;