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
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.
586 status
= unix_convert(ctx
, conn
, pdp
->reqpath
, &smb_fname
,
587 search_flag
? UCF_ALWAYS_ALLOW_WCARD_LCOMP
: 0);
589 if (!NT_STATUS_IS_OK(status
)) {
590 if (!NT_STATUS_EQUAL(status
,
591 NT_STATUS_OBJECT_PATH_NOT_FOUND
)) {
594 if (smb_fname
== NULL
|| smb_fname
->base_name
== NULL
) {
599 /* Optimization - check if we can redirect the whole path. */
601 if (is_msdfs_link_internal(ctx
, conn
, smb_fname
->base_name
,
602 pp_targetpath
, NULL
)) {
604 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
605 "for dfs link %s.\n", dfspath
));
606 status
= NT_STATUS_OK
;
610 DEBUG(6,("dfs_path_lookup: %s resolves to a "
611 "valid dfs link %s.\n", dfspath
,
612 pp_targetpath
? *pp_targetpath
: ""));
615 *consumedcntp
= strlen(dfspath
);
617 status
= NT_STATUS_PATH_NOT_COVERED
;
621 /* Prepare to test only for '/' components in the given path,
622 * so if a Windows path replace all '\\' characters with '/'.
623 * For a POSIX DFS path we know all separators are already '/'. */
625 canon_dfspath
= talloc_strdup(ctx
, dfspath
);
626 if (!canon_dfspath
) {
627 status
= NT_STATUS_NO_MEMORY
;
630 if (!pdp
->posix_path
) {
631 string_replace(canon_dfspath
, '\\', '/');
635 * localpath comes out of unix_convert, so it has
636 * no trailing backslash. Make sure that canon_dfspath hasn't either.
637 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
640 trim_char(canon_dfspath
,0,'/');
643 * Redirect if any component in the path is a link.
644 * We do this by walking backwards through the
645 * local path, chopping off the last component
646 * in both the local path and the canonicalized
647 * DFS path. If we hit a DFS link then we're done.
650 p
= strrchr_m(smb_fname
->base_name
, '/');
652 q
= strrchr_m(canon_dfspath
, '/');
661 if (is_msdfs_link_internal(ctx
, conn
,
662 smb_fname
->base_name
, pp_targetpath
,
664 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
665 "parent %s is dfs link\n", dfspath
,
666 smb_fname_str_dbg(smb_fname
)));
669 *consumedcntp
= strlen(canon_dfspath
);
670 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
676 status
= NT_STATUS_PATH_NOT_COVERED
;
680 /* Step back on the filesystem. */
681 p
= strrchr_m(smb_fname
->base_name
, '/');
684 /* And in the canonicalized dfs path. */
685 q
= strrchr_m(canon_dfspath
, '/');
689 status
= NT_STATUS_OK
;
691 TALLOC_FREE(smb_fname
);
695 /*****************************************************************
696 Decides if a dfs pathname should be redirected or not.
697 If not, the pathname is converted to a tcon-relative local unix path
699 search_wcard_flag: this flag performs 2 functions both related
700 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
703 This function can return NT_STATUS_OK, meaning use the returned path as-is
704 (mapped into a local path).
705 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
706 any other NT_STATUS error which is a genuine error to be
707 returned to the client.
708 *****************************************************************/
710 static NTSTATUS
dfs_redirect(TALLOC_CTX
*ctx
,
711 connection_struct
*conn
,
713 bool search_wcard_flag
,
714 bool allow_broken_path
,
716 bool *ppath_contains_wcard
)
719 struct dfs_path
*pdp
= talloc(ctx
, struct dfs_path
);
722 return NT_STATUS_NO_MEMORY
;
725 status
= parse_dfs_path(conn
, path_in
, search_wcard_flag
,
726 allow_broken_path
, pdp
,
727 ppath_contains_wcard
);
728 if (!NT_STATUS_IS_OK(status
)) {
733 if (pdp
->reqpath
[0] == '\0') {
735 *pp_path_out
= talloc_strdup(ctx
, "");
737 return NT_STATUS_NO_MEMORY
;
739 DEBUG(5,("dfs_redirect: self-referral.\n"));
743 /* If dfs pathname for a non-dfs share, convert to tcon-relative
744 path and return OK */
746 if (!lp_msdfs_root(SNUM(conn
))) {
747 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
750 return NT_STATUS_NO_MEMORY
;
755 /* If it looked like a local path (zero hostname/servicename)
756 * just treat as a tcon-relative path. */
758 if (pdp
->hostname
[0] == '\0' && pdp
->servicename
[0] == '\0') {
759 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
762 return NT_STATUS_NO_MEMORY
;
767 if (!( strequal(pdp
->servicename
, lp_servicename(SNUM(conn
)))
768 || (strequal(pdp
->servicename
, HOMES_NAME
)
769 && strequal(lp_servicename(SNUM(conn
)),
770 conn
->session_info
->unix_info
->sanitized_username
) )) ) {
772 /* The given sharename doesn't match this connection. */
775 return NT_STATUS_OBJECT_PATH_NOT_FOUND
;
778 status
= dfs_path_lookup(ctx
, conn
, path_in
, pdp
,
779 search_wcard_flag
, NULL
, NULL
);
780 if (!NT_STATUS_IS_OK(status
)) {
781 if (NT_STATUS_EQUAL(status
, NT_STATUS_PATH_NOT_COVERED
)) {
782 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in
));
784 DEBUG(10,("dfs_redirect: dfs_path_lookup "
785 "failed for %s with %s\n",
786 path_in
, nt_errstr(status
) ));
791 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in
));
793 /* Form non-dfs tcon-relative path */
794 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
797 return NT_STATUS_NO_MEMORY
;
800 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
807 /**********************************************************************
808 Return a self referral.
809 **********************************************************************/
811 static NTSTATUS
self_ref(TALLOC_CTX
*ctx
,
812 const char *dfs_path
,
813 struct junction_map
*jucn
,
815 bool *self_referralp
)
817 struct referral
*ref
;
819 *self_referralp
= True
;
821 jucn
->referral_count
= 1;
822 if((ref
= talloc_zero(ctx
, struct referral
)) == NULL
) {
823 return NT_STATUS_NO_MEMORY
;
826 ref
->alternate_path
= talloc_strdup(ctx
, dfs_path
);
827 if (!ref
->alternate_path
) {
828 return NT_STATUS_NO_MEMORY
;
831 ref
->ttl
= REFERRAL_TTL
;
832 jucn
->referral_list
= ref
;
833 *consumedcntp
= strlen(dfs_path
);
837 /**********************************************************************
838 Gets valid referrals for a dfs path and fills up the
839 junction_map structure.
840 **********************************************************************/
842 NTSTATUS
get_referred_path(TALLOC_CTX
*ctx
,
843 const char *dfs_path
,
844 struct smbd_server_connection
*sconn
,
845 struct junction_map
*jucn
,
847 bool *self_referralp
)
849 struct connection_struct
*conn
;
850 char *targetpath
= NULL
;
852 NTSTATUS status
= NT_STATUS_NOT_FOUND
;
854 struct dfs_path
*pdp
= talloc(ctx
, struct dfs_path
);
858 return NT_STATUS_NO_MEMORY
;
861 *self_referralp
= False
;
863 status
= parse_dfs_path(NULL
, dfs_path
, False
, !sconn
->using_smb2
,
865 if (!NT_STATUS_IS_OK(status
)) {
869 jucn
->service_name
= talloc_strdup(ctx
, pdp
->servicename
);
870 jucn
->volume_name
= talloc_strdup(ctx
, pdp
->reqpath
);
871 if (!jucn
->service_name
|| !jucn
->volume_name
) {
873 return NT_STATUS_NO_MEMORY
;
876 /* Verify the share is a dfs root */
877 snum
= lp_servicenumber(jucn
->service_name
);
879 char *service_name
= NULL
;
880 if ((snum
= find_service(ctx
, jucn
->service_name
, &service_name
)) < 0) {
881 return NT_STATUS_NOT_FOUND
;
884 return NT_STATUS_NO_MEMORY
;
886 TALLOC_FREE(jucn
->service_name
);
887 jucn
->service_name
= talloc_strdup(ctx
, service_name
);
888 if (!jucn
->service_name
) {
890 return NT_STATUS_NO_MEMORY
;
894 if (!lp_msdfs_root(snum
) && (*lp_msdfs_proxy(snum
) == '\0')) {
895 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
897 pdp
->servicename
, dfs_path
));
899 return NT_STATUS_NOT_FOUND
;
903 * Self referrals are tested with a anonymous IPC connection and
904 * a GET_DFS_REFERRAL call to \\server\share. (which means
905 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
906 * into the directory and will fail if it cannot (as the anonymous
907 * user). Cope with this.
910 if (pdp
->reqpath
[0] == '\0') {
912 struct referral
*ref
;
914 if (*lp_msdfs_proxy(snum
) == '\0') {
924 * It's an msdfs proxy share. Redirect to
925 * the configured target share.
928 jucn
->referral_count
= 1;
929 if ((ref
= talloc_zero(ctx
, struct referral
)) == NULL
) {
931 return NT_STATUS_NO_MEMORY
;
934 if (!(tmp
= talloc_strdup(ctx
, lp_msdfs_proxy(snum
)))) {
936 return NT_STATUS_NO_MEMORY
;
939 trim_string(tmp
, "\\", 0);
941 ref
->alternate_path
= talloc_asprintf(ctx
, "\\%s", tmp
);
944 if (!ref
->alternate_path
) {
946 return NT_STATUS_NO_MEMORY
;
949 if (pdp
->reqpath
[0] != '\0') {
950 ref
->alternate_path
= talloc_asprintf_append(
954 if (!ref
->alternate_path
) {
956 return NT_STATUS_NO_MEMORY
;
960 ref
->ttl
= REFERRAL_TTL
;
961 jucn
->referral_list
= ref
;
962 *consumedcntp
= strlen(dfs_path
);
967 status
= create_conn_struct(ctx
, sconn
, &conn
, snum
,
968 lp_pathname(snum
), NULL
, &oldpath
);
969 if (!NT_STATUS_IS_OK(status
)) {
974 /* If this is a DFS path dfs_lookup should return
975 * NT_STATUS_PATH_NOT_COVERED. */
977 status
= dfs_path_lookup(ctx
, conn
, dfs_path
, pdp
,
978 False
, consumedcntp
, &targetpath
);
980 if (!NT_STATUS_EQUAL(status
, NT_STATUS_PATH_NOT_COVERED
)) {
981 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
986 /* We know this is a valid dfs link. Parse the targetpath. */
987 if (!parse_msdfs_symlink(ctx
, targetpath
,
988 &jucn
->referral_list
,
989 &jucn
->referral_count
)) {
990 DEBUG(3,("get_referred_path: failed to parse symlink "
991 "target %s\n", targetpath
));
992 status
= NT_STATUS_NOT_FOUND
;
996 status
= NT_STATUS_OK
;
998 vfs_ChDir(conn
, oldpath
);
999 SMB_VFS_DISCONNECT(conn
);
1005 static int setup_ver2_dfs_referral(const char *pathname
,
1007 struct junction_map
*junction
,
1010 char* pdata
= *ppdata
;
1012 smb_ucs2_t
*uni_requestedpath
= NULL
;
1013 int uni_reqpathoffset1
,uni_reqpathoffset2
;
1015 int requestedpathlen
=0;
1020 DEBUG(10,("Setting up version2 referral\nRequested path:\n"));
1022 requestedpathlen
= rpcstr_push_talloc(talloc_tos(),
1023 &uni_requestedpath
, pathname
);
1024 if (uni_requestedpath
== NULL
|| requestedpathlen
== 0) {
1029 dump_data(0, (unsigned char *)uni_requestedpath
,
1033 DEBUG(10,("ref count = %u\n",junction
->referral_count
));
1035 uni_reqpathoffset1
= REFERRAL_HEADER_SIZE
+
1036 VERSION2_REFERRAL_SIZE
* junction
->referral_count
;
1038 uni_reqpathoffset2
= uni_reqpathoffset1
+ requestedpathlen
;
1040 uni_curroffset
= uni_reqpathoffset2
+ requestedpathlen
;
1042 reply_size
= REFERRAL_HEADER_SIZE
+
1043 VERSION2_REFERRAL_SIZE
*junction
->referral_count
+
1044 2 * requestedpathlen
;
1045 DEBUG(10,("reply_size: %u\n",reply_size
));
1047 /* add up the unicode lengths of all the referral paths */
1048 for(i
=0;i
<junction
->referral_count
;i
++) {
1049 DEBUG(10,("referral %u : %s\n",
1051 junction
->referral_list
[i
].alternate_path
));
1053 (strlen(junction
->referral_list
[i
].alternate_path
)+1)*2;
1056 DEBUG(10,("reply_size = %u\n",reply_size
));
1057 /* add the unexplained 0x16 bytes */
1060 pdata
= (char *)SMB_REALLOC(pdata
,reply_size
);
1062 DEBUG(0,("Realloc failed!\n"));
1067 /* copy in the dfs requested paths.. required for offset calculations */
1068 memcpy(pdata
+uni_reqpathoffset1
,uni_requestedpath
,requestedpathlen
);
1069 memcpy(pdata
+uni_reqpathoffset2
,uni_requestedpath
,requestedpathlen
);
1071 /* create the header */
1072 SSVAL(pdata
,0,requestedpathlen
- 2); /* UCS2 of path consumed minus
1074 /* number of referral in this pkt */
1075 SSVAL(pdata
,2,junction
->referral_count
);
1077 SIVAL(pdata
,4,DFSREF_REFERRAL_SERVER
| DFSREF_STORAGE_SERVER
);
1079 SIVAL(pdata
,4,DFSREF_STORAGE_SERVER
);
1083 /* add the referral elements */
1084 for(i
=0;i
<junction
->referral_count
;i
++) {
1085 struct referral
* ref
= &junction
->referral_list
[i
];
1088 SSVAL(pdata
,offset
,2); /* version 2 */
1089 SSVAL(pdata
,offset
+2,VERSION2_REFERRAL_SIZE
);
1091 SSVAL(pdata
,offset
+4,1);
1093 SSVAL(pdata
,offset
+4,0);
1096 /* ref_flags :use path_consumed bytes? */
1097 SSVAL(pdata
,offset
+6,0);
1098 SIVAL(pdata
,offset
+8,ref
->proximity
);
1099 SIVAL(pdata
,offset
+12,ref
->ttl
);
1101 SSVAL(pdata
,offset
+16,uni_reqpathoffset1
-offset
);
1102 SSVAL(pdata
,offset
+18,uni_reqpathoffset2
-offset
);
1103 /* copy referred path into current offset */
1104 unilen
= rpcstr_push(pdata
+uni_curroffset
,
1105 ref
->alternate_path
,
1106 reply_size
- uni_curroffset
,
1109 SSVAL(pdata
,offset
+20,uni_curroffset
-offset
);
1111 uni_curroffset
+= unilen
;
1112 offset
+= VERSION2_REFERRAL_SIZE
;
1114 /* add in the unexplained 22 (0x16) bytes at the end */
1115 memset(pdata
+uni_curroffset
,'\0',0x16);
1119 static int setup_ver3_dfs_referral(const char *pathname
,
1121 struct junction_map
*junction
,
1124 char *pdata
= *ppdata
;
1126 smb_ucs2_t
*uni_reqpath
= NULL
;
1127 int uni_reqpathoffset1
, uni_reqpathoffset2
;
1134 DEBUG(10,("setting up version3 referral\n"));
1136 reqpathlen
= rpcstr_push_talloc(talloc_tos(), &uni_reqpath
, pathname
);
1137 if (uni_reqpath
== NULL
|| reqpathlen
== 0) {
1142 dump_data(0, (unsigned char *)uni_reqpath
,
1146 uni_reqpathoffset1
= REFERRAL_HEADER_SIZE
+
1147 VERSION3_REFERRAL_SIZE
* junction
->referral_count
;
1148 uni_reqpathoffset2
= uni_reqpathoffset1
+ reqpathlen
;
1149 reply_size
= uni_curroffset
= uni_reqpathoffset2
+ reqpathlen
;
1151 for(i
=0;i
<junction
->referral_count
;i
++) {
1152 DEBUG(10,("referral %u : %s\n",
1154 junction
->referral_list
[i
].alternate_path
));
1156 (strlen(junction
->referral_list
[i
].alternate_path
)+1)*2;
1159 pdata
= (char *)SMB_REALLOC(pdata
,reply_size
);
1161 DEBUG(0,("version3 referral setup:"
1162 "malloc failed for Realloc!\n"));
1167 /* create the header */
1168 SSVAL(pdata
,0,reqpathlen
- 2); /* UCS2 of path consumed minus
1170 SSVAL(pdata
,2,junction
->referral_count
); /* number of referral */
1172 SIVAL(pdata
,4,DFSREF_REFERRAL_SERVER
| DFSREF_STORAGE_SERVER
);
1174 SIVAL(pdata
,4,DFSREF_STORAGE_SERVER
);
1177 /* copy in the reqpaths */
1178 memcpy(pdata
+uni_reqpathoffset1
,uni_reqpath
,reqpathlen
);
1179 memcpy(pdata
+uni_reqpathoffset2
,uni_reqpath
,reqpathlen
);
1182 for(i
=0;i
<junction
->referral_count
;i
++) {
1183 struct referral
* ref
= &(junction
->referral_list
[i
]);
1186 SSVAL(pdata
,offset
,3); /* version 3 */
1187 SSVAL(pdata
,offset
+2,VERSION3_REFERRAL_SIZE
);
1189 SSVAL(pdata
,offset
+4,1);
1191 SSVAL(pdata
,offset
+4,0);
1194 /* ref_flags :use path_consumed bytes? */
1195 SSVAL(pdata
,offset
+6,0);
1196 SIVAL(pdata
,offset
+8,ref
->ttl
);
1198 SSVAL(pdata
,offset
+12,uni_reqpathoffset1
-offset
);
1199 SSVAL(pdata
,offset
+14,uni_reqpathoffset2
-offset
);
1200 /* copy referred path into current offset */
1201 unilen
= rpcstr_push(pdata
+uni_curroffset
,ref
->alternate_path
,
1202 reply_size
- uni_curroffset
,
1203 STR_UNICODE
| STR_TERMINATE
);
1204 SSVAL(pdata
,offset
+16,uni_curroffset
-offset
);
1205 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
1206 memset(pdata
+offset
+18,'\0',16);
1208 uni_curroffset
+= unilen
;
1209 offset
+= VERSION3_REFERRAL_SIZE
;
1214 /******************************************************************
1215 Set up the DFS referral for the dfs pathname. This call returns
1216 the amount of the path covered by this server, and where the
1217 client should be redirected to. This is the meat of the
1218 TRANS2_GET_DFS_REFERRAL call.
1219 ******************************************************************/
1221 int setup_dfs_referral(connection_struct
*orig_conn
,
1222 const char *dfs_path
,
1223 int max_referral_level
,
1224 char **ppdata
, NTSTATUS
*pstatus
)
1226 struct junction_map
*junction
= NULL
;
1227 int consumedcnt
= 0;
1228 bool self_referral
= False
;
1230 char *pathnamep
= NULL
;
1231 char *local_dfs_path
= NULL
;
1234 if (!(ctx
=talloc_init("setup_dfs_referral"))) {
1235 *pstatus
= NT_STATUS_NO_MEMORY
;
1239 /* get the junction entry */
1241 talloc_destroy(ctx
);
1242 *pstatus
= NT_STATUS_NOT_FOUND
;
1247 * Trim pathname sent by client so it begins with only one backslash.
1248 * Two backslashes confuse some dfs clients
1251 local_dfs_path
= talloc_strdup(ctx
,dfs_path
);
1252 if (!local_dfs_path
) {
1253 *pstatus
= NT_STATUS_NO_MEMORY
;
1254 talloc_destroy(ctx
);
1257 pathnamep
= local_dfs_path
;
1258 while (IS_DIRECTORY_SEP(pathnamep
[0]) &&
1259 IS_DIRECTORY_SEP(pathnamep
[1])) {
1263 junction
= talloc_zero(ctx
, struct junction_map
);
1265 *pstatus
= NT_STATUS_NO_MEMORY
;
1266 talloc_destroy(ctx
);
1270 /* The following call can change cwd. */
1271 *pstatus
= get_referred_path(ctx
, pathnamep
, orig_conn
->sconn
,
1272 junction
, &consumedcnt
, &self_referral
);
1273 if (!NT_STATUS_IS_OK(*pstatus
)) {
1274 vfs_ChDir(orig_conn
,orig_conn
->connectpath
);
1275 talloc_destroy(ctx
);
1278 vfs_ChDir(orig_conn
,orig_conn
->connectpath
);
1280 if (!self_referral
) {
1281 pathnamep
[consumedcnt
] = '\0';
1283 if( DEBUGLVL( 3 ) ) {
1285 dbgtext("setup_dfs_referral: Path %s to "
1286 "alternate path(s):",
1288 for(i
=0;i
<junction
->referral_count
;i
++)
1290 junction
->referral_list
[i
].alternate_path
);
1295 /* create the referral depeding on version */
1296 DEBUG(10,("max_referral_level :%d\n",max_referral_level
));
1298 if (max_referral_level
< 2) {
1299 max_referral_level
= 2;
1301 if (max_referral_level
> 3) {
1302 max_referral_level
= 3;
1305 switch(max_referral_level
) {
1307 reply_size
= setup_ver2_dfs_referral(pathnamep
,
1312 reply_size
= setup_ver3_dfs_referral(pathnamep
, ppdata
,
1313 junction
, self_referral
);
1316 DEBUG(0,("setup_dfs_referral: Invalid dfs referral "
1318 max_referral_level
));
1319 talloc_destroy(ctx
);
1320 *pstatus
= NT_STATUS_INVALID_LEVEL
;
1325 DEBUGADD(0,("DFS Referral pdata:\n"));
1326 dump_data(0,(uint8
*)*ppdata
,reply_size
);
1329 talloc_destroy(ctx
);
1330 *pstatus
= NT_STATUS_OK
;
1334 /**********************************************************************
1335 The following functions are called by the NETDFS RPC pipe functions
1336 **********************************************************************/
1338 /*********************************************************************
1339 Creates a junction structure from a DFS pathname
1340 **********************************************************************/
1342 bool create_junction(TALLOC_CTX
*ctx
,
1343 const char *dfs_path
,
1344 bool allow_broken_path
,
1345 struct junction_map
*jucn
)
1349 struct dfs_path
*pdp
= talloc(ctx
,struct dfs_path
);
1355 status
= parse_dfs_path(NULL
, dfs_path
, False
, allow_broken_path
,
1357 if (!NT_STATUS_IS_OK(status
)) {
1361 /* check if path is dfs : validate first token */
1362 if (!is_myname_or_ipaddr(pdp
->hostname
)) {
1363 DEBUG(4,("create_junction: Invalid hostname %s "
1365 pdp
->hostname
, dfs_path
));
1370 /* Check for a non-DFS share */
1371 snum
= lp_servicenumber(pdp
->servicename
);
1373 if(snum
< 0 || !lp_msdfs_root(snum
)) {
1374 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1380 jucn
->service_name
= talloc_strdup(ctx
, pdp
->servicename
);
1381 jucn
->volume_name
= talloc_strdup(ctx
, pdp
->reqpath
);
1382 jucn
->comment
= talloc_strdup(ctx
, lp_comment(snum
));
1385 if (!jucn
->service_name
|| !jucn
->volume_name
|| ! jucn
->comment
) {
1391 /**********************************************************************
1392 Forms a valid Unix pathname from the junction
1393 **********************************************************************/
1395 static bool junction_to_local_path(const struct junction_map
*jucn
,
1397 connection_struct
**conn_out
,
1403 snum
= lp_servicenumber(jucn
->service_name
);
1407 status
= create_conn_struct(talloc_tos(), smbd_server_conn
, conn_out
,
1408 snum
, lp_pathname(snum
), NULL
, oldpath
);
1409 if (!NT_STATUS_IS_OK(status
)) {
1413 *pp_path_out
= talloc_asprintf(*conn_out
,
1417 if (!*pp_path_out
) {
1418 vfs_ChDir(*conn_out
, *oldpath
);
1419 SMB_VFS_DISCONNECT(*conn_out
);
1420 conn_free(*conn_out
);
1426 bool create_msdfs_link(const struct junction_map
*jucn
)
1430 char *msdfs_link
= NULL
;
1431 connection_struct
*conn
;
1433 bool insert_comma
= False
;
1436 if(!junction_to_local_path(jucn
, &path
, &conn
, &cwd
)) {
1440 /* Form the msdfs_link contents */
1441 msdfs_link
= talloc_strdup(conn
, "msdfs:");
1445 for(i
=0; i
<jucn
->referral_count
; i
++) {
1446 char *refpath
= jucn
->referral_list
[i
].alternate_path
;
1448 /* Alternate paths always use Windows separators. */
1449 trim_char(refpath
, '\\', '\\');
1450 if(*refpath
== '\0') {
1452 insert_comma
= False
;
1456 if (i
> 0 && insert_comma
) {
1457 msdfs_link
= talloc_asprintf_append_buffer(msdfs_link
,
1461 msdfs_link
= talloc_asprintf_append_buffer(msdfs_link
,
1469 if (!insert_comma
) {
1470 insert_comma
= True
;
1474 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1477 if(SMB_VFS_SYMLINK(conn
, msdfs_link
, path
) < 0) {
1478 if (errno
== EEXIST
) {
1479 struct smb_filename
*smb_fname
= NULL
;
1482 status
= create_synthetic_smb_fname(talloc_tos(), path
,
1485 if (!NT_STATUS_IS_OK(status
)) {
1486 errno
= map_errno_from_nt_status(status
);
1490 if(SMB_VFS_UNLINK(conn
, smb_fname
)!=0) {
1491 TALLOC_FREE(smb_fname
);
1494 TALLOC_FREE(smb_fname
);
1496 if (SMB_VFS_SYMLINK(conn
, msdfs_link
, path
) < 0) {
1497 DEBUG(1,("create_msdfs_link: symlink failed "
1498 "%s -> %s\nError: %s\n",
1499 path
, msdfs_link
, strerror(errno
)));
1507 vfs_ChDir(conn
, cwd
);
1508 SMB_VFS_DISCONNECT(conn
);
1513 bool remove_msdfs_link(const struct junction_map
*jucn
)
1517 connection_struct
*conn
;
1519 struct smb_filename
*smb_fname
= NULL
;
1522 if (!junction_to_local_path(jucn
, &path
, &conn
, &cwd
)) {
1526 status
= create_synthetic_smb_fname(talloc_tos(), path
,
1529 if (!NT_STATUS_IS_OK(status
)) {
1530 errno
= map_errno_from_nt_status(status
);
1534 if( SMB_VFS_UNLINK(conn
, smb_fname
) == 0 ) {
1538 TALLOC_FREE(smb_fname
);
1539 vfs_ChDir(conn
, cwd
);
1540 SMB_VFS_DISCONNECT(conn
);
1545 /*********************************************************************
1546 Return the number of DFS links at the root of this share.
1547 *********************************************************************/
1549 static int count_dfs_links(TALLOC_CTX
*ctx
, int snum
)
1552 SMB_STRUCT_DIR
*dirp
= NULL
;
1553 const char *dname
= NULL
;
1554 char *talloced
= NULL
;
1555 const char *connect_path
= lp_pathname(snum
);
1556 const char *msdfs_proxy
= lp_msdfs_proxy(snum
);
1557 connection_struct
*conn
;
1561 if(*connect_path
== '\0') {
1566 * Fake up a connection struct for the VFS layer.
1569 status
= create_conn_struct(talloc_tos(), smbd_server_conn
, &conn
,
1570 snum
, connect_path
, NULL
, &cwd
);
1571 if (!NT_STATUS_IS_OK(status
)) {
1572 DEBUG(3, ("create_conn_struct failed: %s\n",
1573 nt_errstr(status
)));
1577 /* Count a link for the msdfs root - convention */
1580 /* No more links if this is an msdfs proxy. */
1581 if (*msdfs_proxy
!= '\0') {
1585 /* Now enumerate all dfs links */
1586 dirp
= SMB_VFS_OPENDIR(conn
, ".", NULL
, 0);
1591 while ((dname
= vfs_readdirname(conn
, dirp
, NULL
, &talloced
))
1593 if (is_msdfs_link(conn
,
1598 TALLOC_FREE(talloced
);
1601 SMB_VFS_CLOSEDIR(conn
,dirp
);
1604 vfs_ChDir(conn
, cwd
);
1605 SMB_VFS_DISCONNECT(conn
);
1610 /*********************************************************************
1611 *********************************************************************/
1613 static int form_junctions(TALLOC_CTX
*ctx
,
1615 struct junction_map
*jucn
,
1619 SMB_STRUCT_DIR
*dirp
= NULL
;
1620 const char *dname
= NULL
;
1621 char *talloced
= NULL
;
1622 const char *connect_path
= lp_pathname(snum
);
1623 char *service_name
= lp_servicename(snum
);
1624 const char *msdfs_proxy
= lp_msdfs_proxy(snum
);
1625 connection_struct
*conn
;
1626 struct referral
*ref
= NULL
;
1630 if (jn_remain
== 0) {
1634 if(*connect_path
== '\0') {
1639 * Fake up a connection struct for the VFS layer.
1642 status
= create_conn_struct(ctx
, smbd_server_conn
, &conn
, snum
, connect_path
, NULL
,
1644 if (!NT_STATUS_IS_OK(status
)) {
1645 DEBUG(3, ("create_conn_struct failed: %s\n",
1646 nt_errstr(status
)));
1650 /* form a junction for the msdfs root - convention
1651 DO NOT REMOVE THIS: NT clients will not work with us
1652 if this is not present
1654 jucn
[cnt
].service_name
= talloc_strdup(ctx
,service_name
);
1655 jucn
[cnt
].volume_name
= talloc_strdup(ctx
, "");
1656 if (!jucn
[cnt
].service_name
|| !jucn
[cnt
].volume_name
) {
1659 jucn
[cnt
].comment
= "";
1660 jucn
[cnt
].referral_count
= 1;
1662 ref
= jucn
[cnt
].referral_list
= talloc_zero(ctx
, struct referral
);
1663 if (jucn
[cnt
].referral_list
== NULL
) {
1668 ref
->ttl
= REFERRAL_TTL
;
1669 if (*msdfs_proxy
!= '\0') {
1670 ref
->alternate_path
= talloc_strdup(ctx
,
1673 ref
->alternate_path
= talloc_asprintf(ctx
,
1675 get_local_machine_name(),
1679 if (!ref
->alternate_path
) {
1684 /* Don't enumerate if we're an msdfs proxy. */
1685 if (*msdfs_proxy
!= '\0') {
1689 /* Now enumerate all dfs links */
1690 dirp
= SMB_VFS_OPENDIR(conn
, ".", NULL
, 0);
1695 while ((dname
= vfs_readdirname(conn
, dirp
, NULL
, &talloced
))
1697 char *link_target
= NULL
;
1698 if (cnt
>= jn_remain
) {
1699 DEBUG(2, ("form_junctions: ran out of MSDFS "
1701 TALLOC_FREE(talloced
);
1704 if (is_msdfs_link_internal(ctx
,
1706 dname
, &link_target
,
1708 if (parse_msdfs_symlink(ctx
,
1710 &jucn
[cnt
].referral_list
,
1711 &jucn
[cnt
].referral_count
)) {
1713 jucn
[cnt
].service_name
= talloc_strdup(ctx
,
1715 jucn
[cnt
].volume_name
= talloc_strdup(ctx
,
1717 if (!jucn
[cnt
].service_name
||
1718 !jucn
[cnt
].volume_name
) {
1719 TALLOC_FREE(talloced
);
1722 jucn
[cnt
].comment
= "";
1725 TALLOC_FREE(link_target
);
1727 TALLOC_FREE(talloced
);
1733 SMB_VFS_CLOSEDIR(conn
,dirp
);
1736 vfs_ChDir(conn
, cwd
);
1741 struct junction_map
*enum_msdfs_links(struct smbd_server_connection
*sconn
,
1742 TALLOC_CTX
*ctx
, size_t *p_num_jn
)
1744 struct junction_map
*jn
= NULL
;
1746 size_t jn_count
= 0;
1750 if(!lp_host_msdfs()) {
1754 /* Ensure all the usershares are loaded. */
1756 load_registry_shares();
1757 sharecount
= load_usershare_shares(sconn
);
1760 for(i
=0;i
< sharecount
;i
++) {
1761 if(lp_msdfs_root(i
)) {
1762 jn_count
+= count_dfs_links(ctx
, i
);
1765 if (jn_count
== 0) {
1768 jn
= talloc_array(ctx
, struct junction_map
, jn_count
);
1772 for(i
=0; i
< sharecount
; i
++) {
1773 if (*p_num_jn
>= jn_count
) {
1776 if(lp_msdfs_root(i
)) {
1777 *p_num_jn
+= form_junctions(ctx
, i
,
1779 jn_count
- *p_num_jn
);
1785 /******************************************************************************
1786 Core function to resolve a dfs pathname possibly containing a wildcard. If
1787 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1788 detected during dfs resolution.
1789 ******************************************************************************/
1791 NTSTATUS
resolve_dfspath_wcard(TALLOC_CTX
*ctx
,
1792 connection_struct
*conn
,
1794 const char *name_in
,
1797 bool *ppath_contains_wcard
)
1799 bool path_contains_wcard
;
1800 NTSTATUS status
= NT_STATUS_OK
;
1802 if (dfs_pathnames
) {
1803 status
= dfs_redirect(ctx
,
1807 !smbd_server_conn
->using_smb2
,
1809 &path_contains_wcard
);
1811 if (NT_STATUS_IS_OK(status
) && ppath_contains_wcard
!= NULL
) {
1812 *ppath_contains_wcard
= path_contains_wcard
;
1816 * Cheat and just return a copy of the in ptr.
1817 * Once srvstr_get_path() uses talloc it'll
1818 * be a talloced ptr anyway.
1820 *pp_name_out
= discard_const_p(char, name_in
);