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 "libcli/security/security.h"
32 /**********************************************************************
33 Parse a DFS pathname of the form \hostname\service\reqpath
34 into the dfs_path structure.
35 If POSIX pathnames is true, the pathname may also be of the
36 form /hostname/service/reqpath.
37 We cope with either here.
39 Unfortunately, due to broken clients who might set the
40 SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
41 send a local path, we have to cope with that too....
43 If conn != NULL then ensure the provided service is
44 the one pointed to by the connection.
46 This version does everything using pointers within one copy of the
47 pathname string, talloced on the struct dfs_path pointer (which
48 must be talloced). This may be too clever to live....
50 **********************************************************************/
52 static NTSTATUS
parse_dfs_path(connection_struct
*conn
,
55 struct dfs_path
*pdp
, /* MUST BE TALLOCED */
56 bool *ppath_contains_wcard
)
58 struct smbd_server_connection
*sconn
= smbd_server_conn
;
63 NTSTATUS status
= NT_STATUS_OK
;
69 * This is the only talloc we should need to do
70 * on the struct dfs_path. All the pointers inside
71 * it should point to offsets within this string.
74 pathname_local
= talloc_strdup(pdp
, pathname
);
75 if (!pathname_local
) {
76 return NT_STATUS_NO_MEMORY
;
78 /* Get a pointer to the terminating '\0' */
79 eos_ptr
= &pathname_local
[strlen(pathname_local
)];
80 p
= temp
= pathname_local
;
82 pdp
->posix_path
= (lp_posix_pathnames() && *pathname
== '/');
84 sepchar
= pdp
->posix_path
? '/' : '\\';
86 if (!sconn
->using_smb2
&& (*pathname
!= sepchar
)) {
87 DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
90 * Possibly client sent a local path by mistake.
91 * Try and convert to a local path.
94 pdp
->hostname
= eos_ptr
; /* "" */
95 pdp
->servicename
= eos_ptr
; /* "" */
97 /* We've got no info about separators. */
98 pdp
->posix_path
= lp_posix_pathnames();
100 DEBUG(10,("parse_dfs_path: trying to convert %s to a "
107 * Safe to use on talloc'ed string as it only shrinks.
108 * It also doesn't affect the eos_ptr.
110 trim_char(temp
,sepchar
,sepchar
);
112 DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
116 /* Parse out hostname. */
117 p
= strchr_m(temp
,sepchar
);
119 DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
122 * Possibly client sent a local path by mistake.
123 * Try and convert to a local path.
126 pdp
->hostname
= eos_ptr
; /* "" */
127 pdp
->servicename
= eos_ptr
; /* "" */
130 DEBUG(10,("parse_dfs_path: trying to convert %s "
136 pdp
->hostname
= temp
;
138 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp
->hostname
));
140 /* Parse out servicename. */
142 p
= strchr_m(servicename
,sepchar
);
147 /* Is this really our servicename ? */
148 if (conn
&& !( strequal(servicename
, lp_servicename(SNUM(conn
)))
149 || (strequal(servicename
, HOMES_NAME
)
150 && strequal(lp_servicename(SNUM(conn
)),
151 get_current_username()) )) ) {
152 DEBUG(10,("parse_dfs_path: %s is not our servicename\n",
156 * Possibly client sent a local path by mistake.
157 * Try and convert to a local path.
160 pdp
->hostname
= eos_ptr
; /* "" */
161 pdp
->servicename
= eos_ptr
; /* "" */
163 /* Repair the path - replace the sepchar's
166 *servicename
= sepchar
;
172 DEBUG(10,("parse_dfs_path: trying to convert %s "
178 pdp
->servicename
= servicename
;
180 DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp
->servicename
));
183 /* Client sent self referral \server\share. */
184 pdp
->reqpath
= eos_ptr
; /* "" */
192 *ppath_contains_wcard
= False
;
196 /* Rest is reqpath. */
197 if (pdp
->posix_path
) {
198 status
= check_path_syntax_posix(pdp
->reqpath
);
201 status
= check_path_syntax_wcard(pdp
->reqpath
,
202 ppath_contains_wcard
);
204 status
= check_path_syntax(pdp
->reqpath
);
208 if (!NT_STATUS_IS_OK(status
)) {
209 DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
210 p
, nt_errstr(status
) ));
214 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp
->reqpath
));
218 /********************************************************
219 Fake up a connection struct for the VFS layer.
220 Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
221 *********************************************************/
223 NTSTATUS
create_conn_struct(TALLOC_CTX
*ctx
,
224 connection_struct
**pconn
,
227 const struct auth_serversupplied_info
*session_info
,
230 connection_struct
*conn
;
233 const char *vfs_user
;
235 conn
= TALLOC_ZERO_P(ctx
, connection_struct
);
237 return NT_STATUS_NO_MEMORY
;
240 connpath
= talloc_strdup(conn
, path
);
243 return NT_STATUS_NO_MEMORY
;
245 connpath
= talloc_string_sub(conn
,
248 lp_servicename(snum
));
251 return NT_STATUS_NO_MEMORY
;
254 /* needed for smbd_vfs_init() */
256 if (!(conn
->params
= TALLOC_ZERO_P(conn
, struct share_params
))) {
257 DEBUG(0, ("TALLOC failed\n"));
259 return NT_STATUS_NO_MEMORY
;
262 conn
->params
->service
= snum
;
264 conn
->sconn
= smbd_server_conn
;
265 conn
->sconn
->num_tcons_open
++;
267 if (session_info
!= NULL
) {
268 conn
->session_info
= copy_serverinfo(conn
, session_info
);
269 if (conn
->session_info
== NULL
) {
270 DEBUG(0, ("copy_serverinfo failed\n"));
272 return NT_STATUS_NO_MEMORY
;
274 vfs_user
= conn
->session_info
->unix_name
;
276 /* use current authenticated user in absence of session_info */
277 vfs_user
= get_current_username();
280 set_conn_connectpath(conn
, connpath
);
283 * New code to check if there's a share security descripter
284 * added from NT server manager. This is done after the
285 * smb.conf checks are done as we need a uid and token. JRA.
288 if (conn
->session_info
) {
289 share_access_check(conn
->session_info
->security_token
,
290 lp_servicename(snum
), MAXIMUM_ALLOWED_ACCESS
,
291 &conn
->share_access
);
293 if ((conn
->share_access
& FILE_WRITE_DATA
) == 0) {
294 if ((conn
->share_access
& FILE_READ_DATA
) == 0) {
295 /* No access, read or write. */
296 DEBUG(0,("create_conn_struct: connection to %s "
297 "denied due to security "
299 lp_servicename(snum
)));
301 return NT_STATUS_ACCESS_DENIED
;
303 conn
->read_only
= true;
307 conn
->share_access
= 0;
308 conn
->read_only
= true;
311 if (!smbd_vfs_init(conn
)) {
312 NTSTATUS status
= map_nt_error_from_unix(errno
);
313 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
318 /* this must be the first filesystem operation that we do */
319 if (SMB_VFS_CONNECT(conn
, lp_servicename(snum
), vfs_user
) < 0) {
320 DEBUG(0,("VFS connect failed!\n"));
322 return NT_STATUS_UNSUCCESSFUL
;
325 conn
->fs_capabilities
= SMB_VFS_FS_CAPABILITIES(conn
, &conn
->ts_res
);
328 * Windows seems to insist on doing trans2getdfsreferral() calls on
329 * the IPC$ share as the anonymous user. If we try to chdir as that
330 * user we will fail.... WTF ? JRA.
333 oldcwd
= vfs_GetWd(ctx
, conn
);
334 if (oldcwd
== NULL
) {
335 NTSTATUS status
= map_nt_error_from_unix(errno
);
336 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno
)));
341 if (vfs_ChDir(conn
,conn
->connectpath
) != 0) {
342 NTSTATUS status
= map_nt_error_from_unix(errno
);
343 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
345 conn
->connectpath
, strerror(errno
) ));
356 /**********************************************************************
357 Parse the contents of a symlink to verify if it is an msdfs referral
358 A valid referral is of the form:
360 msdfs:server1\share1,server2\share2
361 msdfs:server1\share1\pathname,server2\share2\pathname
362 msdfs:server1/share1,server2/share2
363 msdfs:server1/share1/pathname,server2/share2/pathname.
365 Note that the alternate paths returned here must be of the canonicalized
369 \server\share\path\to\file,
371 even in posix path mode. This is because we have no knowledge if the
372 server we're referring to understands posix paths.
373 **********************************************************************/
375 static bool parse_msdfs_symlink(TALLOC_CTX
*ctx
,
377 struct referral
**preflist
,
382 char **alt_path
= NULL
;
384 struct referral
*reflist
;
387 temp
= talloc_strdup(ctx
, target
);
391 prot
= strtok_r(temp
, ":", &saveptr
);
393 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
397 alt_path
= TALLOC_ARRAY(ctx
, char *, MAX_REFERRAL_COUNT
);
402 /* parse out the alternate paths */
403 while((count
<MAX_REFERRAL_COUNT
) &&
404 ((alt_path
[count
] = strtok_r(NULL
, ",", &saveptr
)) != NULL
)) {
408 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count
));
411 reflist
= *preflist
= TALLOC_ZERO_ARRAY(ctx
,
412 struct referral
, count
);
413 if(reflist
== NULL
) {
414 TALLOC_FREE(alt_path
);
418 reflist
= *preflist
= NULL
;
421 for(i
=0;i
<count
;i
++) {
424 /* Canonicalize link target.
425 * Replace all /'s in the path by a \ */
426 string_replace(alt_path
[i
], '/', '\\');
428 /* Remove leading '\\'s */
430 while (*p
&& (*p
== '\\')) {
434 reflist
[i
].alternate_path
= talloc_asprintf(ctx
,
437 if (!reflist
[i
].alternate_path
) {
441 reflist
[i
].proximity
= 0;
442 reflist
[i
].ttl
= REFERRAL_TTL
;
443 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
444 reflist
[i
].alternate_path
));
449 TALLOC_FREE(alt_path
);
453 /**********************************************************************
454 Returns true if the unix path is a valid msdfs symlink and also
455 returns the target string from inside the link.
456 **********************************************************************/
458 static bool is_msdfs_link_internal(TALLOC_CTX
*ctx
,
459 connection_struct
*conn
,
461 char **pp_link_target
,
462 SMB_STRUCT_STAT
*sbufp
)
464 int referral_len
= 0;
465 #if defined(HAVE_BROKEN_READLINK)
466 char link_target_buf
[PATH_MAX
];
468 char link_target_buf
[7];
471 char *link_target
= NULL
;
472 struct smb_filename smb_fname
;
474 if (pp_link_target
) {
476 link_target
= TALLOC_ARRAY(ctx
, char, bufsize
);
480 *pp_link_target
= link_target
;
482 bufsize
= sizeof(link_target_buf
);
483 link_target
= link_target_buf
;
486 ZERO_STRUCT(smb_fname
);
487 smb_fname
.base_name
= discard_const_p(char, path
);
489 if (SMB_VFS_LSTAT(conn
, &smb_fname
) != 0) {
490 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
494 if (!S_ISLNK(smb_fname
.st
.st_ex_mode
)) {
495 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
500 *sbufp
= smb_fname
.st
;
503 referral_len
= SMB_VFS_READLINK(conn
, path
, link_target
, bufsize
- 1);
504 if (referral_len
== -1) {
505 DEBUG(0,("is_msdfs_link_read_target: Error reading "
506 "msdfs link %s: %s\n",
507 path
, strerror(errno
)));
510 link_target
[referral_len
] = '\0';
512 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path
,
515 if (!strnequal(link_target
, "msdfs:", 6)) {
522 if (link_target
!= link_target_buf
) {
523 TALLOC_FREE(link_target
);
528 /**********************************************************************
529 Returns true if the unix path is a valid msdfs symlink.
530 **********************************************************************/
532 bool is_msdfs_link(connection_struct
*conn
,
534 SMB_STRUCT_STAT
*sbufp
)
536 return is_msdfs_link_internal(talloc_tos(),
543 /*****************************************************************
544 Used by other functions to decide if a dfs path is remote,
545 and to get the list of referred locations for that remote path.
547 search_flag: For findfirsts, dfs links themselves are not
548 redirected, but paths beyond the links are. For normal smb calls,
549 even dfs links need to be redirected.
551 consumedcntp: how much of the dfs path is being redirected. the client
552 should try the remaining path on the redirected server.
554 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
555 link redirect are in targetpath.
556 *****************************************************************/
558 static NTSTATUS
dfs_path_lookup(TALLOC_CTX
*ctx
,
559 connection_struct
*conn
,
560 const char *dfspath
, /* Incoming complete dfs path */
561 const struct dfs_path
*pdp
, /* Parsed out
562 server+share+extrapath. */
563 bool search_flag
, /* Called from a findfirst ? */
565 char **pp_targetpath
)
570 struct smb_filename
*smb_fname
= NULL
;
571 char *canon_dfspath
= NULL
; /* Canonicalized dfs path. (only '/'
574 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
575 conn
->connectpath
, pdp
->reqpath
));
578 * Note the unix path conversion here we're doing we
579 * throw away. We're looking for a symlink for a dfs
580 * resolution, if we don't find it we'll do another
581 * unix_convert later in the codepath.
584 status
= unix_convert(ctx
, conn
, pdp
->reqpath
, &smb_fname
,
585 search_flag
? UCF_ALWAYS_ALLOW_WCARD_LCOMP
: 0);
587 if (!NT_STATUS_IS_OK(status
)) {
588 if (!NT_STATUS_EQUAL(status
,
589 NT_STATUS_OBJECT_PATH_NOT_FOUND
)) {
592 if (smb_fname
== NULL
|| smb_fname
->base_name
== NULL
) {
597 /* Optimization - check if we can redirect the whole path. */
599 if (is_msdfs_link_internal(ctx
, conn
, smb_fname
->base_name
,
600 pp_targetpath
, NULL
)) {
602 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
603 "for dfs link %s.\n", dfspath
));
604 status
= NT_STATUS_OK
;
608 DEBUG(6,("dfs_path_lookup: %s resolves to a "
609 "valid dfs link %s.\n", dfspath
,
610 pp_targetpath
? *pp_targetpath
: ""));
613 *consumedcntp
= strlen(dfspath
);
615 status
= NT_STATUS_PATH_NOT_COVERED
;
619 /* Prepare to test only for '/' components in the given path,
620 * so if a Windows path replace all '\\' characters with '/'.
621 * For a POSIX DFS path we know all separators are already '/'. */
623 canon_dfspath
= talloc_strdup(ctx
, dfspath
);
624 if (!canon_dfspath
) {
625 status
= NT_STATUS_NO_MEMORY
;
628 if (!pdp
->posix_path
) {
629 string_replace(canon_dfspath
, '\\', '/');
633 * localpath comes out of unix_convert, so it has
634 * no trailing backslash. Make sure that canon_dfspath hasn't either.
635 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
638 trim_char(canon_dfspath
,0,'/');
641 * Redirect if any component in the path is a link.
642 * We do this by walking backwards through the
643 * local path, chopping off the last component
644 * in both the local path and the canonicalized
645 * DFS path. If we hit a DFS link then we're done.
648 p
= strrchr_m(smb_fname
->base_name
, '/');
650 q
= strrchr_m(canon_dfspath
, '/');
659 if (is_msdfs_link_internal(ctx
, conn
,
660 smb_fname
->base_name
, pp_targetpath
,
662 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
663 "parent %s is dfs link\n", dfspath
,
664 smb_fname_str_dbg(smb_fname
)));
667 *consumedcntp
= strlen(canon_dfspath
);
668 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
674 status
= NT_STATUS_PATH_NOT_COVERED
;
678 /* Step back on the filesystem. */
679 p
= strrchr_m(smb_fname
->base_name
, '/');
682 /* And in the canonicalized dfs path. */
683 q
= strrchr_m(canon_dfspath
, '/');
687 status
= NT_STATUS_OK
;
689 TALLOC_FREE(smb_fname
);
693 /*****************************************************************
694 Decides if a dfs pathname should be redirected or not.
695 If not, the pathname is converted to a tcon-relative local unix path
697 search_wcard_flag: this flag performs 2 functions both related
698 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
701 This function can return NT_STATUS_OK, meaning use the returned path as-is
702 (mapped into a local path).
703 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
704 any other NT_STATUS error which is a genuine error to be
705 returned to the client.
706 *****************************************************************/
708 static NTSTATUS
dfs_redirect(TALLOC_CTX
*ctx
,
709 connection_struct
*conn
,
711 bool search_wcard_flag
,
713 bool *ppath_contains_wcard
)
716 struct dfs_path
*pdp
= TALLOC_P(ctx
, struct dfs_path
);
719 return NT_STATUS_NO_MEMORY
;
722 status
= parse_dfs_path(conn
, path_in
, search_wcard_flag
, pdp
,
723 ppath_contains_wcard
);
724 if (!NT_STATUS_IS_OK(status
)) {
729 if (pdp
->reqpath
[0] == '\0') {
731 *pp_path_out
= talloc_strdup(ctx
, "");
733 return NT_STATUS_NO_MEMORY
;
735 DEBUG(5,("dfs_redirect: self-referral.\n"));
739 /* If dfs pathname for a non-dfs share, convert to tcon-relative
740 path and return OK */
742 if (!lp_msdfs_root(SNUM(conn
))) {
743 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
746 return NT_STATUS_NO_MEMORY
;
751 /* If it looked like a local path (zero hostname/servicename)
752 * just treat as a tcon-relative path. */
754 if (pdp
->hostname
[0] == '\0' && pdp
->servicename
[0] == '\0') {
755 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
758 return NT_STATUS_NO_MEMORY
;
763 if (!( strequal(pdp
->servicename
, lp_servicename(SNUM(conn
)))
764 || (strequal(pdp
->servicename
, HOMES_NAME
)
765 && strequal(lp_servicename(SNUM(conn
)),
766 conn
->session_info
->sanitized_username
) )) ) {
768 /* The given sharename doesn't match this connection. */
771 return NT_STATUS_OBJECT_PATH_NOT_FOUND
;
774 status
= dfs_path_lookup(ctx
, conn
, path_in
, pdp
,
775 search_wcard_flag
, NULL
, NULL
);
776 if (!NT_STATUS_IS_OK(status
)) {
777 if (NT_STATUS_EQUAL(status
, NT_STATUS_PATH_NOT_COVERED
)) {
778 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in
));
780 DEBUG(10,("dfs_redirect: dfs_path_lookup "
781 "failed for %s with %s\n",
782 path_in
, nt_errstr(status
) ));
787 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in
));
789 /* Form non-dfs tcon-relative path */
790 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
793 return NT_STATUS_NO_MEMORY
;
796 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
803 /**********************************************************************
804 Return a self referral.
805 **********************************************************************/
807 static NTSTATUS
self_ref(TALLOC_CTX
*ctx
,
808 const char *dfs_path
,
809 struct junction_map
*jucn
,
811 bool *self_referralp
)
813 struct referral
*ref
;
815 *self_referralp
= True
;
817 jucn
->referral_count
= 1;
818 if((ref
= TALLOC_ZERO_P(ctx
, struct referral
)) == NULL
) {
819 return NT_STATUS_NO_MEMORY
;
822 ref
->alternate_path
= talloc_strdup(ctx
, dfs_path
);
823 if (!ref
->alternate_path
) {
824 return NT_STATUS_NO_MEMORY
;
827 ref
->ttl
= REFERRAL_TTL
;
828 jucn
->referral_list
= ref
;
829 *consumedcntp
= strlen(dfs_path
);
833 /**********************************************************************
834 Gets valid referrals for a dfs path and fills up the
835 junction_map structure.
836 **********************************************************************/
838 NTSTATUS
get_referred_path(TALLOC_CTX
*ctx
,
839 const char *dfs_path
,
840 struct junction_map
*jucn
,
842 bool *self_referralp
)
844 struct connection_struct
*conn
;
845 char *targetpath
= NULL
;
847 NTSTATUS status
= NT_STATUS_NOT_FOUND
;
849 struct dfs_path
*pdp
= TALLOC_P(ctx
, struct dfs_path
);
853 return NT_STATUS_NO_MEMORY
;
856 *self_referralp
= False
;
858 status
= parse_dfs_path(NULL
, dfs_path
, False
, pdp
, &dummy
);
859 if (!NT_STATUS_IS_OK(status
)) {
863 jucn
->service_name
= talloc_strdup(ctx
, pdp
->servicename
);
864 jucn
->volume_name
= talloc_strdup(ctx
, pdp
->reqpath
);
865 if (!jucn
->service_name
|| !jucn
->volume_name
) {
867 return NT_STATUS_NO_MEMORY
;
870 /* Verify the share is a dfs root */
871 snum
= lp_servicenumber(jucn
->service_name
);
873 char *service_name
= NULL
;
874 if ((snum
= find_service(ctx
, jucn
->service_name
, &service_name
)) < 0) {
875 return NT_STATUS_NOT_FOUND
;
878 return NT_STATUS_NO_MEMORY
;
880 TALLOC_FREE(jucn
->service_name
);
881 jucn
->service_name
= talloc_strdup(ctx
, service_name
);
882 if (!jucn
->service_name
) {
884 return NT_STATUS_NO_MEMORY
;
888 if (!lp_msdfs_root(snum
) && (*lp_msdfs_proxy(snum
) == '\0')) {
889 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
891 pdp
->servicename
, dfs_path
));
893 return NT_STATUS_NOT_FOUND
;
897 * Self referrals are tested with a anonymous IPC connection and
898 * a GET_DFS_REFERRAL call to \\server\share. (which means
899 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
900 * into the directory and will fail if it cannot (as the anonymous
901 * user). Cope with this.
904 if (pdp
->reqpath
[0] == '\0') {
906 struct referral
*ref
;
908 if (*lp_msdfs_proxy(snum
) == '\0') {
918 * It's an msdfs proxy share. Redirect to
919 * the configured target share.
922 jucn
->referral_count
= 1;
923 if ((ref
= TALLOC_ZERO_P(ctx
, struct referral
)) == NULL
) {
925 return NT_STATUS_NO_MEMORY
;
928 if (!(tmp
= talloc_strdup(ctx
, lp_msdfs_proxy(snum
)))) {
930 return NT_STATUS_NO_MEMORY
;
933 trim_string(tmp
, "\\", 0);
935 ref
->alternate_path
= talloc_asprintf(ctx
, "\\%s", tmp
);
938 if (!ref
->alternate_path
) {
940 return NT_STATUS_NO_MEMORY
;
943 if (pdp
->reqpath
[0] != '\0') {
944 ref
->alternate_path
= talloc_asprintf_append(
948 if (!ref
->alternate_path
) {
950 return NT_STATUS_NO_MEMORY
;
954 ref
->ttl
= REFERRAL_TTL
;
955 jucn
->referral_list
= ref
;
956 *consumedcntp
= strlen(dfs_path
);
961 status
= create_conn_struct(ctx
, &conn
, snum
, lp_pathname(snum
),
963 if (!NT_STATUS_IS_OK(status
)) {
968 /* If this is a DFS path dfs_lookup should return
969 * NT_STATUS_PATH_NOT_COVERED. */
971 status
= dfs_path_lookup(ctx
, conn
, dfs_path
, pdp
,
972 False
, consumedcntp
, &targetpath
);
974 if (!NT_STATUS_EQUAL(status
, NT_STATUS_PATH_NOT_COVERED
)) {
975 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
980 /* We know this is a valid dfs link. Parse the targetpath. */
981 if (!parse_msdfs_symlink(ctx
, targetpath
,
982 &jucn
->referral_list
,
983 &jucn
->referral_count
)) {
984 DEBUG(3,("get_referred_path: failed to parse symlink "
985 "target %s\n", targetpath
));
986 status
= NT_STATUS_NOT_FOUND
;
990 status
= NT_STATUS_OK
;
992 vfs_ChDir(conn
, oldpath
);
993 SMB_VFS_DISCONNECT(conn
);
999 static int setup_ver2_dfs_referral(const char *pathname
,
1001 struct junction_map
*junction
,
1004 char* pdata
= *ppdata
;
1006 smb_ucs2_t
*uni_requestedpath
= NULL
;
1007 int uni_reqpathoffset1
,uni_reqpathoffset2
;
1009 int requestedpathlen
=0;
1014 DEBUG(10,("Setting up version2 referral\nRequested path:\n"));
1016 requestedpathlen
= rpcstr_push_talloc(talloc_tos(),
1017 &uni_requestedpath
, pathname
);
1018 if (uni_requestedpath
== NULL
|| requestedpathlen
== 0) {
1023 dump_data(0, (unsigned char *)uni_requestedpath
,
1027 DEBUG(10,("ref count = %u\n",junction
->referral_count
));
1029 uni_reqpathoffset1
= REFERRAL_HEADER_SIZE
+
1030 VERSION2_REFERRAL_SIZE
* junction
->referral_count
;
1032 uni_reqpathoffset2
= uni_reqpathoffset1
+ requestedpathlen
;
1034 uni_curroffset
= uni_reqpathoffset2
+ requestedpathlen
;
1036 reply_size
= REFERRAL_HEADER_SIZE
+
1037 VERSION2_REFERRAL_SIZE
*junction
->referral_count
+
1038 2 * requestedpathlen
;
1039 DEBUG(10,("reply_size: %u\n",reply_size
));
1041 /* add up the unicode lengths of all the referral paths */
1042 for(i
=0;i
<junction
->referral_count
;i
++) {
1043 DEBUG(10,("referral %u : %s\n",
1045 junction
->referral_list
[i
].alternate_path
));
1047 (strlen(junction
->referral_list
[i
].alternate_path
)+1)*2;
1050 DEBUG(10,("reply_size = %u\n",reply_size
));
1051 /* add the unexplained 0x16 bytes */
1054 pdata
= (char *)SMB_REALLOC(pdata
,reply_size
);
1056 DEBUG(0,("Realloc failed!\n"));
1061 /* copy in the dfs requested paths.. required for offset calculations */
1062 memcpy(pdata
+uni_reqpathoffset1
,uni_requestedpath
,requestedpathlen
);
1063 memcpy(pdata
+uni_reqpathoffset2
,uni_requestedpath
,requestedpathlen
);
1065 /* create the header */
1066 SSVAL(pdata
,0,requestedpathlen
- 2); /* UCS2 of path consumed minus
1068 /* number of referral in this pkt */
1069 SSVAL(pdata
,2,junction
->referral_count
);
1071 SIVAL(pdata
,4,DFSREF_REFERRAL_SERVER
| DFSREF_STORAGE_SERVER
);
1073 SIVAL(pdata
,4,DFSREF_STORAGE_SERVER
);
1077 /* add the referral elements */
1078 for(i
=0;i
<junction
->referral_count
;i
++) {
1079 struct referral
* ref
= &junction
->referral_list
[i
];
1082 SSVAL(pdata
,offset
,2); /* version 2 */
1083 SSVAL(pdata
,offset
+2,VERSION2_REFERRAL_SIZE
);
1085 SSVAL(pdata
,offset
+4,1);
1087 SSVAL(pdata
,offset
+4,0);
1090 /* ref_flags :use path_consumed bytes? */
1091 SSVAL(pdata
,offset
+6,0);
1092 SIVAL(pdata
,offset
+8,ref
->proximity
);
1093 SIVAL(pdata
,offset
+12,ref
->ttl
);
1095 SSVAL(pdata
,offset
+16,uni_reqpathoffset1
-offset
);
1096 SSVAL(pdata
,offset
+18,uni_reqpathoffset2
-offset
);
1097 /* copy referred path into current offset */
1098 unilen
= rpcstr_push(pdata
+uni_curroffset
,
1099 ref
->alternate_path
,
1100 reply_size
- uni_curroffset
,
1103 SSVAL(pdata
,offset
+20,uni_curroffset
-offset
);
1105 uni_curroffset
+= unilen
;
1106 offset
+= VERSION2_REFERRAL_SIZE
;
1108 /* add in the unexplained 22 (0x16) bytes at the end */
1109 memset(pdata
+uni_curroffset
,'\0',0x16);
1113 static int setup_ver3_dfs_referral(const char *pathname
,
1115 struct junction_map
*junction
,
1118 char *pdata
= *ppdata
;
1120 smb_ucs2_t
*uni_reqpath
= NULL
;
1121 int uni_reqpathoffset1
, uni_reqpathoffset2
;
1128 DEBUG(10,("setting up version3 referral\n"));
1130 reqpathlen
= rpcstr_push_talloc(talloc_tos(), &uni_reqpath
, pathname
);
1131 if (uni_reqpath
== NULL
|| reqpathlen
== 0) {
1136 dump_data(0, (unsigned char *)uni_reqpath
,
1140 uni_reqpathoffset1
= REFERRAL_HEADER_SIZE
+
1141 VERSION3_REFERRAL_SIZE
* junction
->referral_count
;
1142 uni_reqpathoffset2
= uni_reqpathoffset1
+ reqpathlen
;
1143 reply_size
= uni_curroffset
= uni_reqpathoffset2
+ reqpathlen
;
1145 for(i
=0;i
<junction
->referral_count
;i
++) {
1146 DEBUG(10,("referral %u : %s\n",
1148 junction
->referral_list
[i
].alternate_path
));
1150 (strlen(junction
->referral_list
[i
].alternate_path
)+1)*2;
1153 pdata
= (char *)SMB_REALLOC(pdata
,reply_size
);
1155 DEBUG(0,("version3 referral setup:"
1156 "malloc failed for Realloc!\n"));
1161 /* create the header */
1162 SSVAL(pdata
,0,reqpathlen
- 2); /* UCS2 of path consumed minus
1164 SSVAL(pdata
,2,junction
->referral_count
); /* number of referral */
1166 SIVAL(pdata
,4,DFSREF_REFERRAL_SERVER
| DFSREF_STORAGE_SERVER
);
1168 SIVAL(pdata
,4,DFSREF_STORAGE_SERVER
);
1171 /* copy in the reqpaths */
1172 memcpy(pdata
+uni_reqpathoffset1
,uni_reqpath
,reqpathlen
);
1173 memcpy(pdata
+uni_reqpathoffset2
,uni_reqpath
,reqpathlen
);
1176 for(i
=0;i
<junction
->referral_count
;i
++) {
1177 struct referral
* ref
= &(junction
->referral_list
[i
]);
1180 SSVAL(pdata
,offset
,3); /* version 3 */
1181 SSVAL(pdata
,offset
+2,VERSION3_REFERRAL_SIZE
);
1183 SSVAL(pdata
,offset
+4,1);
1185 SSVAL(pdata
,offset
+4,0);
1188 /* ref_flags :use path_consumed bytes? */
1189 SSVAL(pdata
,offset
+6,0);
1190 SIVAL(pdata
,offset
+8,ref
->ttl
);
1192 SSVAL(pdata
,offset
+12,uni_reqpathoffset1
-offset
);
1193 SSVAL(pdata
,offset
+14,uni_reqpathoffset2
-offset
);
1194 /* copy referred path into current offset */
1195 unilen
= rpcstr_push(pdata
+uni_curroffset
,ref
->alternate_path
,
1196 reply_size
- uni_curroffset
,
1197 STR_UNICODE
| STR_TERMINATE
);
1198 SSVAL(pdata
,offset
+16,uni_curroffset
-offset
);
1199 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
1200 memset(pdata
+offset
+18,'\0',16);
1202 uni_curroffset
+= unilen
;
1203 offset
+= VERSION3_REFERRAL_SIZE
;
1208 /******************************************************************
1209 Set up the DFS referral for the dfs pathname. This call returns
1210 the amount of the path covered by this server, and where the
1211 client should be redirected to. This is the meat of the
1212 TRANS2_GET_DFS_REFERRAL call.
1213 ******************************************************************/
1215 int setup_dfs_referral(connection_struct
*orig_conn
,
1216 const char *dfs_path
,
1217 int max_referral_level
,
1218 char **ppdata
, NTSTATUS
*pstatus
)
1220 struct junction_map
*junction
= NULL
;
1221 int consumedcnt
= 0;
1222 bool self_referral
= False
;
1224 char *pathnamep
= NULL
;
1225 char *local_dfs_path
= NULL
;
1228 if (!(ctx
=talloc_init("setup_dfs_referral"))) {
1229 *pstatus
= NT_STATUS_NO_MEMORY
;
1233 /* get the junction entry */
1235 talloc_destroy(ctx
);
1236 *pstatus
= NT_STATUS_NOT_FOUND
;
1241 * Trim pathname sent by client so it begins with only one backslash.
1242 * Two backslashes confuse some dfs clients
1245 local_dfs_path
= talloc_strdup(ctx
,dfs_path
);
1246 if (!local_dfs_path
) {
1247 *pstatus
= NT_STATUS_NO_MEMORY
;
1248 talloc_destroy(ctx
);
1251 pathnamep
= local_dfs_path
;
1252 while (IS_DIRECTORY_SEP(pathnamep
[0]) &&
1253 IS_DIRECTORY_SEP(pathnamep
[1])) {
1257 junction
= TALLOC_ZERO_P(ctx
, struct junction_map
);
1259 *pstatus
= NT_STATUS_NO_MEMORY
;
1260 talloc_destroy(ctx
);
1264 /* The following call can change cwd. */
1265 *pstatus
= get_referred_path(ctx
, pathnamep
, junction
,
1266 &consumedcnt
, &self_referral
);
1267 if (!NT_STATUS_IS_OK(*pstatus
)) {
1268 vfs_ChDir(orig_conn
,orig_conn
->connectpath
);
1269 talloc_destroy(ctx
);
1272 vfs_ChDir(orig_conn
,orig_conn
->connectpath
);
1274 if (!self_referral
) {
1275 pathnamep
[consumedcnt
] = '\0';
1277 if( DEBUGLVL( 3 ) ) {
1279 dbgtext("setup_dfs_referral: Path %s to "
1280 "alternate path(s):",
1282 for(i
=0;i
<junction
->referral_count
;i
++)
1284 junction
->referral_list
[i
].alternate_path
);
1289 /* create the referral depeding on version */
1290 DEBUG(10,("max_referral_level :%d\n",max_referral_level
));
1292 if (max_referral_level
< 2) {
1293 max_referral_level
= 2;
1295 if (max_referral_level
> 3) {
1296 max_referral_level
= 3;
1299 switch(max_referral_level
) {
1301 reply_size
= setup_ver2_dfs_referral(pathnamep
,
1306 reply_size
= setup_ver3_dfs_referral(pathnamep
, ppdata
,
1307 junction
, self_referral
);
1310 DEBUG(0,("setup_dfs_referral: Invalid dfs referral "
1312 max_referral_level
));
1313 talloc_destroy(ctx
);
1314 *pstatus
= NT_STATUS_INVALID_LEVEL
;
1319 DEBUGADD(0,("DFS Referral pdata:\n"));
1320 dump_data(0,(uint8
*)*ppdata
,reply_size
);
1323 talloc_destroy(ctx
);
1324 *pstatus
= NT_STATUS_OK
;
1328 /**********************************************************************
1329 The following functions are called by the NETDFS RPC pipe functions
1330 **********************************************************************/
1332 /*********************************************************************
1333 Creates a junction structure from a DFS pathname
1334 **********************************************************************/
1336 bool create_junction(TALLOC_CTX
*ctx
,
1337 const char *dfs_path
,
1338 struct junction_map
*jucn
)
1342 struct dfs_path
*pdp
= TALLOC_P(ctx
,struct dfs_path
);
1348 status
= parse_dfs_path(NULL
, dfs_path
, False
, pdp
, &dummy
);
1349 if (!NT_STATUS_IS_OK(status
)) {
1353 /* check if path is dfs : validate first token */
1354 if (!is_myname_or_ipaddr(pdp
->hostname
)) {
1355 DEBUG(4,("create_junction: Invalid hostname %s "
1357 pdp
->hostname
, dfs_path
));
1362 /* Check for a non-DFS share */
1363 snum
= lp_servicenumber(pdp
->servicename
);
1365 if(snum
< 0 || !lp_msdfs_root(snum
)) {
1366 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1372 jucn
->service_name
= talloc_strdup(ctx
, pdp
->servicename
);
1373 jucn
->volume_name
= talloc_strdup(ctx
, pdp
->reqpath
);
1374 jucn
->comment
= talloc_strdup(ctx
, lp_comment(snum
));
1377 if (!jucn
->service_name
|| !jucn
->volume_name
|| ! jucn
->comment
) {
1383 /**********************************************************************
1384 Forms a valid Unix pathname from the junction
1385 **********************************************************************/
1387 static bool junction_to_local_path(const struct junction_map
*jucn
,
1389 connection_struct
**conn_out
,
1395 snum
= lp_servicenumber(jucn
->service_name
);
1399 status
= create_conn_struct(talloc_tos(), conn_out
, snum
,
1400 lp_pathname(snum
), NULL
, oldpath
);
1401 if (!NT_STATUS_IS_OK(status
)) {
1405 *pp_path_out
= talloc_asprintf(*conn_out
,
1409 if (!*pp_path_out
) {
1410 vfs_ChDir(*conn_out
, *oldpath
);
1411 SMB_VFS_DISCONNECT(*conn_out
);
1412 conn_free(*conn_out
);
1418 bool create_msdfs_link(const struct junction_map
*jucn
)
1422 char *msdfs_link
= NULL
;
1423 connection_struct
*conn
;
1425 bool insert_comma
= False
;
1428 if(!junction_to_local_path(jucn
, &path
, &conn
, &cwd
)) {
1432 /* Form the msdfs_link contents */
1433 msdfs_link
= talloc_strdup(conn
, "msdfs:");
1437 for(i
=0; i
<jucn
->referral_count
; i
++) {
1438 char *refpath
= jucn
->referral_list
[i
].alternate_path
;
1440 /* Alternate paths always use Windows separators. */
1441 trim_char(refpath
, '\\', '\\');
1442 if(*refpath
== '\0') {
1444 insert_comma
= False
;
1448 if (i
> 0 && insert_comma
) {
1449 msdfs_link
= talloc_asprintf_append_buffer(msdfs_link
,
1453 msdfs_link
= talloc_asprintf_append_buffer(msdfs_link
,
1461 if (!insert_comma
) {
1462 insert_comma
= True
;
1466 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1469 if(SMB_VFS_SYMLINK(conn
, msdfs_link
, path
) < 0) {
1470 if (errno
== EEXIST
) {
1471 struct smb_filename
*smb_fname
= NULL
;
1474 status
= create_synthetic_smb_fname(talloc_tos(), path
,
1477 if (!NT_STATUS_IS_OK(status
)) {
1478 errno
= map_errno_from_nt_status(status
);
1482 if(SMB_VFS_UNLINK(conn
, smb_fname
)!=0) {
1483 TALLOC_FREE(smb_fname
);
1486 TALLOC_FREE(smb_fname
);
1488 if (SMB_VFS_SYMLINK(conn
, msdfs_link
, path
) < 0) {
1489 DEBUG(1,("create_msdfs_link: symlink failed "
1490 "%s -> %s\nError: %s\n",
1491 path
, msdfs_link
, strerror(errno
)));
1499 vfs_ChDir(conn
, cwd
);
1500 SMB_VFS_DISCONNECT(conn
);
1505 bool remove_msdfs_link(const struct junction_map
*jucn
)
1509 connection_struct
*conn
;
1511 struct smb_filename
*smb_fname
= NULL
;
1514 if (!junction_to_local_path(jucn
, &path
, &conn
, &cwd
)) {
1518 status
= create_synthetic_smb_fname(talloc_tos(), path
,
1521 if (!NT_STATUS_IS_OK(status
)) {
1522 errno
= map_errno_from_nt_status(status
);
1526 if( SMB_VFS_UNLINK(conn
, smb_fname
) == 0 ) {
1530 TALLOC_FREE(smb_fname
);
1531 vfs_ChDir(conn
, cwd
);
1532 SMB_VFS_DISCONNECT(conn
);
1537 /*********************************************************************
1538 Return the number of DFS links at the root of this share.
1539 *********************************************************************/
1541 static int count_dfs_links(TALLOC_CTX
*ctx
, int snum
)
1544 SMB_STRUCT_DIR
*dirp
= NULL
;
1545 const char *dname
= NULL
;
1546 char *talloced
= NULL
;
1547 const char *connect_path
= lp_pathname(snum
);
1548 const char *msdfs_proxy
= lp_msdfs_proxy(snum
);
1549 connection_struct
*conn
;
1553 if(*connect_path
== '\0') {
1558 * Fake up a connection struct for the VFS layer.
1561 status
= create_conn_struct(talloc_tos(), &conn
, snum
, connect_path
,
1563 if (!NT_STATUS_IS_OK(status
)) {
1564 DEBUG(3, ("create_conn_struct failed: %s\n",
1565 nt_errstr(status
)));
1569 /* Count a link for the msdfs root - convention */
1572 /* No more links if this is an msdfs proxy. */
1573 if (*msdfs_proxy
!= '\0') {
1577 /* Now enumerate all dfs links */
1578 dirp
= SMB_VFS_OPENDIR(conn
, ".", NULL
, 0);
1583 while ((dname
= vfs_readdirname(conn
, dirp
, NULL
, &talloced
))
1585 if (is_msdfs_link(conn
,
1590 TALLOC_FREE(talloced
);
1593 SMB_VFS_CLOSEDIR(conn
,dirp
);
1596 vfs_ChDir(conn
, cwd
);
1597 SMB_VFS_DISCONNECT(conn
);
1602 /*********************************************************************
1603 *********************************************************************/
1605 static int form_junctions(TALLOC_CTX
*ctx
,
1607 struct junction_map
*jucn
,
1611 SMB_STRUCT_DIR
*dirp
= NULL
;
1612 const char *dname
= NULL
;
1613 char *talloced
= NULL
;
1614 const char *connect_path
= lp_pathname(snum
);
1615 char *service_name
= lp_servicename(snum
);
1616 const char *msdfs_proxy
= lp_msdfs_proxy(snum
);
1617 connection_struct
*conn
;
1618 struct referral
*ref
= NULL
;
1622 if (jn_remain
== 0) {
1626 if(*connect_path
== '\0') {
1631 * Fake up a connection struct for the VFS layer.
1634 status
= create_conn_struct(ctx
, &conn
, snum
, connect_path
, NULL
,
1636 if (!NT_STATUS_IS_OK(status
)) {
1637 DEBUG(3, ("create_conn_struct failed: %s\n",
1638 nt_errstr(status
)));
1642 /* form a junction for the msdfs root - convention
1643 DO NOT REMOVE THIS: NT clients will not work with us
1644 if this is not present
1646 jucn
[cnt
].service_name
= talloc_strdup(ctx
,service_name
);
1647 jucn
[cnt
].volume_name
= talloc_strdup(ctx
, "");
1648 if (!jucn
[cnt
].service_name
|| !jucn
[cnt
].volume_name
) {
1651 jucn
[cnt
].comment
= "";
1652 jucn
[cnt
].referral_count
= 1;
1654 ref
= jucn
[cnt
].referral_list
= TALLOC_ZERO_P(ctx
, struct referral
);
1655 if (jucn
[cnt
].referral_list
== NULL
) {
1660 ref
->ttl
= REFERRAL_TTL
;
1661 if (*msdfs_proxy
!= '\0') {
1662 ref
->alternate_path
= talloc_strdup(ctx
,
1665 ref
->alternate_path
= talloc_asprintf(ctx
,
1667 get_local_machine_name(),
1671 if (!ref
->alternate_path
) {
1676 /* Don't enumerate if we're an msdfs proxy. */
1677 if (*msdfs_proxy
!= '\0') {
1681 /* Now enumerate all dfs links */
1682 dirp
= SMB_VFS_OPENDIR(conn
, ".", NULL
, 0);
1687 while ((dname
= vfs_readdirname(conn
, dirp
, NULL
, &talloced
))
1689 char *link_target
= NULL
;
1690 if (cnt
>= jn_remain
) {
1691 DEBUG(2, ("form_junctions: ran out of MSDFS "
1693 TALLOC_FREE(talloced
);
1696 if (is_msdfs_link_internal(ctx
,
1698 dname
, &link_target
,
1700 if (parse_msdfs_symlink(ctx
,
1702 &jucn
[cnt
].referral_list
,
1703 &jucn
[cnt
].referral_count
)) {
1705 jucn
[cnt
].service_name
= talloc_strdup(ctx
,
1707 jucn
[cnt
].volume_name
= talloc_strdup(ctx
,
1709 if (!jucn
[cnt
].service_name
||
1710 !jucn
[cnt
].volume_name
) {
1711 TALLOC_FREE(talloced
);
1714 jucn
[cnt
].comment
= "";
1717 TALLOC_FREE(link_target
);
1719 TALLOC_FREE(talloced
);
1725 SMB_VFS_CLOSEDIR(conn
,dirp
);
1728 vfs_ChDir(conn
, cwd
);
1733 struct junction_map
*enum_msdfs_links(TALLOC_CTX
*ctx
, size_t *p_num_jn
)
1735 struct junction_map
*jn
= NULL
;
1737 size_t jn_count
= 0;
1741 if(!lp_host_msdfs()) {
1745 /* Ensure all the usershares are loaded. */
1747 load_registry_shares();
1748 sharecount
= load_usershare_shares();
1751 for(i
=0;i
< sharecount
;i
++) {
1752 if(lp_msdfs_root(i
)) {
1753 jn_count
+= count_dfs_links(ctx
, i
);
1756 if (jn_count
== 0) {
1759 jn
= TALLOC_ARRAY(ctx
, struct junction_map
, jn_count
);
1763 for(i
=0; i
< sharecount
; i
++) {
1764 if (*p_num_jn
>= jn_count
) {
1767 if(lp_msdfs_root(i
)) {
1768 *p_num_jn
+= form_junctions(ctx
, i
,
1770 jn_count
- *p_num_jn
);
1776 /******************************************************************************
1777 Core function to resolve a dfs pathname possibly containing a wildcard. If
1778 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1779 detected during dfs resolution.
1780 ******************************************************************************/
1782 NTSTATUS
resolve_dfspath_wcard(TALLOC_CTX
*ctx
,
1783 connection_struct
*conn
,
1785 const char *name_in
,
1788 bool *ppath_contains_wcard
)
1790 bool path_contains_wcard
;
1791 NTSTATUS status
= NT_STATUS_OK
;
1793 if (dfs_pathnames
) {
1794 status
= dfs_redirect(ctx
,
1799 &path_contains_wcard
);
1801 if (NT_STATUS_IS_OK(status
) && ppath_contains_wcard
!= NULL
) {
1802 *ppath_contains_wcard
= path_contains_wcard
;
1806 * Cheat and just return a copy of the in ptr.
1807 * Once srvstr_get_path() uses talloc it'll
1808 * be a talloced ptr anyway.
1810 *pp_name_out
= CONST_DISCARD(char *,name_in
);