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 bool allow_broken_path
,
1354 struct junction_map
*jucn
)
1358 struct dfs_path
*pdp
= talloc(ctx
,struct dfs_path
);
1364 status
= parse_dfs_path(NULL
, dfs_path
, False
, allow_broken_path
,
1366 if (!NT_STATUS_IS_OK(status
)) {
1370 /* check if path is dfs : validate first token */
1371 if (!is_myname_or_ipaddr(pdp
->hostname
)) {
1372 DEBUG(4,("create_junction: Invalid hostname %s "
1374 pdp
->hostname
, dfs_path
));
1379 /* Check for a non-DFS share */
1380 snum
= lp_servicenumber(pdp
->servicename
);
1382 if(snum
< 0 || !lp_msdfs_root(snum
)) {
1383 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1389 jucn
->service_name
= talloc_strdup(ctx
, pdp
->servicename
);
1390 jucn
->volume_name
= talloc_strdup(ctx
, pdp
->reqpath
);
1391 jucn
->comment
= talloc_strdup(ctx
, lp_comment(snum
));
1394 if (!jucn
->service_name
|| !jucn
->volume_name
|| ! jucn
->comment
) {
1400 /**********************************************************************
1401 Forms a valid Unix pathname from the junction
1402 **********************************************************************/
1404 static bool junction_to_local_path(const struct junction_map
*jucn
,
1406 connection_struct
**conn_out
,
1412 snum
= lp_servicenumber(jucn
->service_name
);
1416 status
= create_conn_struct(talloc_tos(), smbd_server_conn
, conn_out
,
1417 snum
, lp_pathname(snum
), NULL
, oldpath
);
1418 if (!NT_STATUS_IS_OK(status
)) {
1422 *pp_path_out
= talloc_asprintf(*conn_out
,
1426 if (!*pp_path_out
) {
1427 vfs_ChDir(*conn_out
, *oldpath
);
1428 SMB_VFS_DISCONNECT(*conn_out
);
1429 conn_free(*conn_out
);
1435 bool create_msdfs_link(const struct junction_map
*jucn
)
1439 char *msdfs_link
= NULL
;
1440 connection_struct
*conn
;
1442 bool insert_comma
= False
;
1445 if(!junction_to_local_path(jucn
, &path
, &conn
, &cwd
)) {
1449 /* Form the msdfs_link contents */
1450 msdfs_link
= talloc_strdup(conn
, "msdfs:");
1454 for(i
=0; i
<jucn
->referral_count
; i
++) {
1455 char *refpath
= jucn
->referral_list
[i
].alternate_path
;
1457 /* Alternate paths always use Windows separators. */
1458 trim_char(refpath
, '\\', '\\');
1459 if(*refpath
== '\0') {
1461 insert_comma
= False
;
1465 if (i
> 0 && insert_comma
) {
1466 msdfs_link
= talloc_asprintf_append_buffer(msdfs_link
,
1470 msdfs_link
= talloc_asprintf_append_buffer(msdfs_link
,
1478 if (!insert_comma
) {
1479 insert_comma
= True
;
1483 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1486 if(SMB_VFS_SYMLINK(conn
, msdfs_link
, path
) < 0) {
1487 if (errno
== EEXIST
) {
1488 struct smb_filename
*smb_fname
= NULL
;
1491 status
= create_synthetic_smb_fname(talloc_tos(), path
,
1494 if (!NT_STATUS_IS_OK(status
)) {
1495 errno
= map_errno_from_nt_status(status
);
1499 if(SMB_VFS_UNLINK(conn
, smb_fname
)!=0) {
1500 TALLOC_FREE(smb_fname
);
1503 TALLOC_FREE(smb_fname
);
1505 if (SMB_VFS_SYMLINK(conn
, msdfs_link
, path
) < 0) {
1506 DEBUG(1,("create_msdfs_link: symlink failed "
1507 "%s -> %s\nError: %s\n",
1508 path
, msdfs_link
, strerror(errno
)));
1516 vfs_ChDir(conn
, cwd
);
1517 SMB_VFS_DISCONNECT(conn
);
1522 bool remove_msdfs_link(const struct junction_map
*jucn
)
1526 connection_struct
*conn
;
1528 struct smb_filename
*smb_fname
= NULL
;
1531 if (!junction_to_local_path(jucn
, &path
, &conn
, &cwd
)) {
1535 status
= create_synthetic_smb_fname(talloc_tos(), path
,
1538 if (!NT_STATUS_IS_OK(status
)) {
1539 errno
= map_errno_from_nt_status(status
);
1543 if( SMB_VFS_UNLINK(conn
, smb_fname
) == 0 ) {
1547 TALLOC_FREE(smb_fname
);
1548 vfs_ChDir(conn
, cwd
);
1549 SMB_VFS_DISCONNECT(conn
);
1554 /*********************************************************************
1555 Return the number of DFS links at the root of this share.
1556 *********************************************************************/
1558 static int count_dfs_links(TALLOC_CTX
*ctx
, int snum
)
1561 SMB_STRUCT_DIR
*dirp
= NULL
;
1562 const char *dname
= NULL
;
1563 char *talloced
= NULL
;
1564 const char *connect_path
= lp_pathname(snum
);
1565 const char *msdfs_proxy
= lp_msdfs_proxy(snum
);
1566 connection_struct
*conn
;
1570 if(*connect_path
== '\0') {
1575 * Fake up a connection struct for the VFS layer.
1578 status
= create_conn_struct(talloc_tos(), smbd_server_conn
, &conn
,
1579 snum
, connect_path
, NULL
, &cwd
);
1580 if (!NT_STATUS_IS_OK(status
)) {
1581 DEBUG(3, ("create_conn_struct failed: %s\n",
1582 nt_errstr(status
)));
1586 /* Count a link for the msdfs root - convention */
1589 /* No more links if this is an msdfs proxy. */
1590 if (*msdfs_proxy
!= '\0') {
1594 /* Now enumerate all dfs links */
1595 dirp
= SMB_VFS_OPENDIR(conn
, ".", NULL
, 0);
1600 while ((dname
= vfs_readdirname(conn
, dirp
, NULL
, &talloced
))
1602 if (is_msdfs_link(conn
,
1607 TALLOC_FREE(talloced
);
1610 SMB_VFS_CLOSEDIR(conn
,dirp
);
1613 vfs_ChDir(conn
, cwd
);
1614 SMB_VFS_DISCONNECT(conn
);
1619 /*********************************************************************
1620 *********************************************************************/
1622 static int form_junctions(TALLOC_CTX
*ctx
,
1624 struct junction_map
*jucn
,
1628 SMB_STRUCT_DIR
*dirp
= NULL
;
1629 const char *dname
= NULL
;
1630 char *talloced
= NULL
;
1631 const char *connect_path
= lp_pathname(snum
);
1632 char *service_name
= lp_servicename(snum
);
1633 const char *msdfs_proxy
= lp_msdfs_proxy(snum
);
1634 connection_struct
*conn
;
1635 struct referral
*ref
= NULL
;
1639 if (jn_remain
== 0) {
1643 if(*connect_path
== '\0') {
1648 * Fake up a connection struct for the VFS layer.
1651 status
= create_conn_struct(ctx
, smbd_server_conn
, &conn
, snum
, connect_path
, NULL
,
1653 if (!NT_STATUS_IS_OK(status
)) {
1654 DEBUG(3, ("create_conn_struct failed: %s\n",
1655 nt_errstr(status
)));
1659 /* form a junction for the msdfs root - convention
1660 DO NOT REMOVE THIS: NT clients will not work with us
1661 if this is not present
1663 jucn
[cnt
].service_name
= talloc_strdup(ctx
,service_name
);
1664 jucn
[cnt
].volume_name
= talloc_strdup(ctx
, "");
1665 if (!jucn
[cnt
].service_name
|| !jucn
[cnt
].volume_name
) {
1668 jucn
[cnt
].comment
= "";
1669 jucn
[cnt
].referral_count
= 1;
1671 ref
= jucn
[cnt
].referral_list
= talloc_zero(ctx
, struct referral
);
1672 if (jucn
[cnt
].referral_list
== NULL
) {
1677 ref
->ttl
= REFERRAL_TTL
;
1678 if (*msdfs_proxy
!= '\0') {
1679 ref
->alternate_path
= talloc_strdup(ctx
,
1682 ref
->alternate_path
= talloc_asprintf(ctx
,
1684 get_local_machine_name(),
1688 if (!ref
->alternate_path
) {
1693 /* Don't enumerate if we're an msdfs proxy. */
1694 if (*msdfs_proxy
!= '\0') {
1698 /* Now enumerate all dfs links */
1699 dirp
= SMB_VFS_OPENDIR(conn
, ".", NULL
, 0);
1704 while ((dname
= vfs_readdirname(conn
, dirp
, NULL
, &talloced
))
1706 char *link_target
= NULL
;
1707 if (cnt
>= jn_remain
) {
1708 DEBUG(2, ("form_junctions: ran out of MSDFS "
1710 TALLOC_FREE(talloced
);
1713 if (is_msdfs_link_internal(ctx
,
1715 dname
, &link_target
,
1717 if (parse_msdfs_symlink(ctx
,
1719 &jucn
[cnt
].referral_list
,
1720 &jucn
[cnt
].referral_count
)) {
1722 jucn
[cnt
].service_name
= talloc_strdup(ctx
,
1724 jucn
[cnt
].volume_name
= talloc_strdup(ctx
,
1726 if (!jucn
[cnt
].service_name
||
1727 !jucn
[cnt
].volume_name
) {
1728 TALLOC_FREE(talloced
);
1731 jucn
[cnt
].comment
= "";
1734 TALLOC_FREE(link_target
);
1736 TALLOC_FREE(talloced
);
1742 SMB_VFS_CLOSEDIR(conn
,dirp
);
1745 vfs_ChDir(conn
, cwd
);
1750 struct junction_map
*enum_msdfs_links(struct smbd_server_connection
*sconn
,
1751 TALLOC_CTX
*ctx
, size_t *p_num_jn
)
1753 struct junction_map
*jn
= NULL
;
1755 size_t jn_count
= 0;
1759 if(!lp_host_msdfs()) {
1763 /* Ensure all the usershares are loaded. */
1765 load_registry_shares();
1766 sharecount
= load_usershare_shares(sconn
);
1769 for(i
=0;i
< sharecount
;i
++) {
1770 if(lp_msdfs_root(i
)) {
1771 jn_count
+= count_dfs_links(ctx
, i
);
1774 if (jn_count
== 0) {
1777 jn
= talloc_array(ctx
, struct junction_map
, jn_count
);
1781 for(i
=0; i
< sharecount
; i
++) {
1782 if (*p_num_jn
>= jn_count
) {
1785 if(lp_msdfs_root(i
)) {
1786 *p_num_jn
+= form_junctions(ctx
, i
,
1788 jn_count
- *p_num_jn
);
1794 /******************************************************************************
1795 Core function to resolve a dfs pathname possibly containing a wildcard. If
1796 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1797 detected during dfs resolution.
1798 ******************************************************************************/
1800 NTSTATUS
resolve_dfspath_wcard(TALLOC_CTX
*ctx
,
1801 connection_struct
*conn
,
1803 const char *name_in
,
1806 bool *ppath_contains_wcard
)
1808 bool path_contains_wcard
;
1809 NTSTATUS status
= NT_STATUS_OK
;
1811 if (dfs_pathnames
) {
1812 status
= dfs_redirect(ctx
,
1816 !smbd_server_conn
->using_smb2
,
1818 &path_contains_wcard
);
1820 if (NT_STATUS_IS_OK(status
) && ppath_contains_wcard
!= NULL
) {
1821 *ppath_contains_wcard
= path_contains_wcard
;
1825 * Cheat and just return a copy of the in ptr.
1826 * Once srvstr_get_path() uses talloc it'll
1827 * be a talloced ptr anyway.
1829 *pp_name_out
= discard_const_p(char, name_in
);