2 Unix SMB/Netbios implementation.
4 MSDFS services for Samba
5 Copyright (C) Shirish Kalele 2000
6 Copyright (C) Jeremy Allison 2007
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #define DBGC_CLASS DBGC_MSDFS
25 #include "system/filesys.h"
26 #include "smbd/smbd.h"
27 #include "smbd/globals.h"
30 #include "lib/param/loadparm.h"
31 #include "libcli/security/security.h"
33 /**********************************************************************
34 Parse a DFS pathname of the form \hostname\service\reqpath
35 into the dfs_path structure.
36 If POSIX pathnames is true, the pathname may also be of the
37 form /hostname/service/reqpath.
38 We cope with either here.
40 Unfortunately, due to broken clients who might set the
41 SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
42 send a local path, we have to cope with that too....
44 If conn != NULL then ensure the provided service is
45 the one pointed to by the connection.
47 This version does everything using pointers within one copy of the
48 pathname string, talloced on the struct dfs_path pointer (which
49 must be talloced). This may be too clever to live....
51 **********************************************************************/
53 static NTSTATUS
parse_dfs_path(connection_struct
*conn
,
56 bool allow_broken_path
,
57 struct dfs_path
*pdp
, /* MUST BE TALLOCED */
58 bool *ppath_contains_wcard
)
64 NTSTATUS status
= NT_STATUS_OK
;
70 * This is the only talloc we should need to do
71 * on the struct dfs_path. All the pointers inside
72 * it should point to offsets within this string.
75 pathname_local
= talloc_strdup(pdp
, pathname
);
76 if (!pathname_local
) {
77 return NT_STATUS_NO_MEMORY
;
79 /* Get a pointer to the terminating '\0' */
80 eos_ptr
= &pathname_local
[strlen(pathname_local
)];
81 p
= temp
= pathname_local
;
83 pdp
->posix_path
= (lp_posix_pathnames() && *pathname
== '/');
85 sepchar
= pdp
->posix_path
? '/' : '\\';
87 if (allow_broken_path
&& (*pathname
!= sepchar
)) {
88 DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
91 * Possibly client sent a local path by mistake.
92 * Try and convert to a local path.
95 pdp
->hostname
= eos_ptr
; /* "" */
96 pdp
->servicename
= eos_ptr
; /* "" */
98 /* We've got no info about separators. */
99 pdp
->posix_path
= lp_posix_pathnames();
101 DEBUG(10,("parse_dfs_path: trying to convert %s to a "
108 * Safe to use on talloc'ed string as it only shrinks.
109 * It also doesn't affect the eos_ptr.
111 trim_char(temp
,sepchar
,sepchar
);
113 DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
117 /* Parse out hostname. */
118 p
= strchr_m(temp
,sepchar
);
120 DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
123 * Possibly client sent a local path by mistake.
124 * Try and convert to a local path.
127 pdp
->hostname
= eos_ptr
; /* "" */
128 pdp
->servicename
= eos_ptr
; /* "" */
131 DEBUG(10,("parse_dfs_path: trying to convert %s "
137 pdp
->hostname
= temp
;
139 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp
->hostname
));
141 /* Parse out servicename. */
143 p
= strchr_m(servicename
,sepchar
);
148 /* Is this really our servicename ? */
149 if (conn
&& !( strequal(servicename
, lp_servicename(SNUM(conn
)))
150 || (strequal(servicename
, HOMES_NAME
)
151 && strequal(lp_servicename(SNUM(conn
)),
152 get_current_username()) )) ) {
153 DEBUG(10,("parse_dfs_path: %s is not our servicename\n",
157 * Possibly client sent a local path by mistake.
158 * Try and convert to a local path.
161 pdp
->hostname
= eos_ptr
; /* "" */
162 pdp
->servicename
= eos_ptr
; /* "" */
164 /* Repair the path - replace the sepchar's
167 *servicename
= sepchar
;
173 DEBUG(10,("parse_dfs_path: trying to convert %s "
179 pdp
->servicename
= servicename
;
181 DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp
->servicename
));
184 /* Client sent self referral \server\share. */
185 pdp
->reqpath
= eos_ptr
; /* "" */
193 *ppath_contains_wcard
= False
;
197 /* Rest is reqpath. */
198 if (pdp
->posix_path
) {
199 status
= check_path_syntax_posix(pdp
->reqpath
);
202 status
= check_path_syntax_wcard(pdp
->reqpath
,
203 ppath_contains_wcard
);
205 status
= check_path_syntax(pdp
->reqpath
);
209 if (!NT_STATUS_IS_OK(status
)) {
210 DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
211 p
, nt_errstr(status
) ));
215 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp
->reqpath
));
219 /********************************************************
220 Fake up a connection struct for the VFS layer.
221 Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
222 *********************************************************/
224 NTSTATUS
create_conn_struct(TALLOC_CTX
*ctx
,
225 struct smbd_server_connection
*sconn
,
226 connection_struct
**pconn
,
229 const struct auth_session_info
*session_info
,
232 connection_struct
*conn
;
235 const char *vfs_user
;
237 conn
= talloc_zero(ctx
, connection_struct
);
239 return NT_STATUS_NO_MEMORY
;
242 connpath
= talloc_strdup(conn
, path
);
245 return NT_STATUS_NO_MEMORY
;
247 connpath
= talloc_string_sub(conn
,
250 lp_servicename(snum
));
253 return NT_STATUS_NO_MEMORY
;
256 /* needed for smbd_vfs_init() */
258 if (!(conn
->params
= talloc_zero(conn
, struct share_params
))) {
259 DEBUG(0, ("TALLOC failed\n"));
261 return NT_STATUS_NO_MEMORY
;
264 conn
->params
->service
= snum
;
267 conn
->sconn
->num_tcons_open
++;
269 if (session_info
!= NULL
) {
270 conn
->session_info
= copy_session_info(conn
, session_info
);
271 if (conn
->session_info
== NULL
) {
272 DEBUG(0, ("copy_serverinfo failed\n"));
274 return NT_STATUS_NO_MEMORY
;
276 vfs_user
= conn
->session_info
->unix_info
->unix_name
;
278 /* use current authenticated user in absence of session_info */
279 vfs_user
= get_current_username();
282 set_conn_connectpath(conn
, connpath
);
285 * New code to check if there's a share security descripter
286 * added from NT server manager. This is done after the
287 * smb.conf checks are done as we need a uid and token. JRA.
290 if (conn
->session_info
) {
291 share_access_check(conn
->session_info
->security_token
,
292 lp_servicename(snum
), MAXIMUM_ALLOWED_ACCESS
,
293 &conn
->share_access
);
295 if ((conn
->share_access
& FILE_WRITE_DATA
) == 0) {
296 if ((conn
->share_access
& FILE_READ_DATA
) == 0) {
297 /* No access, read or write. */
298 DEBUG(0,("create_conn_struct: connection to %s "
299 "denied due to security "
301 lp_servicename(snum
)));
303 return NT_STATUS_ACCESS_DENIED
;
305 conn
->read_only
= true;
309 conn
->share_access
= 0;
310 conn
->read_only
= true;
313 if (!smbd_vfs_init(conn
)) {
314 NTSTATUS status
= map_nt_error_from_unix(errno
);
315 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
320 /* this must be the first filesystem operation that we do */
321 if (SMB_VFS_CONNECT(conn
, lp_servicename(snum
), vfs_user
) < 0) {
322 DEBUG(0,("VFS connect failed!\n"));
324 return NT_STATUS_UNSUCCESSFUL
;
327 conn
->fs_capabilities
= SMB_VFS_FS_CAPABILITIES(conn
, &conn
->ts_res
);
330 * Windows seems to insist on doing trans2getdfsreferral() calls on
331 * the IPC$ share as the anonymous user. If we try to chdir as that
332 * user we will fail.... WTF ? JRA.
335 oldcwd
= vfs_GetWd(ctx
, conn
);
336 if (oldcwd
== NULL
) {
337 NTSTATUS status
= map_nt_error_from_unix(errno
);
338 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno
)));
343 if (vfs_ChDir(conn
,conn
->connectpath
) != 0) {
344 NTSTATUS status
= map_nt_error_from_unix(errno
);
345 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
347 conn
->connectpath
, strerror(errno
) ));
358 /**********************************************************************
359 Parse the contents of a symlink to verify if it is an msdfs referral
360 A valid referral is of the form:
362 msdfs:server1\share1,server2\share2
363 msdfs:server1\share1\pathname,server2\share2\pathname
364 msdfs:server1/share1,server2/share2
365 msdfs:server1/share1/pathname,server2/share2/pathname.
367 Note that the alternate paths returned here must be of the canonicalized
371 \server\share\path\to\file,
373 even in posix path mode. This is because we have no knowledge if the
374 server we're referring to understands posix paths.
375 **********************************************************************/
377 static bool parse_msdfs_symlink(TALLOC_CTX
*ctx
,
379 struct referral
**preflist
,
384 char **alt_path
= NULL
;
386 struct referral
*reflist
;
389 temp
= talloc_strdup(ctx
, target
);
393 prot
= strtok_r(temp
, ":", &saveptr
);
395 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
399 alt_path
= talloc_array(ctx
, char *, MAX_REFERRAL_COUNT
);
404 /* parse out the alternate paths */
405 while((count
<MAX_REFERRAL_COUNT
) &&
406 ((alt_path
[count
] = strtok_r(NULL
, ",", &saveptr
)) != NULL
)) {
410 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count
));
413 reflist
= *preflist
= talloc_zero_array(ctx
,
414 struct referral
, count
);
415 if(reflist
== NULL
) {
416 TALLOC_FREE(alt_path
);
420 reflist
= *preflist
= NULL
;
423 for(i
=0;i
<count
;i
++) {
426 /* Canonicalize link target.
427 * Replace all /'s in the path by a \ */
428 string_replace(alt_path
[i
], '/', '\\');
430 /* Remove leading '\\'s */
432 while (*p
&& (*p
== '\\')) {
436 reflist
[i
].alternate_path
= talloc_asprintf(ctx
,
439 if (!reflist
[i
].alternate_path
) {
443 reflist
[i
].proximity
= 0;
444 reflist
[i
].ttl
= REFERRAL_TTL
;
445 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
446 reflist
[i
].alternate_path
));
451 TALLOC_FREE(alt_path
);
455 /**********************************************************************
456 Returns true if the unix path is a valid msdfs symlink and also
457 returns the target string from inside the link.
458 **********************************************************************/
460 static bool is_msdfs_link_internal(TALLOC_CTX
*ctx
,
461 connection_struct
*conn
,
463 char **pp_link_target
,
464 SMB_STRUCT_STAT
*sbufp
)
466 int referral_len
= 0;
467 #if defined(HAVE_BROKEN_READLINK)
468 char link_target_buf
[PATH_MAX
];
470 char link_target_buf
[7];
473 char *link_target
= NULL
;
474 struct smb_filename smb_fname
;
476 if (pp_link_target
) {
478 link_target
= talloc_array(ctx
, char, bufsize
);
482 *pp_link_target
= link_target
;
484 bufsize
= sizeof(link_target_buf
);
485 link_target
= link_target_buf
;
488 ZERO_STRUCT(smb_fname
);
489 smb_fname
.base_name
= discard_const_p(char, path
);
491 if (SMB_VFS_LSTAT(conn
, &smb_fname
) != 0) {
492 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
496 if (!S_ISLNK(smb_fname
.st
.st_ex_mode
)) {
497 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
502 *sbufp
= smb_fname
.st
;
505 referral_len
= SMB_VFS_READLINK(conn
, path
, link_target
, bufsize
- 1);
506 if (referral_len
== -1) {
507 DEBUG(0,("is_msdfs_link_read_target: Error reading "
508 "msdfs link %s: %s\n",
509 path
, strerror(errno
)));
512 link_target
[referral_len
] = '\0';
514 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path
,
517 if (!strnequal(link_target
, "msdfs:", 6)) {
524 if (link_target
!= link_target_buf
) {
525 TALLOC_FREE(link_target
);
530 /**********************************************************************
531 Returns true if the unix path is a valid msdfs symlink.
532 **********************************************************************/
534 bool is_msdfs_link(connection_struct
*conn
,
536 SMB_STRUCT_STAT
*sbufp
)
538 return is_msdfs_link_internal(talloc_tos(),
545 /*****************************************************************
546 Used by other functions to decide if a dfs path is remote,
547 and to get the list of referred locations for that remote path.
549 search_flag: For findfirsts, dfs links themselves are not
550 redirected, but paths beyond the links are. For normal smb calls,
551 even dfs links need to be redirected.
553 consumedcntp: how much of the dfs path is being redirected. the client
554 should try the remaining path on the redirected server.
556 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
557 link redirect are in targetpath.
558 *****************************************************************/
560 static NTSTATUS
dfs_path_lookup(TALLOC_CTX
*ctx
,
561 connection_struct
*conn
,
562 const char *dfspath
, /* Incoming complete dfs path */
563 const struct dfs_path
*pdp
, /* Parsed out
564 server+share+extrapath. */
565 bool search_flag
, /* Called from a findfirst ? */
567 char **pp_targetpath
)
572 struct smb_filename
*smb_fname
= NULL
;
573 char *canon_dfspath
= NULL
; /* Canonicalized dfs path. (only '/'
576 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
577 conn
->connectpath
, pdp
->reqpath
));
580 * Note the unix path conversion here we're doing we can
581 * throw away. We're looking for a symlink for a dfs
582 * resolution, if we don't find it we'll do another
583 * unix_convert later in the codepath.
584 * If we needed to remember what we'd resolved in
585 * dp->reqpath (as the original code did) we'd
586 * copy (localhost, dp->reqpath) on any code
587 * path below that returns True - but I don't
588 * think this is needed. JRA.
591 status
= unix_convert(ctx
, conn
, pdp
->reqpath
, &smb_fname
,
592 search_flag
? UCF_ALWAYS_ALLOW_WCARD_LCOMP
: 0);
594 if (!NT_STATUS_IS_OK(status
)) {
595 if (!NT_STATUS_EQUAL(status
,
596 NT_STATUS_OBJECT_PATH_NOT_FOUND
)) {
600 /* Create an smb_fname to use below. */
601 status
= create_synthetic_smb_fname(ctx
, pdp
->reqpath
, NULL
,
603 if (!NT_STATUS_IS_OK(status
)) {
608 /* Optimization - check if we can redirect the whole path. */
610 if (is_msdfs_link_internal(ctx
, conn
, smb_fname
->base_name
,
611 pp_targetpath
, NULL
)) {
613 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
614 "for dfs link %s.\n", dfspath
));
615 status
= NT_STATUS_OK
;
619 DEBUG(6,("dfs_path_lookup: %s resolves to a "
620 "valid dfs link %s.\n", dfspath
,
621 pp_targetpath
? *pp_targetpath
: ""));
624 *consumedcntp
= strlen(dfspath
);
626 status
= NT_STATUS_PATH_NOT_COVERED
;
630 /* Prepare to test only for '/' components in the given path,
631 * so if a Windows path replace all '\\' characters with '/'.
632 * For a POSIX DFS path we know all separators are already '/'. */
634 canon_dfspath
= talloc_strdup(ctx
, dfspath
);
635 if (!canon_dfspath
) {
636 status
= NT_STATUS_NO_MEMORY
;
639 if (!pdp
->posix_path
) {
640 string_replace(canon_dfspath
, '\\', '/');
644 * localpath comes out of unix_convert, so it has
645 * no trailing backslash. Make sure that canon_dfspath hasn't either.
646 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
649 trim_char(canon_dfspath
,0,'/');
652 * Redirect if any component in the path is a link.
653 * We do this by walking backwards through the
654 * local path, chopping off the last component
655 * in both the local path and the canonicalized
656 * DFS path. If we hit a DFS link then we're done.
659 p
= strrchr_m(smb_fname
->base_name
, '/');
661 q
= strrchr_m(canon_dfspath
, '/');
670 if (is_msdfs_link_internal(ctx
, conn
,
671 smb_fname
->base_name
, pp_targetpath
,
673 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
674 "parent %s is dfs link\n", dfspath
,
675 smb_fname_str_dbg(smb_fname
)));
678 *consumedcntp
= strlen(canon_dfspath
);
679 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
685 status
= NT_STATUS_PATH_NOT_COVERED
;
689 /* Step back on the filesystem. */
690 p
= strrchr_m(smb_fname
->base_name
, '/');
693 /* And in the canonicalized dfs path. */
694 q
= strrchr_m(canon_dfspath
, '/');
698 status
= NT_STATUS_OK
;
700 TALLOC_FREE(smb_fname
);
704 /*****************************************************************
705 Decides if a dfs pathname should be redirected or not.
706 If not, the pathname is converted to a tcon-relative local unix path
708 search_wcard_flag: this flag performs 2 functions both related
709 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
712 This function can return NT_STATUS_OK, meaning use the returned path as-is
713 (mapped into a local path).
714 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
715 any other NT_STATUS error which is a genuine error to be
716 returned to the client.
717 *****************************************************************/
719 static NTSTATUS
dfs_redirect(TALLOC_CTX
*ctx
,
720 connection_struct
*conn
,
722 bool search_wcard_flag
,
723 bool allow_broken_path
,
725 bool *ppath_contains_wcard
)
728 struct dfs_path
*pdp
= talloc(ctx
, struct dfs_path
);
731 return NT_STATUS_NO_MEMORY
;
734 status
= parse_dfs_path(conn
, path_in
, search_wcard_flag
,
735 allow_broken_path
, pdp
,
736 ppath_contains_wcard
);
737 if (!NT_STATUS_IS_OK(status
)) {
742 if (pdp
->reqpath
[0] == '\0') {
744 *pp_path_out
= talloc_strdup(ctx
, "");
746 return NT_STATUS_NO_MEMORY
;
748 DEBUG(5,("dfs_redirect: self-referral.\n"));
752 /* If dfs pathname for a non-dfs share, convert to tcon-relative
753 path and return OK */
755 if (!lp_msdfs_root(SNUM(conn
))) {
756 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
759 return NT_STATUS_NO_MEMORY
;
764 /* If it looked like a local path (zero hostname/servicename)
765 * just treat as a tcon-relative path. */
767 if (pdp
->hostname
[0] == '\0' && pdp
->servicename
[0] == '\0') {
768 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
771 return NT_STATUS_NO_MEMORY
;
776 if (!( strequal(pdp
->servicename
, lp_servicename(SNUM(conn
)))
777 || (strequal(pdp
->servicename
, HOMES_NAME
)
778 && strequal(lp_servicename(SNUM(conn
)),
779 conn
->session_info
->unix_info
->sanitized_username
) )) ) {
781 /* The given sharename doesn't match this connection. */
784 return NT_STATUS_OBJECT_PATH_NOT_FOUND
;
787 status
= dfs_path_lookup(ctx
, conn
, path_in
, pdp
,
788 search_wcard_flag
, NULL
, NULL
);
789 if (!NT_STATUS_IS_OK(status
)) {
790 if (NT_STATUS_EQUAL(status
, NT_STATUS_PATH_NOT_COVERED
)) {
791 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in
));
793 DEBUG(10,("dfs_redirect: dfs_path_lookup "
794 "failed for %s with %s\n",
795 path_in
, nt_errstr(status
) ));
800 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in
));
802 /* Form non-dfs tcon-relative path */
803 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
806 return NT_STATUS_NO_MEMORY
;
809 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
816 /**********************************************************************
817 Return a self referral.
818 **********************************************************************/
820 static NTSTATUS
self_ref(TALLOC_CTX
*ctx
,
821 const char *dfs_path
,
822 struct junction_map
*jucn
,
824 bool *self_referralp
)
826 struct referral
*ref
;
828 *self_referralp
= True
;
830 jucn
->referral_count
= 1;
831 if((ref
= talloc_zero(ctx
, struct referral
)) == NULL
) {
832 return NT_STATUS_NO_MEMORY
;
835 ref
->alternate_path
= talloc_strdup(ctx
, dfs_path
);
836 if (!ref
->alternate_path
) {
837 return NT_STATUS_NO_MEMORY
;
840 ref
->ttl
= REFERRAL_TTL
;
841 jucn
->referral_list
= ref
;
842 *consumedcntp
= strlen(dfs_path
);
846 /**********************************************************************
847 Gets valid referrals for a dfs path and fills up the
848 junction_map structure.
849 **********************************************************************/
851 NTSTATUS
get_referred_path(TALLOC_CTX
*ctx
,
852 const char *dfs_path
,
853 struct smbd_server_connection
*sconn
,
854 struct junction_map
*jucn
,
856 bool *self_referralp
)
858 struct connection_struct
*conn
;
859 char *targetpath
= NULL
;
861 NTSTATUS status
= NT_STATUS_NOT_FOUND
;
863 struct dfs_path
*pdp
= talloc(ctx
, struct dfs_path
);
867 return NT_STATUS_NO_MEMORY
;
870 *self_referralp
= False
;
872 status
= parse_dfs_path(NULL
, dfs_path
, False
, !sconn
->using_smb2
,
874 if (!NT_STATUS_IS_OK(status
)) {
878 jucn
->service_name
= talloc_strdup(ctx
, pdp
->servicename
);
879 jucn
->volume_name
= talloc_strdup(ctx
, pdp
->reqpath
);
880 if (!jucn
->service_name
|| !jucn
->volume_name
) {
882 return NT_STATUS_NO_MEMORY
;
885 /* Verify the share is a dfs root */
886 snum
= lp_servicenumber(jucn
->service_name
);
888 char *service_name
= NULL
;
889 if ((snum
= find_service(ctx
, jucn
->service_name
, &service_name
)) < 0) {
890 return NT_STATUS_NOT_FOUND
;
893 return NT_STATUS_NO_MEMORY
;
895 TALLOC_FREE(jucn
->service_name
);
896 jucn
->service_name
= talloc_strdup(ctx
, service_name
);
897 if (!jucn
->service_name
) {
899 return NT_STATUS_NO_MEMORY
;
903 if (!lp_msdfs_root(snum
) && (*lp_msdfs_proxy(snum
) == '\0')) {
904 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
906 pdp
->servicename
, dfs_path
));
908 return NT_STATUS_NOT_FOUND
;
912 * Self referrals are tested with a anonymous IPC connection and
913 * a GET_DFS_REFERRAL call to \\server\share. (which means
914 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
915 * into the directory and will fail if it cannot (as the anonymous
916 * user). Cope with this.
919 if (pdp
->reqpath
[0] == '\0') {
921 struct referral
*ref
;
923 if (*lp_msdfs_proxy(snum
) == '\0') {
933 * It's an msdfs proxy share. Redirect to
934 * the configured target share.
937 jucn
->referral_count
= 1;
938 if ((ref
= talloc_zero(ctx
, struct referral
)) == NULL
) {
940 return NT_STATUS_NO_MEMORY
;
943 if (!(tmp
= talloc_strdup(ctx
, lp_msdfs_proxy(snum
)))) {
945 return NT_STATUS_NO_MEMORY
;
948 trim_string(tmp
, "\\", 0);
950 ref
->alternate_path
= talloc_asprintf(ctx
, "\\%s", tmp
);
953 if (!ref
->alternate_path
) {
955 return NT_STATUS_NO_MEMORY
;
958 if (pdp
->reqpath
[0] != '\0') {
959 ref
->alternate_path
= talloc_asprintf_append(
963 if (!ref
->alternate_path
) {
965 return NT_STATUS_NO_MEMORY
;
969 ref
->ttl
= REFERRAL_TTL
;
970 jucn
->referral_list
= ref
;
971 *consumedcntp
= strlen(dfs_path
);
976 status
= create_conn_struct(ctx
, sconn
, &conn
, snum
,
977 lp_pathname(snum
), NULL
, &oldpath
);
978 if (!NT_STATUS_IS_OK(status
)) {
983 /* If this is a DFS path dfs_lookup should return
984 * NT_STATUS_PATH_NOT_COVERED. */
986 status
= dfs_path_lookup(ctx
, conn
, dfs_path
, pdp
,
987 False
, consumedcntp
, &targetpath
);
989 if (!NT_STATUS_EQUAL(status
, NT_STATUS_PATH_NOT_COVERED
)) {
990 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
995 /* We know this is a valid dfs link. Parse the targetpath. */
996 if (!parse_msdfs_symlink(ctx
, targetpath
,
997 &jucn
->referral_list
,
998 &jucn
->referral_count
)) {
999 DEBUG(3,("get_referred_path: failed to parse symlink "
1000 "target %s\n", targetpath
));
1001 status
= NT_STATUS_NOT_FOUND
;
1005 status
= NT_STATUS_OK
;
1007 vfs_ChDir(conn
, oldpath
);
1008 SMB_VFS_DISCONNECT(conn
);
1014 static int setup_ver2_dfs_referral(const char *pathname
,
1016 struct junction_map
*junction
,
1019 char* pdata
= *ppdata
;
1021 smb_ucs2_t
*uni_requestedpath
= NULL
;
1022 int uni_reqpathoffset1
,uni_reqpathoffset2
;
1024 int requestedpathlen
=0;
1029 DEBUG(10,("Setting up version2 referral\nRequested path:\n"));
1031 requestedpathlen
= rpcstr_push_talloc(talloc_tos(),
1032 &uni_requestedpath
, pathname
);
1033 if (uni_requestedpath
== NULL
|| requestedpathlen
== 0) {
1038 dump_data(0, (unsigned char *)uni_requestedpath
,
1042 DEBUG(10,("ref count = %u\n",junction
->referral_count
));
1044 uni_reqpathoffset1
= REFERRAL_HEADER_SIZE
+
1045 VERSION2_REFERRAL_SIZE
* junction
->referral_count
;
1047 uni_reqpathoffset2
= uni_reqpathoffset1
+ requestedpathlen
;
1049 uni_curroffset
= uni_reqpathoffset2
+ requestedpathlen
;
1051 reply_size
= REFERRAL_HEADER_SIZE
+
1052 VERSION2_REFERRAL_SIZE
*junction
->referral_count
+
1053 2 * requestedpathlen
;
1054 DEBUG(10,("reply_size: %u\n",reply_size
));
1056 /* add up the unicode lengths of all the referral paths */
1057 for(i
=0;i
<junction
->referral_count
;i
++) {
1058 DEBUG(10,("referral %u : %s\n",
1060 junction
->referral_list
[i
].alternate_path
));
1062 (strlen(junction
->referral_list
[i
].alternate_path
)+1)*2;
1065 DEBUG(10,("reply_size = %u\n",reply_size
));
1066 /* add the unexplained 0x16 bytes */
1069 pdata
= (char *)SMB_REALLOC(pdata
,reply_size
);
1071 DEBUG(0,("Realloc failed!\n"));
1076 /* copy in the dfs requested paths.. required for offset calculations */
1077 memcpy(pdata
+uni_reqpathoffset1
,uni_requestedpath
,requestedpathlen
);
1078 memcpy(pdata
+uni_reqpathoffset2
,uni_requestedpath
,requestedpathlen
);
1080 /* create the header */
1081 SSVAL(pdata
,0,requestedpathlen
- 2); /* UCS2 of path consumed minus
1083 /* number of referral in this pkt */
1084 SSVAL(pdata
,2,junction
->referral_count
);
1086 SIVAL(pdata
,4,DFSREF_REFERRAL_SERVER
| DFSREF_STORAGE_SERVER
);
1088 SIVAL(pdata
,4,DFSREF_STORAGE_SERVER
);
1092 /* add the referral elements */
1093 for(i
=0;i
<junction
->referral_count
;i
++) {
1094 struct referral
* ref
= &junction
->referral_list
[i
];
1097 SSVAL(pdata
,offset
,2); /* version 2 */
1098 SSVAL(pdata
,offset
+2,VERSION2_REFERRAL_SIZE
);
1100 SSVAL(pdata
,offset
+4,1);
1102 SSVAL(pdata
,offset
+4,0);
1105 /* ref_flags :use path_consumed bytes? */
1106 SSVAL(pdata
,offset
+6,0);
1107 SIVAL(pdata
,offset
+8,ref
->proximity
);
1108 SIVAL(pdata
,offset
+12,ref
->ttl
);
1110 SSVAL(pdata
,offset
+16,uni_reqpathoffset1
-offset
);
1111 SSVAL(pdata
,offset
+18,uni_reqpathoffset2
-offset
);
1112 /* copy referred path into current offset */
1113 unilen
= rpcstr_push(pdata
+uni_curroffset
,
1114 ref
->alternate_path
,
1115 reply_size
- uni_curroffset
,
1118 SSVAL(pdata
,offset
+20,uni_curroffset
-offset
);
1120 uni_curroffset
+= unilen
;
1121 offset
+= VERSION2_REFERRAL_SIZE
;
1123 /* add in the unexplained 22 (0x16) bytes at the end */
1124 memset(pdata
+uni_curroffset
,'\0',0x16);
1128 static int setup_ver3_dfs_referral(const char *pathname
,
1130 struct junction_map
*junction
,
1133 char *pdata
= *ppdata
;
1135 smb_ucs2_t
*uni_reqpath
= NULL
;
1136 int uni_reqpathoffset1
, uni_reqpathoffset2
;
1143 DEBUG(10,("setting up version3 referral\n"));
1145 reqpathlen
= rpcstr_push_talloc(talloc_tos(), &uni_reqpath
, pathname
);
1146 if (uni_reqpath
== NULL
|| reqpathlen
== 0) {
1151 dump_data(0, (unsigned char *)uni_reqpath
,
1155 uni_reqpathoffset1
= REFERRAL_HEADER_SIZE
+
1156 VERSION3_REFERRAL_SIZE
* junction
->referral_count
;
1157 uni_reqpathoffset2
= uni_reqpathoffset1
+ reqpathlen
;
1158 reply_size
= uni_curroffset
= uni_reqpathoffset2
+ reqpathlen
;
1160 for(i
=0;i
<junction
->referral_count
;i
++) {
1161 DEBUG(10,("referral %u : %s\n",
1163 junction
->referral_list
[i
].alternate_path
));
1165 (strlen(junction
->referral_list
[i
].alternate_path
)+1)*2;
1168 pdata
= (char *)SMB_REALLOC(pdata
,reply_size
);
1170 DEBUG(0,("version3 referral setup:"
1171 "malloc failed for Realloc!\n"));
1176 /* create the header */
1177 SSVAL(pdata
,0,reqpathlen
- 2); /* UCS2 of path consumed minus
1179 SSVAL(pdata
,2,junction
->referral_count
); /* number of referral */
1181 SIVAL(pdata
,4,DFSREF_REFERRAL_SERVER
| DFSREF_STORAGE_SERVER
);
1183 SIVAL(pdata
,4,DFSREF_STORAGE_SERVER
);
1186 /* copy in the reqpaths */
1187 memcpy(pdata
+uni_reqpathoffset1
,uni_reqpath
,reqpathlen
);
1188 memcpy(pdata
+uni_reqpathoffset2
,uni_reqpath
,reqpathlen
);
1191 for(i
=0;i
<junction
->referral_count
;i
++) {
1192 struct referral
* ref
= &(junction
->referral_list
[i
]);
1195 SSVAL(pdata
,offset
,3); /* version 3 */
1196 SSVAL(pdata
,offset
+2,VERSION3_REFERRAL_SIZE
);
1198 SSVAL(pdata
,offset
+4,1);
1200 SSVAL(pdata
,offset
+4,0);
1203 /* ref_flags :use path_consumed bytes? */
1204 SSVAL(pdata
,offset
+6,0);
1205 SIVAL(pdata
,offset
+8,ref
->ttl
);
1207 SSVAL(pdata
,offset
+12,uni_reqpathoffset1
-offset
);
1208 SSVAL(pdata
,offset
+14,uni_reqpathoffset2
-offset
);
1209 /* copy referred path into current offset */
1210 unilen
= rpcstr_push(pdata
+uni_curroffset
,ref
->alternate_path
,
1211 reply_size
- uni_curroffset
,
1212 STR_UNICODE
| STR_TERMINATE
);
1213 SSVAL(pdata
,offset
+16,uni_curroffset
-offset
);
1214 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
1215 memset(pdata
+offset
+18,'\0',16);
1217 uni_curroffset
+= unilen
;
1218 offset
+= VERSION3_REFERRAL_SIZE
;
1223 /******************************************************************
1224 Set up the DFS referral for the dfs pathname. This call returns
1225 the amount of the path covered by this server, and where the
1226 client should be redirected to. This is the meat of the
1227 TRANS2_GET_DFS_REFERRAL call.
1228 ******************************************************************/
1230 int setup_dfs_referral(connection_struct
*orig_conn
,
1231 const char *dfs_path
,
1232 int max_referral_level
,
1233 char **ppdata
, NTSTATUS
*pstatus
)
1235 struct junction_map
*junction
= NULL
;
1236 int consumedcnt
= 0;
1237 bool self_referral
= False
;
1239 char *pathnamep
= NULL
;
1240 char *local_dfs_path
= NULL
;
1243 if (!(ctx
=talloc_init("setup_dfs_referral"))) {
1244 *pstatus
= NT_STATUS_NO_MEMORY
;
1248 /* get the junction entry */
1250 talloc_destroy(ctx
);
1251 *pstatus
= NT_STATUS_NOT_FOUND
;
1256 * Trim pathname sent by client so it begins with only one backslash.
1257 * Two backslashes confuse some dfs clients
1260 local_dfs_path
= talloc_strdup(ctx
,dfs_path
);
1261 if (!local_dfs_path
) {
1262 *pstatus
= NT_STATUS_NO_MEMORY
;
1263 talloc_destroy(ctx
);
1266 pathnamep
= local_dfs_path
;
1267 while (IS_DIRECTORY_SEP(pathnamep
[0]) &&
1268 IS_DIRECTORY_SEP(pathnamep
[1])) {
1272 junction
= talloc_zero(ctx
, struct junction_map
);
1274 *pstatus
= NT_STATUS_NO_MEMORY
;
1275 talloc_destroy(ctx
);
1279 /* The following call can change cwd. */
1280 *pstatus
= get_referred_path(ctx
, pathnamep
, orig_conn
->sconn
,
1281 junction
, &consumedcnt
, &self_referral
);
1282 if (!NT_STATUS_IS_OK(*pstatus
)) {
1283 vfs_ChDir(orig_conn
,orig_conn
->connectpath
);
1284 talloc_destroy(ctx
);
1287 vfs_ChDir(orig_conn
,orig_conn
->connectpath
);
1289 if (!self_referral
) {
1290 pathnamep
[consumedcnt
] = '\0';
1292 if( DEBUGLVL( 3 ) ) {
1294 dbgtext("setup_dfs_referral: Path %s to "
1295 "alternate path(s):",
1297 for(i
=0;i
<junction
->referral_count
;i
++)
1299 junction
->referral_list
[i
].alternate_path
);
1304 /* create the referral depeding on version */
1305 DEBUG(10,("max_referral_level :%d\n",max_referral_level
));
1307 if (max_referral_level
< 2) {
1308 max_referral_level
= 2;
1310 if (max_referral_level
> 3) {
1311 max_referral_level
= 3;
1314 switch(max_referral_level
) {
1316 reply_size
= setup_ver2_dfs_referral(pathnamep
,
1321 reply_size
= setup_ver3_dfs_referral(pathnamep
, ppdata
,
1322 junction
, self_referral
);
1325 DEBUG(0,("setup_dfs_referral: Invalid dfs referral "
1327 max_referral_level
));
1328 talloc_destroy(ctx
);
1329 *pstatus
= NT_STATUS_INVALID_LEVEL
;
1334 DEBUGADD(0,("DFS Referral pdata:\n"));
1335 dump_data(0,(uint8
*)*ppdata
,reply_size
);
1338 talloc_destroy(ctx
);
1339 *pstatus
= NT_STATUS_OK
;
1343 /**********************************************************************
1344 The following functions are called by the NETDFS RPC pipe functions
1345 **********************************************************************/
1347 /*********************************************************************
1348 Creates a junction structure from a DFS pathname
1349 **********************************************************************/
1351 bool create_junction(TALLOC_CTX
*ctx
,
1352 const char *dfs_path
,
1353 struct junction_map
*jucn
)
1357 struct dfs_path
*pdp
= talloc(ctx
,struct dfs_path
);
1363 status
= parse_dfs_path(NULL
, dfs_path
, False
,
1364 !smbd_server_conn
->using_smb2
, pdp
, &dummy
);
1365 if (!NT_STATUS_IS_OK(status
)) {
1369 /* check if path is dfs : validate first token */
1370 if (!is_myname_or_ipaddr(pdp
->hostname
)) {
1371 DEBUG(4,("create_junction: Invalid hostname %s "
1373 pdp
->hostname
, dfs_path
));
1378 /* Check for a non-DFS share */
1379 snum
= lp_servicenumber(pdp
->servicename
);
1381 if(snum
< 0 || !lp_msdfs_root(snum
)) {
1382 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1388 jucn
->service_name
= talloc_strdup(ctx
, pdp
->servicename
);
1389 jucn
->volume_name
= talloc_strdup(ctx
, pdp
->reqpath
);
1390 jucn
->comment
= talloc_strdup(ctx
, lp_comment(snum
));
1393 if (!jucn
->service_name
|| !jucn
->volume_name
|| ! jucn
->comment
) {
1399 /**********************************************************************
1400 Forms a valid Unix pathname from the junction
1401 **********************************************************************/
1403 static bool junction_to_local_path(const struct junction_map
*jucn
,
1405 connection_struct
**conn_out
,
1411 snum
= lp_servicenumber(jucn
->service_name
);
1415 status
= create_conn_struct(talloc_tos(), smbd_server_conn
, conn_out
,
1416 snum
, lp_pathname(snum
), NULL
, oldpath
);
1417 if (!NT_STATUS_IS_OK(status
)) {
1421 *pp_path_out
= talloc_asprintf(*conn_out
,
1425 if (!*pp_path_out
) {
1426 vfs_ChDir(*conn_out
, *oldpath
);
1427 SMB_VFS_DISCONNECT(*conn_out
);
1428 conn_free(*conn_out
);
1434 bool create_msdfs_link(const struct junction_map
*jucn
)
1438 char *msdfs_link
= NULL
;
1439 connection_struct
*conn
;
1441 bool insert_comma
= False
;
1444 if(!junction_to_local_path(jucn
, &path
, &conn
, &cwd
)) {
1448 /* Form the msdfs_link contents */
1449 msdfs_link
= talloc_strdup(conn
, "msdfs:");
1453 for(i
=0; i
<jucn
->referral_count
; i
++) {
1454 char *refpath
= jucn
->referral_list
[i
].alternate_path
;
1456 /* Alternate paths always use Windows separators. */
1457 trim_char(refpath
, '\\', '\\');
1458 if(*refpath
== '\0') {
1460 insert_comma
= False
;
1464 if (i
> 0 && insert_comma
) {
1465 msdfs_link
= talloc_asprintf_append_buffer(msdfs_link
,
1469 msdfs_link
= talloc_asprintf_append_buffer(msdfs_link
,
1477 if (!insert_comma
) {
1478 insert_comma
= True
;
1482 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1485 if(SMB_VFS_SYMLINK(conn
, msdfs_link
, path
) < 0) {
1486 if (errno
== EEXIST
) {
1487 struct smb_filename
*smb_fname
= NULL
;
1490 status
= create_synthetic_smb_fname(talloc_tos(), path
,
1493 if (!NT_STATUS_IS_OK(status
)) {
1494 errno
= map_errno_from_nt_status(status
);
1498 if(SMB_VFS_UNLINK(conn
, smb_fname
)!=0) {
1499 TALLOC_FREE(smb_fname
);
1502 TALLOC_FREE(smb_fname
);
1504 if (SMB_VFS_SYMLINK(conn
, msdfs_link
, path
) < 0) {
1505 DEBUG(1,("create_msdfs_link: symlink failed "
1506 "%s -> %s\nError: %s\n",
1507 path
, msdfs_link
, strerror(errno
)));
1515 vfs_ChDir(conn
, cwd
);
1516 SMB_VFS_DISCONNECT(conn
);
1521 bool remove_msdfs_link(const struct junction_map
*jucn
)
1525 connection_struct
*conn
;
1527 struct smb_filename
*smb_fname
= NULL
;
1530 if (!junction_to_local_path(jucn
, &path
, &conn
, &cwd
)) {
1534 status
= create_synthetic_smb_fname(talloc_tos(), path
,
1537 if (!NT_STATUS_IS_OK(status
)) {
1538 errno
= map_errno_from_nt_status(status
);
1542 if( SMB_VFS_UNLINK(conn
, smb_fname
) == 0 ) {
1546 TALLOC_FREE(smb_fname
);
1547 vfs_ChDir(conn
, cwd
);
1548 SMB_VFS_DISCONNECT(conn
);
1553 /*********************************************************************
1554 Return the number of DFS links at the root of this share.
1555 *********************************************************************/
1557 static int count_dfs_links(TALLOC_CTX
*ctx
, int snum
)
1560 SMB_STRUCT_DIR
*dirp
= NULL
;
1561 const char *dname
= NULL
;
1562 char *talloced
= NULL
;
1563 const char *connect_path
= lp_pathname(snum
);
1564 const char *msdfs_proxy
= lp_msdfs_proxy(snum
);
1565 connection_struct
*conn
;
1569 if(*connect_path
== '\0') {
1574 * Fake up a connection struct for the VFS layer.
1577 status
= create_conn_struct(talloc_tos(), smbd_server_conn
, &conn
,
1578 snum
, connect_path
, NULL
, &cwd
);
1579 if (!NT_STATUS_IS_OK(status
)) {
1580 DEBUG(3, ("create_conn_struct failed: %s\n",
1581 nt_errstr(status
)));
1585 /* Count a link for the msdfs root - convention */
1588 /* No more links if this is an msdfs proxy. */
1589 if (*msdfs_proxy
!= '\0') {
1593 /* Now enumerate all dfs links */
1594 dirp
= SMB_VFS_OPENDIR(conn
, ".", NULL
, 0);
1599 while ((dname
= vfs_readdirname(conn
, dirp
, NULL
, &talloced
))
1601 if (is_msdfs_link(conn
,
1606 TALLOC_FREE(talloced
);
1609 SMB_VFS_CLOSEDIR(conn
,dirp
);
1612 vfs_ChDir(conn
, cwd
);
1613 SMB_VFS_DISCONNECT(conn
);
1618 /*********************************************************************
1619 *********************************************************************/
1621 static int form_junctions(TALLOC_CTX
*ctx
,
1623 struct junction_map
*jucn
,
1627 SMB_STRUCT_DIR
*dirp
= NULL
;
1628 const char *dname
= NULL
;
1629 char *talloced
= NULL
;
1630 const char *connect_path
= lp_pathname(snum
);
1631 char *service_name
= lp_servicename(snum
);
1632 const char *msdfs_proxy
= lp_msdfs_proxy(snum
);
1633 connection_struct
*conn
;
1634 struct referral
*ref
= NULL
;
1638 if (jn_remain
== 0) {
1642 if(*connect_path
== '\0') {
1647 * Fake up a connection struct for the VFS layer.
1650 status
= create_conn_struct(ctx
, smbd_server_conn
, &conn
, snum
, connect_path
, NULL
,
1652 if (!NT_STATUS_IS_OK(status
)) {
1653 DEBUG(3, ("create_conn_struct failed: %s\n",
1654 nt_errstr(status
)));
1658 /* form a junction for the msdfs root - convention
1659 DO NOT REMOVE THIS: NT clients will not work with us
1660 if this is not present
1662 jucn
[cnt
].service_name
= talloc_strdup(ctx
,service_name
);
1663 jucn
[cnt
].volume_name
= talloc_strdup(ctx
, "");
1664 if (!jucn
[cnt
].service_name
|| !jucn
[cnt
].volume_name
) {
1667 jucn
[cnt
].comment
= "";
1668 jucn
[cnt
].referral_count
= 1;
1670 ref
= jucn
[cnt
].referral_list
= talloc_zero(ctx
, struct referral
);
1671 if (jucn
[cnt
].referral_list
== NULL
) {
1676 ref
->ttl
= REFERRAL_TTL
;
1677 if (*msdfs_proxy
!= '\0') {
1678 ref
->alternate_path
= talloc_strdup(ctx
,
1681 ref
->alternate_path
= talloc_asprintf(ctx
,
1683 get_local_machine_name(),
1687 if (!ref
->alternate_path
) {
1692 /* Don't enumerate if we're an msdfs proxy. */
1693 if (*msdfs_proxy
!= '\0') {
1697 /* Now enumerate all dfs links */
1698 dirp
= SMB_VFS_OPENDIR(conn
, ".", NULL
, 0);
1703 while ((dname
= vfs_readdirname(conn
, dirp
, NULL
, &talloced
))
1705 char *link_target
= NULL
;
1706 if (cnt
>= jn_remain
) {
1707 DEBUG(2, ("form_junctions: ran out of MSDFS "
1709 TALLOC_FREE(talloced
);
1712 if (is_msdfs_link_internal(ctx
,
1714 dname
, &link_target
,
1716 if (parse_msdfs_symlink(ctx
,
1718 &jucn
[cnt
].referral_list
,
1719 &jucn
[cnt
].referral_count
)) {
1721 jucn
[cnt
].service_name
= talloc_strdup(ctx
,
1723 jucn
[cnt
].volume_name
= talloc_strdup(ctx
,
1725 if (!jucn
[cnt
].service_name
||
1726 !jucn
[cnt
].volume_name
) {
1727 TALLOC_FREE(talloced
);
1730 jucn
[cnt
].comment
= "";
1733 TALLOC_FREE(link_target
);
1735 TALLOC_FREE(talloced
);
1741 SMB_VFS_CLOSEDIR(conn
,dirp
);
1744 vfs_ChDir(conn
, cwd
);
1749 struct junction_map
*enum_msdfs_links(struct smbd_server_connection
*sconn
,
1750 TALLOC_CTX
*ctx
, size_t *p_num_jn
)
1752 struct junction_map
*jn
= NULL
;
1754 size_t jn_count
= 0;
1758 if(!lp_host_msdfs()) {
1762 /* Ensure all the usershares are loaded. */
1764 load_registry_shares();
1765 sharecount
= load_usershare_shares(sconn
);
1768 for(i
=0;i
< sharecount
;i
++) {
1769 if(lp_msdfs_root(i
)) {
1770 jn_count
+= count_dfs_links(ctx
, i
);
1773 if (jn_count
== 0) {
1776 jn
= talloc_array(ctx
, struct junction_map
, jn_count
);
1780 for(i
=0; i
< sharecount
; i
++) {
1781 if (*p_num_jn
>= jn_count
) {
1784 if(lp_msdfs_root(i
)) {
1785 *p_num_jn
+= form_junctions(ctx
, i
,
1787 jn_count
- *p_num_jn
);
1793 /******************************************************************************
1794 Core function to resolve a dfs pathname possibly containing a wildcard. If
1795 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1796 detected during dfs resolution.
1797 ******************************************************************************/
1799 NTSTATUS
resolve_dfspath_wcard(TALLOC_CTX
*ctx
,
1800 connection_struct
*conn
,
1802 const char *name_in
,
1805 bool *ppath_contains_wcard
)
1807 bool path_contains_wcard
;
1808 NTSTATUS status
= NT_STATUS_OK
;
1810 if (dfs_pathnames
) {
1811 status
= dfs_redirect(ctx
,
1815 !smbd_server_conn
->using_smb2
,
1817 &path_contains_wcard
);
1819 if (NT_STATUS_IS_OK(status
) && ppath_contains_wcard
!= NULL
) {
1820 *ppath_contains_wcard
= path_contains_wcard
;
1824 * Cheat and just return a copy of the in ptr.
1825 * Once srvstr_get_path() uses talloc it'll
1826 * be a talloced ptr anyway.
1828 *pp_name_out
= discard_const_p(char, name_in
);