2 Unix SMB/Netbios implementation.
4 MSDFS services for Samba
5 Copyright (C) Shirish Kalele 2000
6 Copyright (C) Jeremy Allison 2007
7 Copyright (C) Robin McCorkell 2015
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #define DBGC_CLASS DBGC_MSDFS
26 #include "system/filesys.h"
27 #include "smbd/smbd.h"
28 #include "smbd/globals.h"
31 #include "lib/param/loadparm.h"
32 #include "libcli/security/security.h"
33 #include "librpc/gen_ndr/ndr_dfsblobs.h"
34 #include "lib/tsocket/tsocket.h"
36 /**********************************************************************
37 Parse a DFS pathname of the form \hostname\service\reqpath
38 into the dfs_path structure.
39 If POSIX pathnames is true, the pathname may also be of the
40 form /hostname/service/reqpath.
41 We cope with either here.
43 Unfortunately, due to broken clients who might set the
44 SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
45 send a local path, we have to cope with that too....
47 If conn != NULL then ensure the provided service is
48 the one pointed to by the connection.
50 This version does everything using pointers within one copy of the
51 pathname string, talloced on the struct dfs_path pointer (which
52 must be talloced). This may be too clever to live....
54 **********************************************************************/
56 static NTSTATUS parse_dfs_path(connection_struct *conn,
59 bool allow_broken_path,
60 struct dfs_path *pdp, /* MUST BE TALLOCED */
61 bool *ppath_contains_wcard)
67 NTSTATUS status = NT_STATUS_OK;
73 * This is the only talloc we should need to do
74 * on the struct dfs_path. All the pointers inside
75 * it should point to offsets within this string.
78 pathname_local = talloc_strdup(pdp, pathname);
79 if (!pathname_local) {
80 return NT_STATUS_NO_MEMORY;
82 /* Get a pointer to the terminating '\0' */
83 eos_ptr = &pathname_local[strlen(pathname_local)];
84 p = temp = pathname_local;
87 * Non-broken DFS paths *must* start with the
88 * path separator. For Windows this is always '\\',
89 * for posix paths this is always '/'.
92 if (*pathname == '/') {
93 pdp->posix_path = true;
96 pdp->posix_path = false;
100 if (allow_broken_path && (*pathname != sepchar)) {
101 DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
102 pathname, sepchar ));
104 * Possibly client sent a local path by mistake.
105 * Try and convert to a local path.
106 * Note that this is an SMB1-only fallback
107 * to cope with known broken SMB1 clients.
110 pdp->hostname = eos_ptr; /* "" */
111 pdp->servicename = eos_ptr; /* "" */
113 /* We've got no info about separators. */
114 pdp->posix_path = lp_posix_pathnames();
116 DEBUG(10,("parse_dfs_path: trying to convert %s to a "
123 * Safe to use on talloc'ed string as it only shrinks.
124 * It also doesn't affect the eos_ptr.
126 trim_char(temp,sepchar,sepchar);
128 DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
132 /* Parse out hostname. */
133 p = strchr_m(temp,sepchar);
135 DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
138 * Possibly client sent a local path by mistake.
139 * Try and convert to a local path.
142 pdp->hostname = eos_ptr; /* "" */
143 pdp->servicename = eos_ptr; /* "" */
146 DEBUG(10,("parse_dfs_path: trying to convert %s "
152 pdp->hostname = temp;
154 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
156 /* Parse out servicename. */
158 p = strchr_m(servicename,sepchar);
163 /* Is this really our servicename ? */
164 if (conn && !( strequal(servicename, lp_servicename(talloc_tos(), SNUM(conn)))
165 || (strequal(servicename, HOMES_NAME)
166 && strequal(lp_servicename(talloc_tos(), SNUM(conn)),
167 get_current_username()) )) ) {
168 DEBUG(10,("parse_dfs_path: %s is not our servicename\n",
172 * Possibly client sent a local path by mistake.
173 * Try and convert to a local path.
176 pdp->hostname = eos_ptr; /* "" */
177 pdp->servicename = eos_ptr; /* "" */
179 /* Repair the path - replace the sepchar's
182 *servicename = sepchar;
188 DEBUG(10,("parse_dfs_path: trying to convert %s "
194 pdp->servicename = servicename;
196 DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
199 /* Client sent self referral \server\share. */
200 pdp->reqpath = eos_ptr; /* "" */
208 *ppath_contains_wcard = False;
212 /* Rest is reqpath. */
213 if (pdp->posix_path) {
214 status = check_path_syntax_posix(pdp->reqpath);
217 status = check_path_syntax_wcard(pdp->reqpath,
218 ppath_contains_wcard);
220 status = check_path_syntax(pdp->reqpath);
224 if (!NT_STATUS_IS_OK(status)) {
225 DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
226 p, nt_errstr(status) ));
230 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
234 /********************************************************
235 Fake up a connection struct for the VFS layer, for use in
236 applications (such as the python bindings), that do not want the
237 global working directory changed under them.
239 SMB_VFS_CONNECT requires root privileges.
240 *********************************************************/
242 static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx,
243 struct messaging_context *msg,
244 connection_struct **pconn,
247 const struct auth_session_info *session_info)
249 connection_struct *conn;
251 const char *vfs_user;
252 struct smbd_server_connection *sconn;
253 const char *servicename = lp_const_servicename(snum);
255 sconn = talloc_zero(ctx, struct smbd_server_connection);
257 return NT_STATUS_NO_MEMORY;
260 sconn->ev_ctx = samba_tevent_context_init(sconn);
261 if (sconn->ev_ctx == NULL) {
263 return NT_STATUS_NO_MEMORY;
266 sconn->msg_ctx = msg;
268 conn = conn_new(sconn);
271 return NT_STATUS_NO_MEMORY;
274 /* Now we have conn, we need to make sconn a child of conn,
275 * for a proper talloc tree */
276 talloc_steal(conn, sconn);
278 if (snum == -1 && servicename == NULL) {
279 servicename = "Unknown Service (snum == -1)";
282 connpath = talloc_strdup(conn, path);
285 return NT_STATUS_NO_MEMORY;
287 connpath = talloc_string_sub(conn,
293 return NT_STATUS_NO_MEMORY;
296 /* needed for smbd_vfs_init() */
298 conn->params->service = snum;
299 conn->cnum = TID_FIELD_INVALID;
301 if (session_info != NULL) {
302 conn->session_info = copy_session_info(conn, session_info);
303 if (conn->session_info == NULL) {
304 DEBUG(0, ("copy_serverinfo failed\n"));
306 return NT_STATUS_NO_MEMORY;
308 vfs_user = conn->session_info->unix_info->unix_name;
310 /* use current authenticated user in absence of session_info */
311 vfs_user = get_current_username();
314 set_conn_connectpath(conn, connpath);
317 * New code to check if there's a share security descriptor
318 * added from NT server manager. This is done after the
319 * smb.conf checks are done as we need a uid and token. JRA.
322 if (conn->session_info) {
323 share_access_check(conn->session_info->security_token,
325 MAXIMUM_ALLOWED_ACCESS,
326 &conn->share_access);
328 if ((conn->share_access & FILE_WRITE_DATA) == 0) {
329 if ((conn->share_access & FILE_READ_DATA) == 0) {
330 /* No access, read or write. */
331 DEBUG(3,("create_conn_struct: connection to %s "
332 "denied due to security "
336 return NT_STATUS_ACCESS_DENIED;
338 conn->read_only = true;
342 conn->share_access = 0;
343 conn->read_only = true;
346 if (!smbd_vfs_init(conn)) {
347 NTSTATUS status = map_nt_error_from_unix(errno);
348 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
353 /* this must be the first filesystem operation that we do */
354 if (SMB_VFS_CONNECT(conn, servicename, vfs_user) < 0) {
355 DEBUG(0,("VFS connect failed!\n"));
357 return NT_STATUS_UNSUCCESSFUL;
360 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
361 *pconn = talloc_move(ctx, &conn);
366 static int conn_struct_tos_destructor(struct conn_struct_tos *c)
368 if (c->oldcwd_fname != NULL) {
369 vfs_ChDir(c->conn, c->oldcwd_fname);
370 TALLOC_FREE(c->oldcwd_fname);
372 SMB_VFS_DISCONNECT(c->conn);
377 /********************************************************
378 Fake up a connection struct for the VFS layer, for use in
379 applications (such as the python bindings), that do not want the
380 global working directory changed under them.
382 SMB_VFS_CONNECT requires root privileges.
383 This temporary uses become_root() and unbecome_root().
385 But further impersonation has to be cone by the caller.
386 *********************************************************/
387 NTSTATUS create_conn_struct_tos(struct messaging_context *msg,
390 const struct auth_session_info *session_info,
391 struct conn_struct_tos **_c)
393 struct conn_struct_tos *c = NULL;
398 c = talloc_zero(talloc_tos(), struct conn_struct_tos);
400 return NT_STATUS_NO_MEMORY;
404 status = create_conn_struct_as_root(c,
411 if (!NT_STATUS_IS_OK(status)) {
416 talloc_set_destructor(c, conn_struct_tos_destructor);
422 /********************************************************
423 Fake up a connection struct for the VFS layer.
424 Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
426 See also the comment for create_conn_struct_tos() above!
428 The CWD change is reverted by the destructor of
429 conn_struct_tos when the current talloc_tos() is destroyed.
430 *********************************************************/
431 NTSTATUS create_conn_struct_tos_cwd(struct messaging_context *msg,
434 const struct auth_session_info *session_info,
435 struct conn_struct_tos **_c)
437 struct conn_struct_tos *c = NULL;
438 struct smb_filename smb_fname_connectpath = {0};
443 status = create_conn_struct_tos(msg,
448 if (!NT_STATUS_IS_OK(status)) {
453 * Windows seems to insist on doing trans2getdfsreferral() calls on
454 * the IPC$ share as the anonymous user. If we try to chdir as that
455 * user we will fail.... WTF ? JRA.
458 c->oldcwd_fname = vfs_GetWd(c, c->conn);
459 if (c->oldcwd_fname == NULL) {
460 status = map_nt_error_from_unix(errno);
461 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
466 smb_fname_connectpath = (struct smb_filename) {
467 .base_name = c->conn->connectpath
470 if (vfs_ChDir(c->conn, &smb_fname_connectpath) != 0) {
471 status = map_nt_error_from_unix(errno);
472 DBG_NOTICE("Can't ChDir to new conn path %s. "
474 c->conn->connectpath, strerror(errno));
475 TALLOC_FREE(c->oldcwd_fname);
484 static void shuffle_strlist(char **list, int count)
490 for (i = count; i > 1; i--) {
491 r = generate_random() % i;
499 /**********************************************************************
500 Parse the contents of a symlink to verify if it is an msdfs referral
501 A valid referral is of the form:
503 msdfs:server1\share1,server2\share2
504 msdfs:server1\share1\pathname,server2\share2\pathname
505 msdfs:server1/share1,server2/share2
506 msdfs:server1/share1/pathname,server2/share2/pathname.
508 Note that the alternate paths returned here must be of the canonicalized
512 \server\share\path\to\file,
514 even in posix path mode. This is because we have no knowledge if the
515 server we're referring to understands posix paths.
516 **********************************************************************/
518 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
521 struct referral **preflist,
526 char **alt_path = NULL;
528 struct referral *reflist;
531 temp = talloc_strdup(ctx, target);
535 prot = strtok_r(temp, ":", &saveptr);
537 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
541 alt_path = talloc_array(ctx, char *, MAX_REFERRAL_COUNT);
546 /* parse out the alternate paths */
547 while((count<MAX_REFERRAL_COUNT) &&
548 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
552 /* shuffle alternate paths */
553 if (lp_msdfs_shuffle_referrals(snum)) {
554 shuffle_strlist(alt_path, count);
557 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
560 reflist = *preflist = talloc_zero_array(ctx,
561 struct referral, count);
562 if(reflist == NULL) {
563 TALLOC_FREE(alt_path);
567 reflist = *preflist = NULL;
570 for(i=0;i<count;i++) {
573 /* Canonicalize link target.
574 * Replace all /'s in the path by a \ */
575 string_replace(alt_path[i], '/', '\\');
577 /* Remove leading '\\'s */
579 while (*p && (*p == '\\')) {
583 reflist[i].alternate_path = talloc_asprintf(ctx,
586 if (!reflist[i].alternate_path) {
590 reflist[i].proximity = 0;
591 reflist[i].ttl = REFERRAL_TTL;
592 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
593 reflist[i].alternate_path));
598 TALLOC_FREE(alt_path);
602 /**********************************************************************
603 Returns true if the unix path is a valid msdfs symlink and also
604 returns the target string from inside the link.
605 **********************************************************************/
607 static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
608 connection_struct *conn,
609 struct smb_filename *smb_fname,
610 char **pp_link_target)
612 int referral_len = 0;
613 #if defined(HAVE_BROKEN_READLINK)
614 char link_target_buf[PATH_MAX];
616 char link_target_buf[7];
619 char *link_target = NULL;
621 if (pp_link_target) {
623 link_target = talloc_array(ctx, char, bufsize);
627 *pp_link_target = link_target;
629 bufsize = sizeof(link_target_buf);
630 link_target = link_target_buf;
633 if (SMB_VFS_LSTAT(conn, smb_fname) != 0) {
634 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
635 smb_fname->base_name));
638 if (!S_ISLNK(smb_fname->st.st_ex_mode)) {
639 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
640 smb_fname->base_name));
644 referral_len = SMB_VFS_READLINK(conn, smb_fname,
645 link_target, bufsize - 1);
646 if (referral_len == -1) {
647 DEBUG(0,("is_msdfs_link_read_target: Error reading "
648 "msdfs link %s: %s\n",
649 smb_fname->base_name, strerror(errno)));
652 link_target[referral_len] = '\0';
654 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n", smb_fname->base_name,
657 if (!strnequal(link_target, "msdfs:", 6)) {
664 if (link_target != link_target_buf) {
665 TALLOC_FREE(link_target);
670 /**********************************************************************
671 Returns true if the unix path is a valid msdfs symlink.
672 **********************************************************************/
674 bool is_msdfs_link(connection_struct *conn,
675 struct smb_filename *smb_fname)
677 return is_msdfs_link_internal(talloc_tos(),
683 /*****************************************************************
684 Used by other functions to decide if a dfs path is remote,
685 and to get the list of referred locations for that remote path.
687 search_flag: For findfirsts, dfs links themselves are not
688 redirected, but paths beyond the links are. For normal smb calls,
689 even dfs links need to be redirected.
691 consumedcntp: how much of the dfs path is being redirected. the client
692 should try the remaining path on the redirected server.
694 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
695 link redirect are in targetpath.
696 *****************************************************************/
698 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
699 connection_struct *conn,
700 const char *dfspath, /* Incoming complete dfs path */
701 const struct dfs_path *pdp, /* Parsed out
702 server+share+extrapath. */
705 char **pp_targetpath)
710 struct smb_filename *smb_fname = NULL;
711 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
714 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
715 conn->connectpath, pdp->reqpath));
718 * Note the unix path conversion here we're doing we
719 * throw away. We're looking for a symlink for a dfs
720 * resolution, if we don't find it we'll do another
721 * unix_convert later in the codepath.
724 status = unix_convert(ctx, conn, pdp->reqpath, &smb_fname,
727 if (!NT_STATUS_IS_OK(status)) {
728 if (!NT_STATUS_EQUAL(status,
729 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
732 if (smb_fname == NULL || smb_fname->base_name == NULL) {
737 /* Optimization - check if we can redirect the whole path. */
739 if (is_msdfs_link_internal(ctx, conn, smb_fname, pp_targetpath)) {
740 /* XX_ALLOW_WCARD_XXX is called from search functions. */
742 (UCF_COND_ALLOW_WCARD_LCOMP|
743 UCF_ALWAYS_ALLOW_WCARD_LCOMP)) {
744 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
745 "for dfs link %s.\n", dfspath));
746 status = NT_STATUS_OK;
750 DEBUG(6,("dfs_path_lookup: %s resolves to a "
751 "valid dfs link %s.\n", dfspath,
752 pp_targetpath ? *pp_targetpath : ""));
755 *consumedcntp = strlen(dfspath);
757 status = NT_STATUS_PATH_NOT_COVERED;
761 /* Prepare to test only for '/' components in the given path,
762 * so if a Windows path replace all '\\' characters with '/'.
763 * For a POSIX DFS path we know all separators are already '/'. */
765 canon_dfspath = talloc_strdup(ctx, dfspath);
766 if (!canon_dfspath) {
767 status = NT_STATUS_NO_MEMORY;
770 if (!pdp->posix_path) {
771 string_replace(canon_dfspath, '\\', '/');
775 * localpath comes out of unix_convert, so it has
776 * no trailing backslash. Make sure that canon_dfspath hasn't either.
777 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
780 trim_char(canon_dfspath,0,'/');
783 * Redirect if any component in the path is a link.
784 * We do this by walking backwards through the
785 * local path, chopping off the last component
786 * in both the local path and the canonicalized
787 * DFS path. If we hit a DFS link then we're done.
790 p = strrchr_m(smb_fname->base_name, '/');
792 q = strrchr_m(canon_dfspath, '/');
801 if (is_msdfs_link_internal(ctx, conn,
802 smb_fname, pp_targetpath)) {
803 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
804 "parent %s is dfs link\n", dfspath,
805 smb_fname_str_dbg(smb_fname)));
808 *consumedcntp = strlen(canon_dfspath);
809 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
815 status = NT_STATUS_PATH_NOT_COVERED;
819 /* Step back on the filesystem. */
820 p = strrchr_m(smb_fname->base_name, '/');
823 /* And in the canonicalized dfs path. */
824 q = strrchr_m(canon_dfspath, '/');
828 status = NT_STATUS_OK;
830 TALLOC_FREE(smb_fname);
834 /*****************************************************************
835 Decides if a dfs pathname should be redirected or not.
836 If not, the pathname is converted to a tcon-relative local unix path
838 search_wcard_flag: this flag performs 2 functions both related
839 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
842 This function can return NT_STATUS_OK, meaning use the returned path as-is
843 (mapped into a local path).
844 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
845 any other NT_STATUS error which is a genuine error to be
846 returned to the client.
847 *****************************************************************/
849 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
850 connection_struct *conn,
853 bool allow_broken_path,
855 bool *ppath_contains_wcard)
858 bool search_wcard_flag = (ucf_flags &
859 (UCF_COND_ALLOW_WCARD_LCOMP|UCF_ALWAYS_ALLOW_WCARD_LCOMP));
860 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
863 return NT_STATUS_NO_MEMORY;
866 status = parse_dfs_path(conn, path_in, search_wcard_flag,
867 allow_broken_path, pdp,
868 ppath_contains_wcard);
869 if (!NT_STATUS_IS_OK(status)) {
874 if (pdp->reqpath[0] == '\0') {
876 *pp_path_out = talloc_strdup(ctx, "");
878 return NT_STATUS_NO_MEMORY;
880 DEBUG(5,("dfs_redirect: self-referral.\n"));
884 /* If dfs pathname for a non-dfs share, convert to tcon-relative
885 path and return OK */
887 if (!lp_msdfs_root(SNUM(conn))) {
888 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
891 return NT_STATUS_NO_MEMORY;
896 /* If it looked like a local path (zero hostname/servicename)
897 * just treat as a tcon-relative path. */
899 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
900 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
903 return NT_STATUS_NO_MEMORY;
908 if (!( strequal(pdp->servicename, lp_servicename(talloc_tos(), SNUM(conn)))
909 || (strequal(pdp->servicename, HOMES_NAME)
910 && strequal(lp_servicename(talloc_tos(), SNUM(conn)),
911 conn->session_info->unix_info->sanitized_username) )) ) {
913 /* The given sharename doesn't match this connection. */
916 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
919 status = dfs_path_lookup(ctx, conn, path_in, pdp,
920 ucf_flags, NULL, NULL);
921 if (!NT_STATUS_IS_OK(status)) {
922 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
923 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
925 DEBUG(10,("dfs_redirect: dfs_path_lookup "
926 "failed for %s with %s\n",
927 path_in, nt_errstr(status) ));
932 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
934 /* Form non-dfs tcon-relative path */
935 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
938 return NT_STATUS_NO_MEMORY;
941 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
948 /**********************************************************************
949 Return a self referral.
950 **********************************************************************/
952 static NTSTATUS self_ref(TALLOC_CTX *ctx,
953 const char *dfs_path,
954 struct junction_map *jucn,
956 bool *self_referralp)
958 struct referral *ref;
960 *self_referralp = True;
962 jucn->referral_count = 1;
963 if((ref = talloc_zero(ctx, struct referral)) == NULL) {
964 return NT_STATUS_NO_MEMORY;
967 ref->alternate_path = talloc_strdup(ctx, dfs_path);
968 if (!ref->alternate_path) {
970 return NT_STATUS_NO_MEMORY;
973 ref->ttl = REFERRAL_TTL;
974 jucn->referral_list = ref;
975 *consumedcntp = strlen(dfs_path);
979 /**********************************************************************
980 Gets valid referrals for a dfs path and fills up the
981 junction_map structure.
982 **********************************************************************/
984 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
985 const char *dfs_path,
986 const struct tsocket_address *remote_address,
987 const struct tsocket_address *local_address,
988 bool allow_broken_path,
989 struct junction_map *jucn,
991 bool *self_referralp)
993 TALLOC_CTX *frame = talloc_stackframe();
994 struct conn_struct_tos *c = NULL;
995 struct connection_struct *conn = NULL;
996 char *targetpath = NULL;
998 NTSTATUS status = NT_STATUS_NOT_FOUND;
1000 struct dfs_path *pdp = talloc_zero(frame, struct dfs_path);
1004 return NT_STATUS_NO_MEMORY;
1007 *self_referralp = False;
1009 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1011 if (!NT_STATUS_IS_OK(status)) {
1016 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1017 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1018 if (!jucn->service_name || !jucn->volume_name) {
1020 return NT_STATUS_NO_MEMORY;
1023 /* Verify the share is a dfs root */
1024 snum = lp_servicenumber(jucn->service_name);
1026 char *service_name = NULL;
1027 if ((snum = find_service(ctx, jucn->service_name, &service_name)) < 0) {
1029 return NT_STATUS_NOT_FOUND;
1031 if (!service_name) {
1033 return NT_STATUS_NO_MEMORY;
1035 TALLOC_FREE(jucn->service_name);
1036 jucn->service_name = talloc_strdup(ctx, service_name);
1037 if (!jucn->service_name) {
1039 return NT_STATUS_NO_MEMORY;
1043 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(talloc_tos(), snum) == '\0')) {
1044 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
1046 pdp->servicename, dfs_path));
1048 return NT_STATUS_NOT_FOUND;
1052 * Self referrals are tested with a anonymous IPC connection and
1053 * a GET_DFS_REFERRAL call to \\server\share. (which means
1054 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
1055 * into the directory and will fail if it cannot (as the anonymous
1056 * user). Cope with this.
1059 if (pdp->reqpath[0] == '\0') {
1061 struct referral *ref;
1064 if (*lp_msdfs_proxy(talloc_tos(), snum) == '\0') {
1066 return self_ref(ctx,
1074 * It's an msdfs proxy share. Redirect to
1075 * the configured target share.
1078 tmp = talloc_asprintf(frame, "msdfs:%s",
1079 lp_msdfs_proxy(frame, snum));
1082 return NT_STATUS_NO_MEMORY;
1085 if (!parse_msdfs_symlink(ctx, snum, tmp, &ref, &refcount)) {
1087 return NT_STATUS_INVALID_PARAMETER;
1089 jucn->referral_count = refcount;
1090 jucn->referral_list = ref;
1091 *consumedcntp = strlen(dfs_path);
1093 return NT_STATUS_OK;
1096 status = create_conn_struct_tos_cwd(server_messaging_context(),
1098 lp_path(frame, snum),
1101 if (!NT_STATUS_IS_OK(status)) {
1110 * The remote and local address should be passed down to
1111 * create_conn_struct_cwd.
1113 if (conn->sconn->remote_address == NULL) {
1114 conn->sconn->remote_address =
1115 tsocket_address_copy(remote_address, conn->sconn);
1116 if (conn->sconn->remote_address == NULL) {
1118 return NT_STATUS_NO_MEMORY;
1121 if (conn->sconn->local_address == NULL) {
1122 conn->sconn->local_address =
1123 tsocket_address_copy(local_address, conn->sconn);
1124 if (conn->sconn->local_address == NULL) {
1126 return NT_STATUS_NO_MEMORY;
1130 /* If this is a DFS path dfs_lookup should return
1131 * NT_STATUS_PATH_NOT_COVERED. */
1133 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
1134 0, consumedcntp, &targetpath);
1136 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
1137 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
1139 if (NT_STATUS_IS_OK(status)) {
1141 * We are in an error path here (we
1142 * know it's not a DFS path), but
1143 * dfs_path_lookup() can return
1144 * NT_STATUS_OK. Ensure we always
1145 * return a valid error code.
1147 * #9588 - ACLs are not inherited to directories
1150 status = NT_STATUS_NOT_FOUND;
1155 /* We know this is a valid dfs link. Parse the targetpath. */
1156 if (!parse_msdfs_symlink(ctx, snum, targetpath,
1157 &jucn->referral_list,
1158 &jucn->referral_count)) {
1159 DEBUG(3,("get_referred_path: failed to parse symlink "
1160 "target %s\n", targetpath ));
1161 status = NT_STATUS_NOT_FOUND;
1165 status = NT_STATUS_OK;
1171 /******************************************************************
1172 Set up the DFS referral for the dfs pathname. This call returns
1173 the amount of the path covered by this server, and where the
1174 client should be redirected to. This is the meat of the
1175 TRANS2_GET_DFS_REFERRAL call.
1176 ******************************************************************/
1178 int setup_dfs_referral(connection_struct *orig_conn,
1179 const char *dfs_path,
1180 int max_referral_level,
1181 char **ppdata, NTSTATUS *pstatus)
1183 char *pdata = *ppdata;
1185 struct dfs_GetDFSReferral *r;
1186 DATA_BLOB blob = data_blob_null;
1188 enum ndr_err_code ndr_err;
1190 r = talloc_zero(talloc_tos(), struct dfs_GetDFSReferral);
1192 *pstatus = NT_STATUS_NO_MEMORY;
1196 r->in.req.max_referral_level = max_referral_level;
1197 r->in.req.servername = talloc_strdup(r, dfs_path);
1198 if (r->in.req.servername == NULL) {
1200 *pstatus = NT_STATUS_NO_MEMORY;
1204 status = SMB_VFS_GET_DFS_REFERRALS(orig_conn, r);
1205 if (!NT_STATUS_IS_OK(status)) {
1211 ndr_err = ndr_push_struct_blob(&blob, r,
1213 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1214 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1216 *pstatus = NT_STATUS_INVALID_PARAMETER;
1220 pdata = (char *)SMB_REALLOC(pdata, blob.length);
1223 DEBUG(0,("referral setup:"
1224 "malloc failed for Realloc!\n"));
1228 reply_size = blob.length;
1229 memcpy(pdata, blob.data, blob.length);
1232 *pstatus = NT_STATUS_OK;
1236 /**********************************************************************
1237 The following functions are called by the NETDFS RPC pipe functions
1238 **********************************************************************/
1240 /*********************************************************************
1241 Creates a junction structure from a DFS pathname
1242 **********************************************************************/
1244 bool create_junction(TALLOC_CTX *ctx,
1245 const char *dfs_path,
1246 bool allow_broken_path,
1247 struct junction_map *jucn)
1251 struct dfs_path *pdp = talloc(ctx,struct dfs_path);
1257 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1259 if (!NT_STATUS_IS_OK(status)) {
1263 /* check if path is dfs : validate first token */
1264 if (!is_myname_or_ipaddr(pdp->hostname)) {
1265 DEBUG(4,("create_junction: Invalid hostname %s "
1267 pdp->hostname, dfs_path));
1272 /* Check for a non-DFS share */
1273 snum = lp_servicenumber(pdp->servicename);
1275 if(snum < 0 || !lp_msdfs_root(snum)) {
1276 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1282 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1283 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1284 jucn->comment = lp_comment(ctx, snum);
1287 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1293 /**********************************************************************
1294 Forms a valid Unix pathname from the junction
1295 **********************************************************************/
1297 static bool junction_to_local_path_tos(const struct junction_map *jucn,
1299 connection_struct **conn_out)
1301 struct conn_struct_tos *c = NULL;
1303 char *path_out = NULL;
1306 snum = lp_servicenumber(jucn->service_name);
1310 status = create_conn_struct_tos_cwd(server_messaging_context(),
1312 lp_path(talloc_tos(), snum),
1315 if (!NT_STATUS_IS_OK(status)) {
1319 path_out = talloc_asprintf(c,
1321 lp_path(talloc_tos(), snum),
1323 if (path_out == NULL) {
1327 *pp_path_out = path_out;
1328 *conn_out = c->conn;
1332 bool create_msdfs_link(const struct junction_map *jucn)
1334 TALLOC_CTX *frame = talloc_stackframe();
1336 char *msdfs_link = NULL;
1337 connection_struct *conn;
1339 bool insert_comma = False;
1341 struct smb_filename *smb_fname = NULL;
1344 ok = junction_to_local_path_tos(jucn, &path, &conn);
1350 /* Form the msdfs_link contents */
1351 msdfs_link = talloc_strdup(conn, "msdfs:");
1355 for(i=0; i<jucn->referral_count; i++) {
1356 char *refpath = jucn->referral_list[i].alternate_path;
1358 /* Alternate paths always use Windows separators. */
1359 trim_char(refpath, '\\', '\\');
1360 if(*refpath == '\0') {
1362 insert_comma = False;
1366 if (i > 0 && insert_comma) {
1367 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1371 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1379 if (!insert_comma) {
1380 insert_comma = True;
1384 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1387 smb_fname = synthetic_smb_fname(frame,
1392 if (smb_fname == NULL) {
1397 if(SMB_VFS_SYMLINK(conn, msdfs_link, smb_fname) < 0) {
1398 if (errno == EEXIST) {
1399 if(SMB_VFS_UNLINK(conn, smb_fname)!=0) {
1400 TALLOC_FREE(smb_fname);
1404 if (SMB_VFS_SYMLINK(conn, msdfs_link, smb_fname) < 0) {
1405 DEBUG(1,("create_msdfs_link: symlink failed "
1406 "%s -> %s\nError: %s\n",
1407 path, msdfs_link, strerror(errno)));
1419 bool remove_msdfs_link(const struct junction_map *jucn)
1421 TALLOC_CTX *frame = talloc_stackframe();
1423 connection_struct *conn;
1425 struct smb_filename *smb_fname;
1428 ok = junction_to_local_path_tos(jucn, &path, &conn);
1434 smb_fname = synthetic_smb_fname(frame,
1439 if (smb_fname == NULL) {
1445 if( SMB_VFS_UNLINK(conn, smb_fname) == 0 ) {
1453 /*********************************************************************
1454 Return the number of DFS links at the root of this share.
1455 *********************************************************************/
1457 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1459 TALLOC_CTX *frame = talloc_stackframe();
1462 const char *dname = NULL;
1463 char *talloced = NULL;
1464 const char *connect_path = lp_path(frame, snum);
1465 const char *msdfs_proxy = lp_msdfs_proxy(frame, snum);
1466 struct conn_struct_tos *c = NULL;
1467 connection_struct *conn = NULL;
1469 struct smb_filename *smb_fname = NULL;
1471 if(*connect_path == '\0') {
1477 * Fake up a connection struct for the VFS layer.
1480 status = create_conn_struct_tos_cwd(server_messaging_context(),
1485 if (!NT_STATUS_IS_OK(status)) {
1486 DEBUG(3, ("create_conn_struct failed: %s\n",
1487 nt_errstr(status)));
1493 /* Count a link for the msdfs root - convention */
1496 /* No more links if this is an msdfs proxy. */
1497 if (*msdfs_proxy != '\0') {
1501 smb_fname = synthetic_smb_fname(frame,
1506 if (smb_fname == NULL) {
1510 /* Now enumerate all dfs links */
1511 dirp = SMB_VFS_OPENDIR(conn, smb_fname, NULL, 0);
1516 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1518 struct smb_filename *smb_dname =
1519 synthetic_smb_fname(frame,
1524 if (smb_dname == NULL) {
1527 if (is_msdfs_link(conn, smb_dname)) {
1530 TALLOC_FREE(talloced);
1531 TALLOC_FREE(smb_dname);
1534 SMB_VFS_CLOSEDIR(conn,dirp);
1541 /*********************************************************************
1542 *********************************************************************/
1544 static int form_junctions(TALLOC_CTX *ctx,
1546 struct junction_map *jucn,
1549 TALLOC_CTX *frame = talloc_stackframe();
1552 const char *dname = NULL;
1553 char *talloced = NULL;
1554 const char *connect_path = lp_path(frame, snum);
1555 char *service_name = lp_servicename(frame, snum);
1556 const char *msdfs_proxy = lp_msdfs_proxy(frame, snum);
1557 struct conn_struct_tos *c = NULL;
1558 connection_struct *conn = NULL;
1559 struct referral *ref = NULL;
1560 struct smb_filename *smb_fname = NULL;
1563 if (jn_remain == 0) {
1568 if(*connect_path == '\0') {
1574 * Fake up a connection struct for the VFS layer.
1577 status = create_conn_struct_tos_cwd(server_messaging_context(),
1582 if (!NT_STATUS_IS_OK(status)) {
1583 DEBUG(3, ("create_conn_struct failed: %s\n",
1584 nt_errstr(status)));
1590 /* form a junction for the msdfs root - convention
1591 DO NOT REMOVE THIS: NT clients will not work with us
1592 if this is not present
1594 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1595 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1596 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1599 jucn[cnt].comment = "";
1600 jucn[cnt].referral_count = 1;
1602 ref = jucn[cnt].referral_list = talloc_zero(ctx, struct referral);
1603 if (jucn[cnt].referral_list == NULL) {
1608 ref->ttl = REFERRAL_TTL;
1609 if (*msdfs_proxy != '\0') {
1610 ref->alternate_path = talloc_strdup(ctx,
1613 ref->alternate_path = talloc_asprintf(ctx,
1615 get_local_machine_name(),
1619 if (!ref->alternate_path) {
1624 /* Don't enumerate if we're an msdfs proxy. */
1625 if (*msdfs_proxy != '\0') {
1629 smb_fname = synthetic_smb_fname(frame,
1634 if (smb_fname == NULL) {
1638 /* Now enumerate all dfs links */
1639 dirp = SMB_VFS_OPENDIR(conn, smb_fname, NULL, 0);
1644 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1646 char *link_target = NULL;
1647 struct smb_filename *smb_dname = NULL;
1649 if (cnt >= jn_remain) {
1650 DEBUG(2, ("form_junctions: ran out of MSDFS "
1652 TALLOC_FREE(talloced);
1655 smb_dname = synthetic_smb_fname(talloc_tos(),
1660 if (smb_dname == NULL) {
1661 TALLOC_FREE(talloced);
1664 if (is_msdfs_link_internal(ctx,
1666 smb_dname, &link_target)) {
1667 if (parse_msdfs_symlink(ctx, snum,
1669 &jucn[cnt].referral_list,
1670 &jucn[cnt].referral_count)) {
1672 jucn[cnt].service_name = talloc_strdup(ctx,
1674 jucn[cnt].volume_name = talloc_strdup(ctx,
1676 if (!jucn[cnt].service_name ||
1677 !jucn[cnt].volume_name) {
1678 TALLOC_FREE(talloced);
1681 jucn[cnt].comment = "";
1684 TALLOC_FREE(link_target);
1686 TALLOC_FREE(talloced);
1687 TALLOC_FREE(smb_dname);
1693 SMB_VFS_CLOSEDIR(conn,dirp);
1700 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1702 struct junction_map *jn = NULL;
1704 size_t jn_count = 0;
1708 if(!lp_host_msdfs()) {
1712 /* Ensure all the usershares are loaded. */
1714 load_registry_shares();
1715 sharecount = load_usershare_shares(NULL, connections_snum_used);
1718 for(i=0;i < sharecount;i++) {
1719 if(lp_msdfs_root(i)) {
1720 jn_count += count_dfs_links(ctx, i);
1723 if (jn_count == 0) {
1726 jn = talloc_array(ctx, struct junction_map, jn_count);
1730 for(i=0; i < sharecount; i++) {
1731 if (*p_num_jn >= jn_count) {
1734 if(lp_msdfs_root(i)) {
1735 *p_num_jn += form_junctions(ctx, i,
1737 jn_count - *p_num_jn);
1743 /******************************************************************************
1744 Core function to resolve a dfs pathname possibly containing a wildcard. If
1745 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1746 detected during dfs resolution.
1747 ******************************************************************************/
1749 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1750 connection_struct *conn,
1751 const char *name_in,
1753 bool allow_broken_path,
1755 bool *ppath_contains_wcard)
1757 bool path_contains_wcard = false;
1758 NTSTATUS status = NT_STATUS_OK;
1760 status = dfs_redirect(ctx,
1766 &path_contains_wcard);
1768 if (NT_STATUS_IS_OK(status) &&
1769 ppath_contains_wcard != NULL &&
1770 path_contains_wcard) {
1771 *ppath_contains_wcard = path_contains_wcard;