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 */
63 const struct loadparm_substitution *lp_sub =
64 loadparm_s3_global_substitution();
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(), lp_sub, SNUM(conn)))
167 || (strequal(servicename, HOMES_NAME)
168 && strequal(lp_servicename(talloc_tos(), lp_sub, 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; /* "" */
212 /* Rest is reqpath. */
213 if (pdp->posix_path) {
214 status = check_path_syntax_posix(pdp->reqpath);
217 bool has_wcard = ms_has_wild(pdp->reqpath);
219 return NT_STATUS_INVALID_PARAMETER;
222 status = check_path_syntax(pdp->reqpath);
225 if (!NT_STATUS_IS_OK(status)) {
226 DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
227 p, nt_errstr(status) ));
231 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
235 /********************************************************
236 Fake up a connection struct for the VFS layer, for use in
237 applications (such as the python bindings), that do not want the
238 global working directory changed under them.
240 SMB_VFS_CONNECT requires root privileges.
241 *********************************************************/
243 static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx,
244 struct messaging_context *msg,
245 connection_struct **pconn,
248 const struct auth_session_info *session_info)
250 connection_struct *conn;
252 const char *vfs_user;
253 struct smbd_server_connection *sconn;
254 const char *servicename = lp_const_servicename(snum);
257 sconn = talloc_zero(ctx, struct smbd_server_connection);
259 return NT_STATUS_NO_MEMORY;
262 sconn->ev_ctx = samba_tevent_context_init(sconn);
263 if (sconn->ev_ctx == NULL) {
265 return NT_STATUS_NO_MEMORY;
268 sconn->msg_ctx = msg;
270 conn = conn_new(sconn);
273 return NT_STATUS_NO_MEMORY;
276 /* Now we have conn, we need to make sconn a child of conn,
277 * for a proper talloc tree */
278 talloc_steal(conn, sconn);
280 if (snum == -1 && servicename == NULL) {
281 servicename = "Unknown Service (snum == -1)";
284 connpath = talloc_strdup(conn, path);
287 return NT_STATUS_NO_MEMORY;
289 connpath = talloc_string_sub(conn,
295 return NT_STATUS_NO_MEMORY;
298 /* needed for smbd_vfs_init() */
300 conn->params->service = snum;
301 conn->cnum = TID_FIELD_INVALID;
303 SMB_ASSERT(session_info != NULL);
305 conn->session_info = copy_session_info(conn, session_info);
306 if (conn->session_info == NULL) {
307 DBG_ERR("copy_serverinfo failed\n");
309 return NT_STATUS_NO_MEMORY;
312 /* unix_info could be NULL in session_info */
313 if (conn->session_info->unix_info != NULL) {
314 vfs_user = conn->session_info->unix_info->unix_name;
316 vfs_user = get_current_username();
319 set_conn_connectpath(conn, connpath);
322 * New code to check if there's a share security descriptor
323 * added from NT server manager. This is done after the
324 * smb.conf checks are done as we need a uid and token. JRA.
327 share_access_check(conn->session_info->security_token,
329 MAXIMUM_ALLOWED_ACCESS,
330 &conn->share_access);
332 if ((conn->share_access & FILE_WRITE_DATA) == 0) {
333 if ((conn->share_access & FILE_READ_DATA) == 0) {
334 /* No access, read or write. */
335 DBG_WARNING("connection to %s "
336 "denied due to security "
340 return NT_STATUS_ACCESS_DENIED;
342 conn->read_only = true;
345 if (!smbd_vfs_init(conn)) {
346 NTSTATUS status = map_nt_error_from_unix(errno);
347 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
352 /* this must be the first filesystem operation that we do */
353 if (SMB_VFS_CONNECT(conn, servicename, vfs_user) < 0) {
354 DEBUG(0,("VFS connect failed!\n"));
356 return NT_STATUS_UNSUCCESSFUL;
359 ok = canonicalize_connect_path(conn);
361 DBG_ERR("Failed to canonicalize sharepath\n");
363 return NT_STATUS_ACCESS_DENIED;
366 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
367 conn->tcon_done = true;
368 *pconn = talloc_move(ctx, &conn);
373 static int conn_struct_tos_destructor(struct conn_struct_tos *c)
375 if (c->oldcwd_fname != NULL) {
376 vfs_ChDir(c->conn, c->oldcwd_fname);
377 TALLOC_FREE(c->oldcwd_fname);
379 SMB_VFS_DISCONNECT(c->conn);
384 /********************************************************
385 Fake up a connection struct for the VFS layer, for use in
386 applications (such as the python bindings), that do not want the
387 global working directory changed under them.
389 SMB_VFS_CONNECT requires root privileges.
390 This temporary uses become_root() and unbecome_root().
392 But further impersonation has to be cone by the caller.
393 *********************************************************/
394 NTSTATUS create_conn_struct_tos(struct messaging_context *msg,
397 const struct auth_session_info *session_info,
398 struct conn_struct_tos **_c)
400 struct conn_struct_tos *c = NULL;
405 c = talloc_zero(talloc_tos(), struct conn_struct_tos);
407 return NT_STATUS_NO_MEMORY;
411 status = create_conn_struct_as_root(c,
418 if (!NT_STATUS_IS_OK(status)) {
423 talloc_set_destructor(c, conn_struct_tos_destructor);
429 /********************************************************
430 Fake up a connection struct for the VFS layer.
431 Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
433 See also the comment for create_conn_struct_tos() above!
435 The CWD change is reverted by the destructor of
436 conn_struct_tos when the current talloc_tos() is destroyed.
437 *********************************************************/
438 NTSTATUS create_conn_struct_tos_cwd(struct messaging_context *msg,
441 const struct auth_session_info *session_info,
442 struct conn_struct_tos **_c)
444 struct conn_struct_tos *c = NULL;
445 struct smb_filename smb_fname_connectpath = {0};
450 status = create_conn_struct_tos(msg,
455 if (!NT_STATUS_IS_OK(status)) {
460 * Windows seems to insist on doing trans2getdfsreferral() calls on
461 * the IPC$ share as the anonymous user. If we try to chdir as that
462 * user we will fail.... WTF ? JRA.
465 c->oldcwd_fname = vfs_GetWd(c, c->conn);
466 if (c->oldcwd_fname == NULL) {
467 status = map_nt_error_from_unix(errno);
468 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
473 smb_fname_connectpath = (struct smb_filename) {
474 .base_name = c->conn->connectpath
477 if (vfs_ChDir(c->conn, &smb_fname_connectpath) != 0) {
478 status = map_nt_error_from_unix(errno);
479 DBG_NOTICE("Can't ChDir to new conn path %s. "
481 c->conn->connectpath, strerror(errno));
482 TALLOC_FREE(c->oldcwd_fname);
491 static void shuffle_strlist(char **list, int count)
497 for (i = count; i > 1; i--) {
498 r = generate_random() % i;
506 /**********************************************************************
507 Parse the contents of a symlink to verify if it is an msdfs referral
508 A valid referral is of the form:
510 msdfs:server1\share1,server2\share2
511 msdfs:server1\share1\pathname,server2\share2\pathname
512 msdfs:server1/share1,server2/share2
513 msdfs:server1/share1/pathname,server2/share2/pathname.
515 Note that the alternate paths returned here must be of the canonicalized
519 \server\share\path\to\file,
521 even in posix path mode. This is because we have no knowledge if the
522 server we're referring to understands posix paths.
523 **********************************************************************/
525 bool parse_msdfs_symlink(TALLOC_CTX *ctx,
526 bool shuffle_referrals,
528 struct referral **ppreflist,
533 char **alt_path = NULL;
535 struct referral *reflist = NULL;
538 temp = talloc_strdup(ctx, target);
542 prot = strtok_r(temp, ":", &saveptr);
544 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
549 alt_path = talloc_array(ctx, char *, MAX_REFERRAL_COUNT);
555 /* parse out the alternate paths */
556 while((count<MAX_REFERRAL_COUNT) &&
557 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
561 /* shuffle alternate paths */
562 if (shuffle_referrals) {
563 shuffle_strlist(alt_path, count);
566 DBG_DEBUG("count=%zu\n", count);
569 reflist = talloc_zero_array(ctx,
570 struct referral, count);
571 if(reflist == NULL) {
573 TALLOC_FREE(alt_path);
580 for(i=0;i<count;i++) {
583 /* Canonicalize link target.
584 * Replace all /'s in the path by a \ */
585 string_replace(alt_path[i], '/', '\\');
587 /* Remove leading '\\'s */
589 while (*p && (*p == '\\')) {
593 reflist[i].alternate_path = talloc_asprintf(reflist,
596 if (!reflist[i].alternate_path) {
598 TALLOC_FREE(alt_path);
599 TALLOC_FREE(reflist);
603 reflist[i].proximity = 0;
604 reflist[i].ttl = REFERRAL_TTL;
605 DBG_DEBUG("Created alt path: %s\n",
606 reflist[i].alternate_path);
609 if (ppreflist != NULL) {
610 *ppreflist = reflist;
612 TALLOC_FREE(reflist);
614 if (prefcount != NULL) {
618 TALLOC_FREE(alt_path);
622 /**********************************************************************
623 Returns true if the unix path is a valid msdfs symlink.
624 **********************************************************************/
626 bool is_msdfs_link(connection_struct *conn,
627 struct smb_filename *smb_fname)
629 NTSTATUS status = SMB_VFS_READ_DFS_PATHAT(conn,
635 return (NT_STATUS_IS_OK(status));
638 /*****************************************************************
639 Used by other functions to decide if a dfs path is remote,
640 and to get the list of referred locations for that remote path.
642 search_flag: For findfirsts, dfs links themselves are not
643 redirected, but paths beyond the links are. For normal smb calls,
644 even dfs links need to be redirected.
646 consumedcntp: how much of the dfs path is being redirected. the client
647 should try the remaining path on the redirected server.
649 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
650 link redirect are in targetpath.
651 *****************************************************************/
653 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
654 connection_struct *conn,
655 const char *dfspath, /* Incoming complete dfs path */
656 const struct dfs_path *pdp, /* Parsed out
657 server+share+extrapath. */
660 struct referral **ppreflist,
661 size_t *preferral_count)
666 struct smb_filename *smb_fname = NULL;
667 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
670 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
671 conn->connectpath, pdp->reqpath));
674 * Note the unix path conversion here we're doing we
675 * throw away. We're looking for a symlink for a dfs
676 * resolution, if we don't find it we'll do another
677 * unix_convert later in the codepath.
680 status = unix_convert(ctx, conn, pdp->reqpath, 0, &smb_fname,
683 if (!NT_STATUS_IS_OK(status)) {
684 if (!NT_STATUS_EQUAL(status,
685 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
688 if (smb_fname == NULL || smb_fname->base_name == NULL) {
693 /* Optimization - check if we can redirect the whole path. */
695 status = SMB_VFS_READ_DFS_PATHAT(conn,
702 if (NT_STATUS_IS_OK(status)) {
703 /* XX_ALLOW_WCARD_XXX is called from search functions. */
704 if (ucf_flags & UCF_ALWAYS_ALLOW_WCARD_LCOMP) {
705 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
706 "for dfs link %s.\n", dfspath));
707 status = NT_STATUS_OK;
711 DBG_INFO("%s resolves to a valid dfs link\n",
715 *consumedcntp = strlen(dfspath);
717 status = NT_STATUS_PATH_NOT_COVERED;
721 /* Prepare to test only for '/' components in the given path,
722 * so if a Windows path replace all '\\' characters with '/'.
723 * For a POSIX DFS path we know all separators are already '/'. */
725 canon_dfspath = talloc_strdup(ctx, dfspath);
726 if (!canon_dfspath) {
727 status = NT_STATUS_NO_MEMORY;
730 if (!pdp->posix_path) {
731 string_replace(canon_dfspath, '\\', '/');
735 * localpath comes out of unix_convert, so it has
736 * no trailing backslash. Make sure that canon_dfspath hasn't either.
737 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
740 trim_char(canon_dfspath,0,'/');
743 * Redirect if any component in the path is a link.
744 * We do this by walking backwards through the
745 * local path, chopping off the last component
746 * in both the local path and the canonicalized
747 * DFS path. If we hit a DFS link then we're done.
750 p = strrchr_m(smb_fname->base_name, '/');
752 q = strrchr_m(canon_dfspath, '/');
761 status = SMB_VFS_READ_DFS_PATHAT(conn,
768 if (NT_STATUS_IS_OK(status)) {
769 DBG_INFO("Redirecting %s because "
770 "parent %s is a dfs link\n",
772 smb_fname_str_dbg(smb_fname));
775 *consumedcntp = strlen(canon_dfspath);
776 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
782 status = NT_STATUS_PATH_NOT_COVERED;
786 /* Step back on the filesystem. */
787 p = strrchr_m(smb_fname->base_name, '/');
790 /* And in the canonicalized dfs path. */
791 q = strrchr_m(canon_dfspath, '/');
795 status = NT_STATUS_OK;
798 TALLOC_FREE(smb_fname);
802 /*****************************************************************
803 Decides if a dfs pathname should be redirected or not.
804 If not, the pathname is converted to a tcon-relative local unix path
806 search_wcard_flag: this flag performs 2 functions both related
807 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
810 This function can return NT_STATUS_OK, meaning use the returned path as-is
811 (mapped into a local path).
812 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
813 any other NT_STATUS error which is a genuine error to be
814 returned to the client.
815 *****************************************************************/
817 NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
818 connection_struct *conn,
821 bool allow_broken_path,
824 const struct loadparm_substitution *lp_sub =
825 loadparm_s3_global_substitution();
827 bool search_wcard_flag = (ucf_flags & UCF_ALWAYS_ALLOW_WCARD_LCOMP);
828 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
831 return NT_STATUS_NO_MEMORY;
834 status = parse_dfs_path(conn, path_in, search_wcard_flag,
835 allow_broken_path, pdp);
836 if (!NT_STATUS_IS_OK(status)) {
841 if (pdp->reqpath[0] == '\0') {
843 *pp_path_out = talloc_strdup(ctx, "");
845 return NT_STATUS_NO_MEMORY;
847 DEBUG(5,("dfs_redirect: self-referral.\n"));
851 /* If dfs pathname for a non-dfs share, convert to tcon-relative
852 path and return OK */
854 if (!lp_msdfs_root(SNUM(conn))) {
855 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
858 return NT_STATUS_NO_MEMORY;
863 /* If it looked like a local path (zero hostname/servicename)
864 * just treat as a tcon-relative path. */
866 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
867 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
870 return NT_STATUS_NO_MEMORY;
875 if (!( strequal(pdp->servicename, lp_servicename(talloc_tos(), lp_sub, SNUM(conn)))
876 || (strequal(pdp->servicename, HOMES_NAME)
877 && strequal(lp_servicename(talloc_tos(), lp_sub, SNUM(conn)),
878 conn->session_info->unix_info->sanitized_username) )) ) {
880 /* The given sharename doesn't match this connection. */
883 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
886 status = dfs_path_lookup(ctx,
891 NULL, /* int *consumedcntp */
892 NULL, /* struct referral **ppreflist */
893 NULL); /* size_t *preferral_count */
894 if (!NT_STATUS_IS_OK(status)) {
895 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
896 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
898 DEBUG(10,("dfs_redirect: dfs_path_lookup "
899 "failed for %s with %s\n",
900 path_in, nt_errstr(status) ));
905 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
907 /* Form non-dfs tcon-relative path */
908 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
911 return NT_STATUS_NO_MEMORY;
914 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
921 /**********************************************************************
922 Return a self referral.
923 **********************************************************************/
925 static NTSTATUS self_ref(TALLOC_CTX *ctx,
926 const char *dfs_path,
927 struct junction_map *jucn,
929 bool *self_referralp)
931 struct referral *ref;
933 *self_referralp = True;
935 jucn->referral_count = 1;
936 if((ref = talloc_zero(ctx, struct referral)) == NULL) {
937 return NT_STATUS_NO_MEMORY;
940 ref->alternate_path = talloc_strdup(ctx, dfs_path);
941 if (!ref->alternate_path) {
943 return NT_STATUS_NO_MEMORY;
946 ref->ttl = REFERRAL_TTL;
947 jucn->referral_list = ref;
948 *consumedcntp = strlen(dfs_path);
952 /**********************************************************************
953 Gets valid referrals for a dfs path and fills up the
954 junction_map structure.
955 **********************************************************************/
957 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
958 struct auth_session_info *session_info,
959 const char *dfs_path,
960 const struct tsocket_address *remote_address,
961 const struct tsocket_address *local_address,
962 bool allow_broken_path,
963 struct junction_map *jucn,
965 bool *self_referralp)
967 TALLOC_CTX *frame = talloc_stackframe();
968 const struct loadparm_substitution *lp_sub =
969 loadparm_s3_global_substitution();
970 struct conn_struct_tos *c = NULL;
971 struct connection_struct *conn = NULL;
973 NTSTATUS status = NT_STATUS_NOT_FOUND;
974 struct dfs_path *pdp = talloc_zero(frame, struct dfs_path);
978 return NT_STATUS_NO_MEMORY;
981 *self_referralp = False;
983 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path, pdp);
984 if (!NT_STATUS_IS_OK(status)) {
989 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
990 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
991 if (!jucn->service_name || !jucn->volume_name) {
993 return NT_STATUS_NO_MEMORY;
996 /* Verify the share is a dfs root */
997 snum = lp_servicenumber(jucn->service_name);
999 char *service_name = NULL;
1000 if ((snum = find_service(ctx, jucn->service_name, &service_name)) < 0) {
1002 return NT_STATUS_NOT_FOUND;
1004 if (!service_name) {
1006 return NT_STATUS_NO_MEMORY;
1008 TALLOC_FREE(jucn->service_name);
1009 jucn->service_name = talloc_strdup(ctx, service_name);
1010 if (!jucn->service_name) {
1012 return NT_STATUS_NO_MEMORY;
1016 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(talloc_tos(), lp_sub, snum) == '\0')) {
1017 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
1019 pdp->servicename, dfs_path));
1021 return NT_STATUS_NOT_FOUND;
1025 * Self referrals are tested with a anonymous IPC connection and
1026 * a GET_DFS_REFERRAL call to \\server\share. (which means
1027 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
1028 * into the directory and will fail if it cannot (as the anonymous
1029 * user). Cope with this.
1032 if (pdp->reqpath[0] == '\0') {
1034 struct referral *ref;
1037 if (*lp_msdfs_proxy(talloc_tos(), lp_sub, snum) == '\0') {
1039 return self_ref(ctx,
1047 * It's an msdfs proxy share. Redirect to
1048 * the configured target share.
1051 tmp = talloc_asprintf(frame, "msdfs:%s",
1052 lp_msdfs_proxy(frame, lp_sub, snum));
1055 return NT_STATUS_NO_MEMORY;
1058 if (!parse_msdfs_symlink(ctx,
1059 lp_msdfs_shuffle_referrals(snum),
1064 return NT_STATUS_INVALID_PARAMETER;
1066 jucn->referral_count = refcount;
1067 jucn->referral_list = ref;
1068 *consumedcntp = strlen(dfs_path);
1070 return NT_STATUS_OK;
1073 status = create_conn_struct_tos_cwd(global_messaging_context(),
1075 lp_path(frame, lp_sub, snum),
1078 if (!NT_STATUS_IS_OK(status)) {
1087 * The remote and local address should be passed down to
1088 * create_conn_struct_cwd.
1090 if (conn->sconn->remote_address == NULL) {
1091 conn->sconn->remote_address =
1092 tsocket_address_copy(remote_address, conn->sconn);
1093 if (conn->sconn->remote_address == NULL) {
1095 return NT_STATUS_NO_MEMORY;
1098 if (conn->sconn->local_address == NULL) {
1099 conn->sconn->local_address =
1100 tsocket_address_copy(local_address, conn->sconn);
1101 if (conn->sconn->local_address == NULL) {
1103 return NT_STATUS_NO_MEMORY;
1107 /* If this is a DFS path dfs_lookup should return
1108 * NT_STATUS_PATH_NOT_COVERED. */
1110 status = dfs_path_lookup(ctx,
1116 &jucn->referral_list,
1117 &jucn->referral_count);
1119 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
1120 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
1122 if (NT_STATUS_IS_OK(status)) {
1124 * We are in an error path here (we
1125 * know it's not a DFS path), but
1126 * dfs_path_lookup() can return
1127 * NT_STATUS_OK. Ensure we always
1128 * return a valid error code.
1130 * #9588 - ACLs are not inherited to directories
1133 status = NT_STATUS_NOT_FOUND;
1138 status = NT_STATUS_OK;
1144 /******************************************************************
1145 Set up the DFS referral for the dfs pathname. This call returns
1146 the amount of the path covered by this server, and where the
1147 client should be redirected to. This is the meat of the
1148 TRANS2_GET_DFS_REFERRAL call.
1149 ******************************************************************/
1151 int setup_dfs_referral(connection_struct *orig_conn,
1152 const char *dfs_path,
1153 int max_referral_level,
1154 char **ppdata, NTSTATUS *pstatus)
1156 char *pdata = *ppdata;
1158 struct dfs_GetDFSReferral *r;
1159 DATA_BLOB blob = data_blob_null;
1161 enum ndr_err_code ndr_err;
1163 r = talloc_zero(talloc_tos(), struct dfs_GetDFSReferral);
1165 *pstatus = NT_STATUS_NO_MEMORY;
1169 r->in.req.max_referral_level = max_referral_level;
1170 r->in.req.servername = talloc_strdup(r, dfs_path);
1171 if (r->in.req.servername == NULL) {
1173 *pstatus = NT_STATUS_NO_MEMORY;
1177 status = SMB_VFS_GET_DFS_REFERRALS(orig_conn, r);
1178 if (!NT_STATUS_IS_OK(status)) {
1184 ndr_err = ndr_push_struct_blob(&blob, r,
1186 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1187 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1189 *pstatus = NT_STATUS_INVALID_PARAMETER;
1193 pdata = (char *)SMB_REALLOC(pdata, blob.length);
1196 DEBUG(0,("referral setup:"
1197 "malloc failed for Realloc!\n"));
1201 reply_size = blob.length;
1202 memcpy(pdata, blob.data, blob.length);
1205 *pstatus = NT_STATUS_OK;
1209 /**********************************************************************
1210 The following functions are called by the NETDFS RPC pipe functions
1211 **********************************************************************/
1213 /*********************************************************************
1214 Creates a junction structure from a DFS pathname
1215 **********************************************************************/
1217 bool create_junction(TALLOC_CTX *ctx,
1218 const char *dfs_path,
1219 bool allow_broken_path,
1220 struct junction_map *jucn)
1222 const struct loadparm_substitution *lp_sub =
1223 loadparm_s3_global_substitution();
1225 struct dfs_path *pdp = talloc(ctx,struct dfs_path);
1231 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path, pdp);
1232 if (!NT_STATUS_IS_OK(status)) {
1236 /* check if path is dfs : validate first token */
1237 if (!is_myname_or_ipaddr(pdp->hostname)) {
1238 DEBUG(4,("create_junction: Invalid hostname %s "
1240 pdp->hostname, dfs_path));
1245 /* Check for a non-DFS share */
1246 snum = lp_servicenumber(pdp->servicename);
1248 if(snum < 0 || !lp_msdfs_root(snum)) {
1249 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1255 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1256 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1257 jucn->comment = lp_comment(ctx, lp_sub, snum);
1260 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1266 /**********************************************************************
1267 Forms a valid Unix pathname from the junction
1268 **********************************************************************/
1270 static bool junction_to_local_path_tos(const struct junction_map *jucn,
1271 struct auth_session_info *session_info,
1273 connection_struct **conn_out)
1275 const struct loadparm_substitution *lp_sub =
1276 loadparm_s3_global_substitution();
1277 struct conn_struct_tos *c = NULL;
1279 char *path_out = NULL;
1282 snum = lp_servicenumber(jucn->service_name);
1286 status = create_conn_struct_tos_cwd(global_messaging_context(),
1288 lp_path(talloc_tos(), lp_sub, snum),
1291 if (!NT_STATUS_IS_OK(status)) {
1295 path_out = talloc_asprintf(c,
1297 lp_path(talloc_tos(), lp_sub, snum),
1299 if (path_out == NULL) {
1303 *pp_path_out = path_out;
1304 *conn_out = c->conn;
1309 * Create a msdfs string in Samba format we can store
1310 * in a filesystem object (currently a symlink).
1313 char *msdfs_link_string(TALLOC_CTX *ctx,
1314 const struct referral *reflist,
1315 size_t referral_count)
1317 char *refpath = NULL;
1318 bool insert_comma = false;
1319 char *msdfs_link = NULL;
1322 /* Form the msdfs_link contents */
1323 msdfs_link = talloc_strdup(ctx, "msdfs:");
1324 if (msdfs_link == NULL) {
1328 for( i= 0; i < referral_count; i++) {
1329 refpath = talloc_strdup(ctx, reflist[i].alternate_path);
1331 if (refpath == NULL) {
1335 /* Alternate paths always use Windows separators. */
1336 trim_char(refpath, '\\', '\\');
1337 if (*refpath == '\0') {
1339 insert_comma = false;
1343 if (i > 0 && insert_comma) {
1344 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1348 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1353 if (msdfs_link == NULL) {
1357 if (!insert_comma) {
1358 insert_comma = true;
1361 TALLOC_FREE(refpath);
1368 TALLOC_FREE(refpath);
1369 TALLOC_FREE(msdfs_link);
1373 bool create_msdfs_link(const struct junction_map *jucn,
1374 struct auth_session_info *session_info)
1376 TALLOC_CTX *frame = talloc_stackframe();
1378 connection_struct *conn;
1379 struct smb_filename *smb_fname = NULL;
1384 ok = junction_to_local_path_tos(jucn, session_info, &path, &conn);
1389 if (!CAN_WRITE(conn)) {
1390 const struct loadparm_substitution *lp_sub =
1391 loadparm_s3_global_substitution();
1392 int snum = lp_servicenumber(jucn->service_name);
1394 DBG_WARNING("Can't create DFS entry on read-only share %s\n",
1395 lp_servicename(frame, lp_sub, snum));
1399 smb_fname = synthetic_smb_fname(frame,
1405 if (smb_fname == NULL) {
1409 status = SMB_VFS_CREATE_DFS_PATHAT(conn,
1412 jucn->referral_list,
1413 jucn->referral_count);
1414 if (!NT_STATUS_IS_OK(status)) {
1415 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1416 int retval = SMB_VFS_UNLINKAT(conn,
1424 status = SMB_VFS_CREATE_DFS_PATHAT(conn,
1427 jucn->referral_list,
1428 jucn->referral_count);
1429 if (!NT_STATUS_IS_OK(status)) {
1430 DBG_WARNING("SMB_VFS_CREATE_DFS_PATHAT failed "
1445 bool remove_msdfs_link(const struct junction_map *jucn,
1446 struct auth_session_info *session_info)
1448 TALLOC_CTX *frame = talloc_stackframe();
1450 connection_struct *conn;
1452 struct smb_filename *smb_fname;
1456 ok = junction_to_local_path_tos(jucn, session_info, &path, &conn);
1462 if (!CAN_WRITE(conn)) {
1463 const struct loadparm_substitution *lp_sub =
1464 loadparm_s3_global_substitution();
1465 int snum = lp_servicenumber(jucn->service_name);
1467 DBG_WARNING("Can't remove DFS entry on read-only share %s\n",
1468 lp_servicename(frame, lp_sub, snum));
1473 smb_fname = synthetic_smb_fname(frame,
1479 if (smb_fname == NULL) {
1485 retval = SMB_VFS_UNLINKAT(conn,
1497 /*********************************************************************
1498 Return the number of DFS links at the root of this share.
1499 *********************************************************************/
1501 static size_t count_dfs_links(TALLOC_CTX *ctx,
1502 struct auth_session_info *session_info,
1505 TALLOC_CTX *frame = talloc_stackframe();
1506 const struct loadparm_substitution *lp_sub =
1507 loadparm_s3_global_substitution();
1509 const char *dname = NULL;
1510 char *talloced = NULL;
1511 const char *connect_path = lp_path(frame, lp_sub, snum);
1512 const char *msdfs_proxy = lp_msdfs_proxy(frame, lp_sub, snum);
1513 struct conn_struct_tos *c = NULL;
1514 connection_struct *conn = NULL;
1516 struct smb_filename *smb_fname = NULL;
1517 struct smb_Dir *dir_hnd = NULL;
1520 if(*connect_path == '\0') {
1526 * Fake up a connection struct for the VFS layer.
1529 status = create_conn_struct_tos_cwd(global_messaging_context(),
1534 if (!NT_STATUS_IS_OK(status)) {
1535 DEBUG(3, ("create_conn_struct failed: %s\n",
1536 nt_errstr(status)));
1542 /* Count a link for the msdfs root - convention */
1545 /* No more links if this is an msdfs proxy. */
1546 if (*msdfs_proxy != '\0') {
1550 smb_fname = synthetic_smb_fname(frame,
1556 if (smb_fname == NULL) {
1560 /* Now enumerate all dfs links */
1561 dir_hnd = OpenDir(frame, conn, smb_fname, NULL, 0);
1562 if (dir_hnd == NULL) {
1566 while ((dname = ReadDirName(dir_hnd, &offset, NULL, &talloced))
1569 struct smb_filename *smb_dname =
1570 synthetic_smb_fname(frame,
1576 if (smb_dname == NULL) {
1579 if (is_msdfs_link(conn, smb_dname)) {
1580 if (cnt + 1 < cnt) {
1586 TALLOC_FREE(talloced);
1587 TALLOC_FREE(smb_dname);
1595 /*********************************************************************
1596 *********************************************************************/
1598 static int form_junctions(TALLOC_CTX *ctx,
1599 struct auth_session_info *session_info,
1601 struct junction_map *jucn,
1604 TALLOC_CTX *frame = talloc_stackframe();
1605 const struct loadparm_substitution *lp_sub =
1606 loadparm_s3_global_substitution();
1608 const char *dname = NULL;
1609 char *talloced = NULL;
1610 const char *connect_path = lp_path(frame, lp_sub, snum);
1611 char *service_name = lp_servicename(frame, lp_sub, snum);
1612 const char *msdfs_proxy = lp_msdfs_proxy(frame, lp_sub, snum);
1613 struct conn_struct_tos *c = NULL;
1614 connection_struct *conn = NULL;
1615 struct referral *ref = NULL;
1616 struct smb_filename *smb_fname = NULL;
1617 struct smb_Dir *dir_hnd = NULL;
1621 if (jn_remain == 0) {
1626 if(*connect_path == '\0') {
1632 * Fake up a connection struct for the VFS layer.
1635 status = create_conn_struct_tos_cwd(global_messaging_context(),
1640 if (!NT_STATUS_IS_OK(status)) {
1641 DEBUG(3, ("create_conn_struct failed: %s\n",
1642 nt_errstr(status)));
1648 /* form a junction for the msdfs root - convention
1649 DO NOT REMOVE THIS: NT clients will not work with us
1650 if this is not present
1652 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1653 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1654 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1657 jucn[cnt].comment = "";
1658 jucn[cnt].referral_count = 1;
1660 ref = jucn[cnt].referral_list = talloc_zero(ctx, struct referral);
1661 if (jucn[cnt].referral_list == NULL) {
1666 ref->ttl = REFERRAL_TTL;
1667 if (*msdfs_proxy != '\0') {
1668 ref->alternate_path = talloc_strdup(ctx,
1671 ref->alternate_path = talloc_asprintf(ctx,
1673 get_local_machine_name(),
1677 if (!ref->alternate_path) {
1682 /* Don't enumerate if we're an msdfs proxy. */
1683 if (*msdfs_proxy != '\0') {
1687 smb_fname = synthetic_smb_fname(frame,
1693 if (smb_fname == NULL) {
1697 /* Now enumerate all dfs links */
1698 dir_hnd = OpenDir(frame, conn, smb_fname, NULL, 0);
1699 if (dir_hnd == NULL) {
1703 while ((dname = ReadDirName(dir_hnd, &offset, NULL, &talloced))
1706 struct smb_filename *smb_dname = NULL;
1708 if (cnt >= jn_remain) {
1709 DEBUG(2, ("form_junctions: ran out of MSDFS "
1711 TALLOC_FREE(talloced);
1714 smb_dname = synthetic_smb_fname(talloc_tos(),
1720 if (smb_dname == NULL) {
1721 TALLOC_FREE(talloced);
1725 status = SMB_VFS_READ_DFS_PATHAT(conn,
1729 &jucn[cnt].referral_list,
1730 &jucn[cnt].referral_count);
1732 if (NT_STATUS_IS_OK(status)) {
1733 jucn[cnt].service_name = talloc_strdup(ctx,
1735 jucn[cnt].volume_name = talloc_strdup(ctx, dname);
1736 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1737 TALLOC_FREE(talloced);
1740 jucn[cnt].comment = "";
1743 TALLOC_FREE(talloced);
1744 TALLOC_FREE(smb_dname);
1752 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx,
1753 struct auth_session_info *session_info,
1756 struct junction_map *jn = NULL;
1758 size_t jn_count = 0;
1762 if(!lp_host_msdfs()) {
1766 /* Ensure all the usershares are loaded. */
1768 load_registry_shares();
1769 sharecount = load_usershare_shares(NULL, connections_snum_used);
1772 for(i=0;i < sharecount;i++) {
1773 if(lp_msdfs_root(i)) {
1774 jn_count += count_dfs_links(ctx, session_info, i);
1777 if (jn_count == 0) {
1780 jn = talloc_array(ctx, struct junction_map, jn_count);
1784 for(i=0; i < sharecount; i++) {
1785 if (*p_num_jn >= jn_count) {
1788 if(lp_msdfs_root(i)) {
1789 *p_num_jn += form_junctions(ctx,
1793 jn_count - *p_num_jn);