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);
258 sconn = talloc_zero(ctx, struct smbd_server_connection);
260 return NT_STATUS_NO_MEMORY;
263 sconn->ev_ctx = samba_tevent_context_init(sconn);
264 if (sconn->ev_ctx == NULL) {
266 return NT_STATUS_NO_MEMORY;
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 /* unix_info could be NULL in session_info */
312 if (conn->session_info->unix_info != NULL) {
313 vfs_user = conn->session_info->unix_info->unix_name;
315 vfs_user = get_current_username();
318 /* use current authenticated user in absence of session_info */
319 vfs_user = get_current_username();
322 set_conn_connectpath(conn, connpath);
325 * New code to check if there's a share security descriptor
326 * added from NT server manager. This is done after the
327 * smb.conf checks are done as we need a uid and token. JRA.
330 if (conn->session_info) {
331 share_access_check(conn->session_info->security_token,
333 MAXIMUM_ALLOWED_ACCESS,
334 &conn->share_access);
336 if ((conn->share_access & FILE_WRITE_DATA) == 0) {
337 if ((conn->share_access & FILE_READ_DATA) == 0) {
338 /* No access, read or write. */
339 DEBUG(3,("create_conn_struct: connection to %s "
340 "denied due to security "
344 return NT_STATUS_ACCESS_DENIED;
346 conn->read_only = true;
350 conn->share_access = 0;
351 conn->read_only = true;
354 if (!smbd_vfs_init(conn)) {
355 NTSTATUS status = map_nt_error_from_unix(errno);
356 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
361 /* this must be the first filesystem operation that we do */
362 if (SMB_VFS_CONNECT(conn, servicename, vfs_user) < 0) {
363 DEBUG(0,("VFS connect failed!\n"));
365 return NT_STATUS_UNSUCCESSFUL;
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 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
537 struct referral **preflist,
542 char **alt_path = NULL;
544 struct referral *reflist;
547 temp = talloc_strdup(ctx, target);
551 prot = strtok_r(temp, ":", &saveptr);
553 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
557 alt_path = talloc_array(ctx, char *, MAX_REFERRAL_COUNT);
562 /* parse out the alternate paths */
563 while((count<MAX_REFERRAL_COUNT) &&
564 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
568 /* shuffle alternate paths */
569 if (lp_msdfs_shuffle_referrals(snum)) {
570 shuffle_strlist(alt_path, count);
573 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
576 reflist = *preflist = talloc_zero_array(ctx,
577 struct referral, count);
578 if(reflist == NULL) {
579 TALLOC_FREE(alt_path);
583 reflist = *preflist = NULL;
586 for(i=0;i<count;i++) {
589 /* Canonicalize link target.
590 * Replace all /'s in the path by a \ */
591 string_replace(alt_path[i], '/', '\\');
593 /* Remove leading '\\'s */
595 while (*p && (*p == '\\')) {
599 reflist[i].alternate_path = talloc_asprintf(ctx,
602 if (!reflist[i].alternate_path) {
606 reflist[i].proximity = 0;
607 reflist[i].ttl = REFERRAL_TTL;
608 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
609 reflist[i].alternate_path));
614 TALLOC_FREE(alt_path);
618 /**********************************************************************
619 Returns true if the unix path is a valid msdfs symlink and also
620 returns the target string from inside the link.
621 **********************************************************************/
623 static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
624 connection_struct *conn,
625 struct smb_filename *smb_fname,
626 char **pp_link_target)
628 int referral_len = 0;
629 #if defined(HAVE_BROKEN_READLINK)
630 char link_target_buf[PATH_MAX];
632 char link_target_buf[7];
635 char *link_target = NULL;
637 if (pp_link_target) {
639 link_target = talloc_array(ctx, char, bufsize);
643 *pp_link_target = link_target;
645 bufsize = sizeof(link_target_buf);
646 link_target = link_target_buf;
649 if (SMB_VFS_LSTAT(conn, smb_fname) != 0) {
650 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
651 smb_fname->base_name));
654 if (!S_ISLNK(smb_fname->st.st_ex_mode)) {
655 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
656 smb_fname->base_name));
660 referral_len = SMB_VFS_READLINKAT(conn,
666 if (referral_len == -1) {
667 DEBUG(0,("is_msdfs_link_read_target: Error reading "
668 "msdfs link %s: %s\n",
669 smb_fname->base_name, strerror(errno)));
672 link_target[referral_len] = '\0';
674 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n", smb_fname->base_name,
677 if (!strnequal(link_target, "msdfs:", 6)) {
684 if (link_target != link_target_buf) {
685 TALLOC_FREE(link_target);
690 /**********************************************************************
691 Returns true if the unix path is a valid msdfs symlink.
692 **********************************************************************/
694 bool is_msdfs_link(connection_struct *conn,
695 struct smb_filename *smb_fname)
697 return is_msdfs_link_internal(talloc_tos(),
703 /*****************************************************************
704 Used by other functions to decide if a dfs path is remote,
705 and to get the list of referred locations for that remote path.
707 search_flag: For findfirsts, dfs links themselves are not
708 redirected, but paths beyond the links are. For normal smb calls,
709 even dfs links need to be redirected.
711 consumedcntp: how much of the dfs path is being redirected. the client
712 should try the remaining path on the redirected server.
714 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
715 link redirect are in targetpath.
716 *****************************************************************/
718 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
719 connection_struct *conn,
720 const char *dfspath, /* Incoming complete dfs path */
721 const struct dfs_path *pdp, /* Parsed out
722 server+share+extrapath. */
725 char **pp_targetpath)
730 struct smb_filename *smb_fname = NULL;
731 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
734 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
735 conn->connectpath, pdp->reqpath));
738 * Note the unix path conversion here we're doing we
739 * throw away. We're looking for a symlink for a dfs
740 * resolution, if we don't find it we'll do another
741 * unix_convert later in the codepath.
744 status = unix_convert(ctx, conn, pdp->reqpath, &smb_fname,
747 if (!NT_STATUS_IS_OK(status)) {
748 if (!NT_STATUS_EQUAL(status,
749 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
752 if (smb_fname == NULL || smb_fname->base_name == NULL) {
757 /* Optimization - check if we can redirect the whole path. */
759 if (is_msdfs_link_internal(ctx, conn, smb_fname, pp_targetpath)) {
760 /* XX_ALLOW_WCARD_XXX is called from search functions. */
762 (UCF_COND_ALLOW_WCARD_LCOMP|
763 UCF_ALWAYS_ALLOW_WCARD_LCOMP)) {
764 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
765 "for dfs link %s.\n", dfspath));
766 status = NT_STATUS_OK;
770 DEBUG(6,("dfs_path_lookup: %s resolves to a "
771 "valid dfs link %s.\n", dfspath,
772 pp_targetpath ? *pp_targetpath : ""));
775 *consumedcntp = strlen(dfspath);
777 status = NT_STATUS_PATH_NOT_COVERED;
781 /* Prepare to test only for '/' components in the given path,
782 * so if a Windows path replace all '\\' characters with '/'.
783 * For a POSIX DFS path we know all separators are already '/'. */
785 canon_dfspath = talloc_strdup(ctx, dfspath);
786 if (!canon_dfspath) {
787 status = NT_STATUS_NO_MEMORY;
790 if (!pdp->posix_path) {
791 string_replace(canon_dfspath, '\\', '/');
795 * localpath comes out of unix_convert, so it has
796 * no trailing backslash. Make sure that canon_dfspath hasn't either.
797 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
800 trim_char(canon_dfspath,0,'/');
803 * Redirect if any component in the path is a link.
804 * We do this by walking backwards through the
805 * local path, chopping off the last component
806 * in both the local path and the canonicalized
807 * DFS path. If we hit a DFS link then we're done.
810 p = strrchr_m(smb_fname->base_name, '/');
812 q = strrchr_m(canon_dfspath, '/');
821 if (is_msdfs_link_internal(ctx, conn,
822 smb_fname, pp_targetpath)) {
823 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
824 "parent %s is dfs link\n", dfspath,
825 smb_fname_str_dbg(smb_fname)));
828 *consumedcntp = strlen(canon_dfspath);
829 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
835 status = NT_STATUS_PATH_NOT_COVERED;
839 /* Step back on the filesystem. */
840 p = strrchr_m(smb_fname->base_name, '/');
843 /* And in the canonicalized dfs path. */
844 q = strrchr_m(canon_dfspath, '/');
848 status = NT_STATUS_OK;
850 TALLOC_FREE(smb_fname);
854 /*****************************************************************
855 Decides if a dfs pathname should be redirected or not.
856 If not, the pathname is converted to a tcon-relative local unix path
858 search_wcard_flag: this flag performs 2 functions both related
859 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
862 This function can return NT_STATUS_OK, meaning use the returned path as-is
863 (mapped into a local path).
864 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
865 any other NT_STATUS error which is a genuine error to be
866 returned to the client.
867 *****************************************************************/
869 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
870 connection_struct *conn,
873 bool allow_broken_path,
875 bool *ppath_contains_wcard)
877 const struct loadparm_substitution *lp_sub =
878 loadparm_s3_global_substitution();
880 bool search_wcard_flag = (ucf_flags &
881 (UCF_COND_ALLOW_WCARD_LCOMP|UCF_ALWAYS_ALLOW_WCARD_LCOMP));
882 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
885 return NT_STATUS_NO_MEMORY;
888 status = parse_dfs_path(conn, path_in, search_wcard_flag,
889 allow_broken_path, pdp,
890 ppath_contains_wcard);
891 if (!NT_STATUS_IS_OK(status)) {
896 if (pdp->reqpath[0] == '\0') {
898 *pp_path_out = talloc_strdup(ctx, "");
900 return NT_STATUS_NO_MEMORY;
902 DEBUG(5,("dfs_redirect: self-referral.\n"));
906 /* If dfs pathname for a non-dfs share, convert to tcon-relative
907 path and return OK */
909 if (!lp_msdfs_root(SNUM(conn))) {
910 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
913 return NT_STATUS_NO_MEMORY;
918 /* If it looked like a local path (zero hostname/servicename)
919 * just treat as a tcon-relative path. */
921 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
922 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
925 return NT_STATUS_NO_MEMORY;
930 if (!( strequal(pdp->servicename, lp_servicename(talloc_tos(), lp_sub, SNUM(conn)))
931 || (strequal(pdp->servicename, HOMES_NAME)
932 && strequal(lp_servicename(talloc_tos(), lp_sub, SNUM(conn)),
933 conn->session_info->unix_info->sanitized_username) )) ) {
935 /* The given sharename doesn't match this connection. */
938 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
941 status = dfs_path_lookup(ctx, conn, path_in, pdp,
942 ucf_flags, NULL, NULL);
943 if (!NT_STATUS_IS_OK(status)) {
944 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
945 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
947 DEBUG(10,("dfs_redirect: dfs_path_lookup "
948 "failed for %s with %s\n",
949 path_in, nt_errstr(status) ));
954 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
956 /* Form non-dfs tcon-relative path */
957 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
960 return NT_STATUS_NO_MEMORY;
963 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
970 /**********************************************************************
971 Return a self referral.
972 **********************************************************************/
974 static NTSTATUS self_ref(TALLOC_CTX *ctx,
975 const char *dfs_path,
976 struct junction_map *jucn,
978 bool *self_referralp)
980 struct referral *ref;
982 *self_referralp = True;
984 jucn->referral_count = 1;
985 if((ref = talloc_zero(ctx, struct referral)) == NULL) {
986 return NT_STATUS_NO_MEMORY;
989 ref->alternate_path = talloc_strdup(ctx, dfs_path);
990 if (!ref->alternate_path) {
992 return NT_STATUS_NO_MEMORY;
995 ref->ttl = REFERRAL_TTL;
996 jucn->referral_list = ref;
997 *consumedcntp = strlen(dfs_path);
1001 /**********************************************************************
1002 Gets valid referrals for a dfs path and fills up the
1003 junction_map structure.
1004 **********************************************************************/
1006 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
1007 const char *dfs_path,
1008 const struct tsocket_address *remote_address,
1009 const struct tsocket_address *local_address,
1010 bool allow_broken_path,
1011 struct junction_map *jucn,
1013 bool *self_referralp)
1015 TALLOC_CTX *frame = talloc_stackframe();
1016 const struct loadparm_substitution *lp_sub =
1017 loadparm_s3_global_substitution();
1018 struct conn_struct_tos *c = NULL;
1019 struct connection_struct *conn = NULL;
1020 char *targetpath = NULL;
1022 NTSTATUS status = NT_STATUS_NOT_FOUND;
1024 struct dfs_path *pdp = talloc_zero(frame, struct dfs_path);
1028 return NT_STATUS_NO_MEMORY;
1031 *self_referralp = False;
1033 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1035 if (!NT_STATUS_IS_OK(status)) {
1040 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1041 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1042 if (!jucn->service_name || !jucn->volume_name) {
1044 return NT_STATUS_NO_MEMORY;
1047 /* Verify the share is a dfs root */
1048 snum = lp_servicenumber(jucn->service_name);
1050 char *service_name = NULL;
1051 if ((snum = find_service(ctx, jucn->service_name, &service_name)) < 0) {
1053 return NT_STATUS_NOT_FOUND;
1055 if (!service_name) {
1057 return NT_STATUS_NO_MEMORY;
1059 TALLOC_FREE(jucn->service_name);
1060 jucn->service_name = talloc_strdup(ctx, service_name);
1061 if (!jucn->service_name) {
1063 return NT_STATUS_NO_MEMORY;
1067 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(talloc_tos(), lp_sub, snum) == '\0')) {
1068 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
1070 pdp->servicename, dfs_path));
1072 return NT_STATUS_NOT_FOUND;
1076 * Self referrals are tested with a anonymous IPC connection and
1077 * a GET_DFS_REFERRAL call to \\server\share. (which means
1078 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
1079 * into the directory and will fail if it cannot (as the anonymous
1080 * user). Cope with this.
1083 if (pdp->reqpath[0] == '\0') {
1085 struct referral *ref;
1088 if (*lp_msdfs_proxy(talloc_tos(), lp_sub, snum) == '\0') {
1090 return self_ref(ctx,
1098 * It's an msdfs proxy share. Redirect to
1099 * the configured target share.
1102 tmp = talloc_asprintf(frame, "msdfs:%s",
1103 lp_msdfs_proxy(frame, lp_sub, snum));
1106 return NT_STATUS_NO_MEMORY;
1109 if (!parse_msdfs_symlink(ctx, snum, tmp, &ref, &refcount)) {
1111 return NT_STATUS_INVALID_PARAMETER;
1113 jucn->referral_count = refcount;
1114 jucn->referral_list = ref;
1115 *consumedcntp = strlen(dfs_path);
1117 return NT_STATUS_OK;
1120 status = create_conn_struct_tos_cwd(global_messaging_context(),
1122 lp_path(frame, lp_sub, snum),
1125 if (!NT_STATUS_IS_OK(status)) {
1134 * The remote and local address should be passed down to
1135 * create_conn_struct_cwd.
1137 if (conn->sconn->remote_address == NULL) {
1138 conn->sconn->remote_address =
1139 tsocket_address_copy(remote_address, conn->sconn);
1140 if (conn->sconn->remote_address == NULL) {
1142 return NT_STATUS_NO_MEMORY;
1145 if (conn->sconn->local_address == NULL) {
1146 conn->sconn->local_address =
1147 tsocket_address_copy(local_address, conn->sconn);
1148 if (conn->sconn->local_address == NULL) {
1150 return NT_STATUS_NO_MEMORY;
1154 /* If this is a DFS path dfs_lookup should return
1155 * NT_STATUS_PATH_NOT_COVERED. */
1157 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
1158 0, consumedcntp, &targetpath);
1160 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
1161 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
1163 if (NT_STATUS_IS_OK(status)) {
1165 * We are in an error path here (we
1166 * know it's not a DFS path), but
1167 * dfs_path_lookup() can return
1168 * NT_STATUS_OK. Ensure we always
1169 * return a valid error code.
1171 * #9588 - ACLs are not inherited to directories
1174 status = NT_STATUS_NOT_FOUND;
1179 /* We know this is a valid dfs link. Parse the targetpath. */
1180 if (!parse_msdfs_symlink(ctx, snum, targetpath,
1181 &jucn->referral_list,
1182 &jucn->referral_count)) {
1183 DEBUG(3,("get_referred_path: failed to parse symlink "
1184 "target %s\n", targetpath ));
1185 status = NT_STATUS_NOT_FOUND;
1189 status = NT_STATUS_OK;
1195 /******************************************************************
1196 Set up the DFS referral for the dfs pathname. This call returns
1197 the amount of the path covered by this server, and where the
1198 client should be redirected to. This is the meat of the
1199 TRANS2_GET_DFS_REFERRAL call.
1200 ******************************************************************/
1202 int setup_dfs_referral(connection_struct *orig_conn,
1203 const char *dfs_path,
1204 int max_referral_level,
1205 char **ppdata, NTSTATUS *pstatus)
1207 char *pdata = *ppdata;
1209 struct dfs_GetDFSReferral *r;
1210 DATA_BLOB blob = data_blob_null;
1212 enum ndr_err_code ndr_err;
1214 r = talloc_zero(talloc_tos(), struct dfs_GetDFSReferral);
1216 *pstatus = NT_STATUS_NO_MEMORY;
1220 r->in.req.max_referral_level = max_referral_level;
1221 r->in.req.servername = talloc_strdup(r, dfs_path);
1222 if (r->in.req.servername == NULL) {
1224 *pstatus = NT_STATUS_NO_MEMORY;
1228 status = SMB_VFS_GET_DFS_REFERRALS(orig_conn, r);
1229 if (!NT_STATUS_IS_OK(status)) {
1235 ndr_err = ndr_push_struct_blob(&blob, r,
1237 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1238 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1240 *pstatus = NT_STATUS_INVALID_PARAMETER;
1244 pdata = (char *)SMB_REALLOC(pdata, blob.length);
1247 DEBUG(0,("referral setup:"
1248 "malloc failed for Realloc!\n"));
1252 reply_size = blob.length;
1253 memcpy(pdata, blob.data, blob.length);
1256 *pstatus = NT_STATUS_OK;
1260 /**********************************************************************
1261 The following functions are called by the NETDFS RPC pipe functions
1262 **********************************************************************/
1264 /*********************************************************************
1265 Creates a junction structure from a DFS pathname
1266 **********************************************************************/
1268 bool create_junction(TALLOC_CTX *ctx,
1269 const char *dfs_path,
1270 bool allow_broken_path,
1271 struct junction_map *jucn)
1273 const struct loadparm_substitution *lp_sub =
1274 loadparm_s3_global_substitution();
1277 struct dfs_path *pdp = talloc(ctx,struct dfs_path);
1283 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1285 if (!NT_STATUS_IS_OK(status)) {
1289 /* check if path is dfs : validate first token */
1290 if (!is_myname_or_ipaddr(pdp->hostname)) {
1291 DEBUG(4,("create_junction: Invalid hostname %s "
1293 pdp->hostname, dfs_path));
1298 /* Check for a non-DFS share */
1299 snum = lp_servicenumber(pdp->servicename);
1301 if(snum < 0 || !lp_msdfs_root(snum)) {
1302 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1308 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1309 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1310 jucn->comment = lp_comment(ctx, lp_sub, snum);
1313 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1319 /**********************************************************************
1320 Forms a valid Unix pathname from the junction
1321 **********************************************************************/
1323 static bool junction_to_local_path_tos(const struct junction_map *jucn,
1325 connection_struct **conn_out)
1327 const struct loadparm_substitution *lp_sub =
1328 loadparm_s3_global_substitution();
1329 struct conn_struct_tos *c = NULL;
1331 char *path_out = NULL;
1334 snum = lp_servicenumber(jucn->service_name);
1338 status = create_conn_struct_tos_cwd(global_messaging_context(),
1340 lp_path(talloc_tos(), lp_sub, snum),
1343 if (!NT_STATUS_IS_OK(status)) {
1347 path_out = talloc_asprintf(c,
1349 lp_path(talloc_tos(), lp_sub, snum),
1351 if (path_out == NULL) {
1355 *pp_path_out = path_out;
1356 *conn_out = c->conn;
1360 bool create_msdfs_link(const struct junction_map *jucn)
1362 TALLOC_CTX *frame = talloc_stackframe();
1364 char *msdfs_link = NULL;
1365 connection_struct *conn;
1367 bool insert_comma = False;
1369 struct smb_filename *smb_fname = NULL;
1373 ok = junction_to_local_path_tos(jucn, &path, &conn);
1379 /* Form the msdfs_link contents */
1380 msdfs_link = talloc_strdup(conn, "msdfs:");
1384 for(i=0; i<jucn->referral_count; i++) {
1385 char *refpath = jucn->referral_list[i].alternate_path;
1387 /* Alternate paths always use Windows separators. */
1388 trim_char(refpath, '\\', '\\');
1389 if(*refpath == '\0') {
1391 insert_comma = False;
1395 if (i > 0 && insert_comma) {
1396 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1400 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1408 if (!insert_comma) {
1409 insert_comma = True;
1413 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1416 smb_fname = synthetic_smb_fname(frame,
1421 if (smb_fname == NULL) {
1426 retval = SMB_VFS_SYMLINKAT(conn,
1431 if (errno == EEXIST) {
1432 retval = SMB_VFS_UNLINKAT(conn,
1437 TALLOC_FREE(smb_fname);
1441 retval = SMB_VFS_SYMLINKAT(conn,
1446 DEBUG(1,("create_msdfs_link: symlinkat failed "
1447 "%s -> %s\nError: %s\n",
1448 path, msdfs_link, strerror(errno)));
1460 bool remove_msdfs_link(const struct junction_map *jucn)
1462 TALLOC_CTX *frame = talloc_stackframe();
1464 connection_struct *conn;
1466 struct smb_filename *smb_fname;
1470 ok = junction_to_local_path_tos(jucn, &path, &conn);
1476 smb_fname = synthetic_smb_fname(frame,
1481 if (smb_fname == NULL) {
1487 retval = SMB_VFS_UNLINKAT(conn,
1499 /*********************************************************************
1500 Return the number of DFS links at the root of this share.
1501 *********************************************************************/
1503 static size_t count_dfs_links(TALLOC_CTX *ctx, int snum)
1505 TALLOC_CTX *frame = talloc_stackframe();
1506 const struct loadparm_substitution *lp_sub =
1507 loadparm_s3_global_substitution();
1510 const char *dname = NULL;
1511 char *talloced = NULL;
1512 const char *connect_path = lp_path(frame, lp_sub, snum);
1513 const char *msdfs_proxy = lp_msdfs_proxy(frame, lp_sub, snum);
1514 struct conn_struct_tos *c = NULL;
1515 connection_struct *conn = NULL;
1517 struct smb_filename *smb_fname = NULL;
1519 if(*connect_path == '\0') {
1525 * Fake up a connection struct for the VFS layer.
1528 status = create_conn_struct_tos_cwd(global_messaging_context(),
1533 if (!NT_STATUS_IS_OK(status)) {
1534 DEBUG(3, ("create_conn_struct failed: %s\n",
1535 nt_errstr(status)));
1541 /* Count a link for the msdfs root - convention */
1544 /* No more links if this is an msdfs proxy. */
1545 if (*msdfs_proxy != '\0') {
1549 smb_fname = synthetic_smb_fname(frame,
1554 if (smb_fname == NULL) {
1558 /* Now enumerate all dfs links */
1559 dirp = SMB_VFS_OPENDIR(conn, smb_fname, NULL, 0);
1564 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1566 struct smb_filename *smb_dname =
1567 synthetic_smb_fname(frame,
1572 if (smb_dname == NULL) {
1575 if (is_msdfs_link(conn, smb_dname)) {
1576 if (cnt + 1 < cnt) {
1582 TALLOC_FREE(talloced);
1583 TALLOC_FREE(smb_dname);
1586 SMB_VFS_CLOSEDIR(conn,dirp);
1593 /*********************************************************************
1594 *********************************************************************/
1596 static int form_junctions(TALLOC_CTX *ctx,
1598 struct junction_map *jucn,
1601 TALLOC_CTX *frame = talloc_stackframe();
1602 const struct loadparm_substitution *lp_sub =
1603 loadparm_s3_global_substitution();
1606 const char *dname = NULL;
1607 char *talloced = NULL;
1608 const char *connect_path = lp_path(frame, lp_sub, snum);
1609 char *service_name = lp_servicename(frame, lp_sub, snum);
1610 const char *msdfs_proxy = lp_msdfs_proxy(frame, lp_sub, snum);
1611 struct conn_struct_tos *c = NULL;
1612 connection_struct *conn = NULL;
1613 struct referral *ref = NULL;
1614 struct smb_filename *smb_fname = NULL;
1617 if (jn_remain == 0) {
1622 if(*connect_path == '\0') {
1628 * Fake up a connection struct for the VFS layer.
1631 status = create_conn_struct_tos_cwd(global_messaging_context(),
1636 if (!NT_STATUS_IS_OK(status)) {
1637 DEBUG(3, ("create_conn_struct failed: %s\n",
1638 nt_errstr(status)));
1644 /* form a junction for the msdfs root - convention
1645 DO NOT REMOVE THIS: NT clients will not work with us
1646 if this is not present
1648 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1649 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1650 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1653 jucn[cnt].comment = "";
1654 jucn[cnt].referral_count = 1;
1656 ref = jucn[cnt].referral_list = talloc_zero(ctx, struct referral);
1657 if (jucn[cnt].referral_list == NULL) {
1662 ref->ttl = REFERRAL_TTL;
1663 if (*msdfs_proxy != '\0') {
1664 ref->alternate_path = talloc_strdup(ctx,
1667 ref->alternate_path = talloc_asprintf(ctx,
1669 get_local_machine_name(),
1673 if (!ref->alternate_path) {
1678 /* Don't enumerate if we're an msdfs proxy. */
1679 if (*msdfs_proxy != '\0') {
1683 smb_fname = synthetic_smb_fname(frame,
1688 if (smb_fname == NULL) {
1692 /* Now enumerate all dfs links */
1693 dirp = SMB_VFS_OPENDIR(conn, smb_fname, NULL, 0);
1698 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1700 char *link_target = NULL;
1701 struct smb_filename *smb_dname = NULL;
1703 if (cnt >= jn_remain) {
1704 DEBUG(2, ("form_junctions: ran out of MSDFS "
1706 TALLOC_FREE(talloced);
1709 smb_dname = synthetic_smb_fname(talloc_tos(),
1714 if (smb_dname == NULL) {
1715 TALLOC_FREE(talloced);
1718 if (is_msdfs_link_internal(ctx,
1720 smb_dname, &link_target)) {
1721 if (parse_msdfs_symlink(ctx, snum,
1723 &jucn[cnt].referral_list,
1724 &jucn[cnt].referral_count)) {
1726 jucn[cnt].service_name = talloc_strdup(ctx,
1728 jucn[cnt].volume_name = talloc_strdup(ctx,
1730 if (!jucn[cnt].service_name ||
1731 !jucn[cnt].volume_name) {
1732 TALLOC_FREE(talloced);
1735 jucn[cnt].comment = "";
1738 TALLOC_FREE(link_target);
1740 TALLOC_FREE(talloced);
1741 TALLOC_FREE(smb_dname);
1747 SMB_VFS_CLOSEDIR(conn,dirp);
1754 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
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, 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, i,
1791 jn_count - *p_num_jn);
1797 /******************************************************************************
1798 Core function to resolve a dfs pathname possibly containing a wildcard. If
1799 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1800 detected during dfs resolution.
1801 ******************************************************************************/
1803 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1804 connection_struct *conn,
1805 const char *name_in,
1807 bool allow_broken_path,
1809 bool *ppath_contains_wcard)
1811 bool path_contains_wcard = false;
1812 NTSTATUS status = NT_STATUS_OK;
1814 status = dfs_redirect(ctx,
1820 &path_contains_wcard);
1822 if (NT_STATUS_IS_OK(status) &&
1823 ppath_contains_wcard != NULL &&
1824 path_contains_wcard) {
1825 *ppath_contains_wcard = path_contains_wcard;