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"
31 /**********************************************************************
32 Parse a DFS pathname of the form \hostname\service\reqpath
33 into the dfs_path structure.
34 If POSIX pathnames is true, the pathname may also be of the
35 form /hostname/service/reqpath.
36 We cope with either here.
38 Unfortunately, due to broken clients who might set the
39 SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
40 send a local path, we have to cope with that too....
42 If conn != NULL then ensure the provided service is
43 the one pointed to by the connection.
45 This version does everything using pointers within one copy of the
46 pathname string, talloced on the struct dfs_path pointer (which
47 must be talloced). This may be too clever to live....
49 **********************************************************************/
51 static NTSTATUS
parse_dfs_path(connection_struct
*conn
,
54 struct dfs_path
*pdp
, /* MUST BE TALLOCED */
55 bool *ppath_contains_wcard
)
57 struct smbd_server_connection
*sconn
= smbd_server_conn
;
62 NTSTATUS status
= NT_STATUS_OK
;
68 * This is the only talloc we should need to do
69 * on the struct dfs_path. All the pointers inside
70 * it should point to offsets within this string.
73 pathname_local
= talloc_strdup(pdp
, pathname
);
74 if (!pathname_local
) {
75 return NT_STATUS_NO_MEMORY
;
77 /* Get a pointer to the terminating '\0' */
78 eos_ptr
= &pathname_local
[strlen(pathname_local
)];
79 p
= temp
= pathname_local
;
81 pdp
->posix_path
= (lp_posix_pathnames() && *pathname
== '/');
83 sepchar
= pdp
->posix_path
? '/' : '\\';
85 if (!sconn
->using_smb2
&& (*pathname
!= sepchar
)) {
86 DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
89 * Possibly client sent a local path by mistake.
90 * Try and convert to a local path.
93 pdp
->hostname
= eos_ptr
; /* "" */
94 pdp
->servicename
= eos_ptr
; /* "" */
96 /* We've got no info about separators. */
97 pdp
->posix_path
= lp_posix_pathnames();
99 DEBUG(10,("parse_dfs_path: trying to convert %s to a "
106 * Safe to use on talloc'ed string as it only shrinks.
107 * It also doesn't affect the eos_ptr.
109 trim_char(temp
,sepchar
,sepchar
);
111 DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
115 /* Parse out hostname. */
116 p
= strchr_m(temp
,sepchar
);
118 DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
121 * Possibly client sent a local path by mistake.
122 * Try and convert to a local path.
125 pdp
->hostname
= eos_ptr
; /* "" */
126 pdp
->servicename
= eos_ptr
; /* "" */
129 DEBUG(10,("parse_dfs_path: trying to convert %s "
135 pdp
->hostname
= temp
;
137 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp
->hostname
));
139 /* Parse out servicename. */
141 p
= strchr_m(servicename
,sepchar
);
146 /* Is this really our servicename ? */
147 if (conn
&& !( strequal(servicename
, lp_servicename(SNUM(conn
)))
148 || (strequal(servicename
, HOMES_NAME
)
149 && strequal(lp_servicename(SNUM(conn
)),
150 get_current_username()) )) ) {
151 DEBUG(10,("parse_dfs_path: %s is not our servicename\n",
155 * Possibly client sent a local path by mistake.
156 * Try and convert to a local path.
159 pdp
->hostname
= eos_ptr
; /* "" */
160 pdp
->servicename
= eos_ptr
; /* "" */
162 /* Repair the path - replace the sepchar's
165 *servicename
= sepchar
;
171 DEBUG(10,("parse_dfs_path: trying to convert %s "
177 pdp
->servicename
= servicename
;
179 DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp
->servicename
));
182 /* Client sent self referral \server\share. */
183 pdp
->reqpath
= eos_ptr
; /* "" */
191 *ppath_contains_wcard
= False
;
195 /* Rest is reqpath. */
196 if (pdp
->posix_path
) {
197 status
= check_path_syntax_posix(pdp
->reqpath
);
200 status
= check_path_syntax_wcard(pdp
->reqpath
,
201 ppath_contains_wcard
);
203 status
= check_path_syntax(pdp
->reqpath
);
207 if (!NT_STATUS_IS_OK(status
)) {
208 DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
209 p
, nt_errstr(status
) ));
213 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp
->reqpath
));
217 /********************************************************
218 Fake up a connection struct for the VFS layer.
219 Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
220 *********************************************************/
222 NTSTATUS
create_conn_struct(TALLOC_CTX
*ctx
,
223 connection_struct
**pconn
,
226 const struct auth_serversupplied_info
*session_info
,
229 connection_struct
*conn
;
232 const char *vfs_user
;
234 conn
= TALLOC_ZERO_P(ctx
, connection_struct
);
236 return NT_STATUS_NO_MEMORY
;
239 connpath
= talloc_strdup(conn
, path
);
242 return NT_STATUS_NO_MEMORY
;
244 connpath
= talloc_string_sub(conn
,
247 lp_servicename(snum
));
250 return NT_STATUS_NO_MEMORY
;
253 /* needed for smbd_vfs_init() */
255 if (!(conn
->params
= TALLOC_ZERO_P(conn
, struct share_params
))) {
256 DEBUG(0, ("TALLOC failed\n"));
258 return NT_STATUS_NO_MEMORY
;
261 conn
->params
->service
= snum
;
263 conn
->sconn
= smbd_server_conn
;
264 conn
->sconn
->num_tcons_open
++;
266 if (session_info
!= NULL
) {
267 conn
->session_info
= copy_serverinfo(conn
, session_info
);
268 if (conn
->session_info
== NULL
) {
269 DEBUG(0, ("copy_serverinfo failed\n"));
271 return NT_STATUS_NO_MEMORY
;
273 vfs_user
= conn
->session_info
->unix_name
;
275 /* use current authenticated user in absence of session_info */
276 vfs_user
= get_current_username();
279 set_conn_connectpath(conn
, connpath
);
281 if (!smbd_vfs_init(conn
)) {
282 NTSTATUS status
= map_nt_error_from_unix(errno
);
283 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
288 /* this must be the first filesystem operation that we do */
289 if (SMB_VFS_CONNECT(conn
, lp_servicename(snum
), vfs_user
) < 0) {
290 DEBUG(0,("VFS connect failed!\n"));
292 return NT_STATUS_UNSUCCESSFUL
;
295 conn
->fs_capabilities
= SMB_VFS_FS_CAPABILITIES(conn
, &conn
->ts_res
);
298 * Windows seems to insist on doing trans2getdfsreferral() calls on
299 * the IPC$ share as the anonymous user. If we try to chdir as that
300 * user we will fail.... WTF ? JRA.
303 oldcwd
= vfs_GetWd(ctx
, conn
);
304 if (oldcwd
== NULL
) {
305 NTSTATUS status
= map_nt_error_from_unix(errno
);
306 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno
)));
311 if (vfs_ChDir(conn
,conn
->connectpath
) != 0) {
312 NTSTATUS status
= map_nt_error_from_unix(errno
);
313 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
315 conn
->connectpath
, strerror(errno
) ));
326 /**********************************************************************
327 Parse the contents of a symlink to verify if it is an msdfs referral
328 A valid referral is of the form:
330 msdfs:server1\share1,server2\share2
331 msdfs:server1\share1\pathname,server2\share2\pathname
332 msdfs:server1/share1,server2/share2
333 msdfs:server1/share1/pathname,server2/share2/pathname.
335 Note that the alternate paths returned here must be of the canonicalized
339 \server\share\path\to\file,
341 even in posix path mode. This is because we have no knowledge if the
342 server we're referring to understands posix paths.
343 **********************************************************************/
345 static bool parse_msdfs_symlink(TALLOC_CTX
*ctx
,
347 struct referral
**preflist
,
352 char **alt_path
= NULL
;
354 struct referral
*reflist
;
357 temp
= talloc_strdup(ctx
, target
);
361 prot
= strtok_r(temp
, ":", &saveptr
);
363 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
367 alt_path
= TALLOC_ARRAY(ctx
, char *, MAX_REFERRAL_COUNT
);
372 /* parse out the alternate paths */
373 while((count
<MAX_REFERRAL_COUNT
) &&
374 ((alt_path
[count
] = strtok_r(NULL
, ",", &saveptr
)) != NULL
)) {
378 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count
));
381 reflist
= *preflist
= TALLOC_ZERO_ARRAY(ctx
,
382 struct referral
, count
);
383 if(reflist
== NULL
) {
384 TALLOC_FREE(alt_path
);
388 reflist
= *preflist
= NULL
;
391 for(i
=0;i
<count
;i
++) {
394 /* Canonicalize link target.
395 * Replace all /'s in the path by a \ */
396 string_replace(alt_path
[i
], '/', '\\');
398 /* Remove leading '\\'s */
400 while (*p
&& (*p
== '\\')) {
404 reflist
[i
].alternate_path
= talloc_asprintf(ctx
,
407 if (!reflist
[i
].alternate_path
) {
411 reflist
[i
].proximity
= 0;
412 reflist
[i
].ttl
= REFERRAL_TTL
;
413 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
414 reflist
[i
].alternate_path
));
419 TALLOC_FREE(alt_path
);
423 /**********************************************************************
424 Returns true if the unix path is a valid msdfs symlink and also
425 returns the target string from inside the link.
426 **********************************************************************/
428 static bool is_msdfs_link_internal(TALLOC_CTX
*ctx
,
429 connection_struct
*conn
,
431 char **pp_link_target
,
432 SMB_STRUCT_STAT
*sbufp
)
434 int referral_len
= 0;
435 #if defined(HAVE_BROKEN_READLINK)
436 char link_target_buf
[PATH_MAX
];
438 char link_target_buf
[7];
441 char *link_target
= NULL
;
442 struct smb_filename smb_fname
;
444 if (pp_link_target
) {
446 link_target
= TALLOC_ARRAY(ctx
, char, bufsize
);
450 *pp_link_target
= link_target
;
452 bufsize
= sizeof(link_target_buf
);
453 link_target
= link_target_buf
;
456 ZERO_STRUCT(smb_fname
);
457 smb_fname
.base_name
= discard_const_p(char, path
);
459 if (SMB_VFS_LSTAT(conn
, &smb_fname
) != 0) {
460 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
464 if (!S_ISLNK(smb_fname
.st
.st_ex_mode
)) {
465 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
470 *sbufp
= smb_fname
.st
;
473 referral_len
= SMB_VFS_READLINK(conn
, path
, link_target
, bufsize
- 1);
474 if (referral_len
== -1) {
475 DEBUG(0,("is_msdfs_link_read_target: Error reading "
476 "msdfs link %s: %s\n",
477 path
, strerror(errno
)));
480 link_target
[referral_len
] = '\0';
482 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path
,
485 if (!strnequal(link_target
, "msdfs:", 6)) {
492 if (link_target
!= link_target_buf
) {
493 TALLOC_FREE(link_target
);
498 /**********************************************************************
499 Returns true if the unix path is a valid msdfs symlink.
500 **********************************************************************/
502 bool is_msdfs_link(connection_struct
*conn
,
504 SMB_STRUCT_STAT
*sbufp
)
506 return is_msdfs_link_internal(talloc_tos(),
513 /*****************************************************************
514 Used by other functions to decide if a dfs path is remote,
515 and to get the list of referred locations for that remote path.
517 search_flag: For findfirsts, dfs links themselves are not
518 redirected, but paths beyond the links are. For normal smb calls,
519 even dfs links need to be redirected.
521 consumedcntp: how much of the dfs path is being redirected. the client
522 should try the remaining path on the redirected server.
524 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
525 link redirect are in targetpath.
526 *****************************************************************/
528 static NTSTATUS
dfs_path_lookup(TALLOC_CTX
*ctx
,
529 connection_struct
*conn
,
530 const char *dfspath
, /* Incoming complete dfs path */
531 const struct dfs_path
*pdp
, /* Parsed out
532 server+share+extrapath. */
533 bool search_flag
, /* Called from a findfirst ? */
535 char **pp_targetpath
)
540 struct smb_filename
*smb_fname
= NULL
;
541 char *canon_dfspath
= NULL
; /* Canonicalized dfs path. (only '/'
544 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
545 conn
->connectpath
, pdp
->reqpath
));
548 * Note the unix path conversion here we're doing we can
549 * throw away. We're looking for a symlink for a dfs
550 * resolution, if we don't find it we'll do another
551 * unix_convert later in the codepath.
552 * If we needed to remember what we'd resolved in
553 * dp->reqpath (as the original code did) we'd
554 * copy (localhost, dp->reqpath) on any code
555 * path below that returns True - but I don't
556 * think this is needed. JRA.
559 status
= unix_convert(ctx
, conn
, pdp
->reqpath
, &smb_fname
,
560 search_flag
? UCF_ALWAYS_ALLOW_WCARD_LCOMP
: 0);
562 if (!NT_STATUS_IS_OK(status
)) {
563 if (!NT_STATUS_EQUAL(status
,
564 NT_STATUS_OBJECT_PATH_NOT_FOUND
)) {
568 /* Create an smb_fname to use below. */
569 status
= create_synthetic_smb_fname(ctx
, pdp
->reqpath
, NULL
,
571 if (!NT_STATUS_IS_OK(status
)) {
576 /* Optimization - check if we can redirect the whole path. */
578 if (is_msdfs_link_internal(ctx
, conn
, smb_fname
->base_name
,
579 pp_targetpath
, NULL
)) {
581 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
582 "for dfs link %s.\n", dfspath
));
583 status
= NT_STATUS_OK
;
587 DEBUG(6,("dfs_path_lookup: %s resolves to a "
588 "valid dfs link %s.\n", dfspath
,
589 pp_targetpath
? *pp_targetpath
: ""));
592 *consumedcntp
= strlen(dfspath
);
594 status
= NT_STATUS_PATH_NOT_COVERED
;
598 /* Prepare to test only for '/' components in the given path,
599 * so if a Windows path replace all '\\' characters with '/'.
600 * For a POSIX DFS path we know all separators are already '/'. */
602 canon_dfspath
= talloc_strdup(ctx
, dfspath
);
603 if (!canon_dfspath
) {
604 status
= NT_STATUS_NO_MEMORY
;
607 if (!pdp
->posix_path
) {
608 string_replace(canon_dfspath
, '\\', '/');
612 * localpath comes out of unix_convert, so it has
613 * no trailing backslash. Make sure that canon_dfspath hasn't either.
614 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
617 trim_char(canon_dfspath
,0,'/');
620 * Redirect if any component in the path is a link.
621 * We do this by walking backwards through the
622 * local path, chopping off the last component
623 * in both the local path and the canonicalized
624 * DFS path. If we hit a DFS link then we're done.
627 p
= strrchr_m(smb_fname
->base_name
, '/');
629 q
= strrchr_m(canon_dfspath
, '/');
638 if (is_msdfs_link_internal(ctx
, conn
,
639 smb_fname
->base_name
, pp_targetpath
,
641 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
642 "parent %s is dfs link\n", dfspath
,
643 smb_fname_str_dbg(smb_fname
)));
646 *consumedcntp
= strlen(canon_dfspath
);
647 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
653 status
= NT_STATUS_PATH_NOT_COVERED
;
657 /* Step back on the filesystem. */
658 p
= strrchr_m(smb_fname
->base_name
, '/');
661 /* And in the canonicalized dfs path. */
662 q
= strrchr_m(canon_dfspath
, '/');
666 status
= NT_STATUS_OK
;
668 TALLOC_FREE(smb_fname
);
672 /*****************************************************************
673 Decides if a dfs pathname should be redirected or not.
674 If not, the pathname is converted to a tcon-relative local unix path
676 search_wcard_flag: this flag performs 2 functions both related
677 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
680 This function can return NT_STATUS_OK, meaning use the returned path as-is
681 (mapped into a local path).
682 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
683 any other NT_STATUS error which is a genuine error to be
684 returned to the client.
685 *****************************************************************/
687 static NTSTATUS
dfs_redirect(TALLOC_CTX
*ctx
,
688 connection_struct
*conn
,
690 bool search_wcard_flag
,
692 bool *ppath_contains_wcard
)
695 struct dfs_path
*pdp
= TALLOC_P(ctx
, struct dfs_path
);
698 return NT_STATUS_NO_MEMORY
;
701 status
= parse_dfs_path(conn
, path_in
, search_wcard_flag
, pdp
,
702 ppath_contains_wcard
);
703 if (!NT_STATUS_IS_OK(status
)) {
708 if (pdp
->reqpath
[0] == '\0') {
710 *pp_path_out
= talloc_strdup(ctx
, "");
712 return NT_STATUS_NO_MEMORY
;
714 DEBUG(5,("dfs_redirect: self-referral.\n"));
718 /* If dfs pathname for a non-dfs share, convert to tcon-relative
719 path and return OK */
721 if (!lp_msdfs_root(SNUM(conn
))) {
722 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
725 return NT_STATUS_NO_MEMORY
;
730 /* If it looked like a local path (zero hostname/servicename)
731 * just treat as a tcon-relative path. */
733 if (pdp
->hostname
[0] == '\0' && pdp
->servicename
[0] == '\0') {
734 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
737 return NT_STATUS_NO_MEMORY
;
742 if (!( strequal(pdp
->servicename
, lp_servicename(SNUM(conn
)))
743 || (strequal(pdp
->servicename
, HOMES_NAME
)
744 && strequal(lp_servicename(SNUM(conn
)),
745 conn
->session_info
->sanitized_username
) )) ) {
747 /* The given sharename doesn't match this connection. */
750 return NT_STATUS_OBJECT_PATH_NOT_FOUND
;
753 status
= dfs_path_lookup(ctx
, conn
, path_in
, pdp
,
754 search_wcard_flag
, NULL
, NULL
);
755 if (!NT_STATUS_IS_OK(status
)) {
756 if (NT_STATUS_EQUAL(status
, NT_STATUS_PATH_NOT_COVERED
)) {
757 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in
));
759 DEBUG(10,("dfs_redirect: dfs_path_lookup "
760 "failed for %s with %s\n",
761 path_in
, nt_errstr(status
) ));
766 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in
));
768 /* Form non-dfs tcon-relative path */
769 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
772 return NT_STATUS_NO_MEMORY
;
775 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
782 /**********************************************************************
783 Return a self referral.
784 **********************************************************************/
786 static NTSTATUS
self_ref(TALLOC_CTX
*ctx
,
787 const char *dfs_path
,
788 struct junction_map
*jucn
,
790 bool *self_referralp
)
792 struct referral
*ref
;
794 *self_referralp
= True
;
796 jucn
->referral_count
= 1;
797 if((ref
= TALLOC_ZERO_P(ctx
, struct referral
)) == NULL
) {
798 return NT_STATUS_NO_MEMORY
;
801 ref
->alternate_path
= talloc_strdup(ctx
, dfs_path
);
802 if (!ref
->alternate_path
) {
803 return NT_STATUS_NO_MEMORY
;
806 ref
->ttl
= REFERRAL_TTL
;
807 jucn
->referral_list
= ref
;
808 *consumedcntp
= strlen(dfs_path
);
812 /**********************************************************************
813 Gets valid referrals for a dfs path and fills up the
814 junction_map structure.
815 **********************************************************************/
817 NTSTATUS
get_referred_path(TALLOC_CTX
*ctx
,
818 const char *dfs_path
,
819 struct junction_map
*jucn
,
821 bool *self_referralp
)
823 struct connection_struct
*conn
;
824 char *targetpath
= NULL
;
826 NTSTATUS status
= NT_STATUS_NOT_FOUND
;
828 struct dfs_path
*pdp
= TALLOC_P(ctx
, struct dfs_path
);
832 return NT_STATUS_NO_MEMORY
;
835 *self_referralp
= False
;
837 status
= parse_dfs_path(NULL
, dfs_path
, False
, pdp
, &dummy
);
838 if (!NT_STATUS_IS_OK(status
)) {
842 jucn
->service_name
= talloc_strdup(ctx
, pdp
->servicename
);
843 jucn
->volume_name
= talloc_strdup(ctx
, pdp
->reqpath
);
844 if (!jucn
->service_name
|| !jucn
->volume_name
) {
846 return NT_STATUS_NO_MEMORY
;
849 /* Verify the share is a dfs root */
850 snum
= lp_servicenumber(jucn
->service_name
);
852 char *service_name
= NULL
;
853 if ((snum
= find_service(ctx
, jucn
->service_name
, &service_name
)) < 0) {
854 return NT_STATUS_NOT_FOUND
;
857 return NT_STATUS_NO_MEMORY
;
859 TALLOC_FREE(jucn
->service_name
);
860 jucn
->service_name
= talloc_strdup(ctx
, service_name
);
861 if (!jucn
->service_name
) {
863 return NT_STATUS_NO_MEMORY
;
867 if (!lp_msdfs_root(snum
) && (*lp_msdfs_proxy(snum
) == '\0')) {
868 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
870 pdp
->servicename
, dfs_path
));
872 return NT_STATUS_NOT_FOUND
;
876 * Self referrals are tested with a anonymous IPC connection and
877 * a GET_DFS_REFERRAL call to \\server\share. (which means
878 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
879 * into the directory and will fail if it cannot (as the anonymous
880 * user). Cope with this.
883 if (pdp
->reqpath
[0] == '\0') {
885 struct referral
*ref
;
887 if (*lp_msdfs_proxy(snum
) == '\0') {
897 * It's an msdfs proxy share. Redirect to
898 * the configured target share.
901 jucn
->referral_count
= 1;
902 if ((ref
= TALLOC_ZERO_P(ctx
, struct referral
)) == NULL
) {
904 return NT_STATUS_NO_MEMORY
;
907 if (!(tmp
= talloc_strdup(ctx
, lp_msdfs_proxy(snum
)))) {
909 return NT_STATUS_NO_MEMORY
;
912 trim_string(tmp
, "\\", 0);
914 ref
->alternate_path
= talloc_asprintf(ctx
, "\\%s", tmp
);
917 if (!ref
->alternate_path
) {
919 return NT_STATUS_NO_MEMORY
;
922 if (pdp
->reqpath
[0] != '\0') {
923 ref
->alternate_path
= talloc_asprintf_append(
927 if (!ref
->alternate_path
) {
929 return NT_STATUS_NO_MEMORY
;
933 ref
->ttl
= REFERRAL_TTL
;
934 jucn
->referral_list
= ref
;
935 *consumedcntp
= strlen(dfs_path
);
940 status
= create_conn_struct(ctx
, &conn
, snum
, lp_pathname(snum
),
942 if (!NT_STATUS_IS_OK(status
)) {
947 /* If this is a DFS path dfs_lookup should return
948 * NT_STATUS_PATH_NOT_COVERED. */
950 status
= dfs_path_lookup(ctx
, conn
, dfs_path
, pdp
,
951 False
, consumedcntp
, &targetpath
);
953 if (!NT_STATUS_EQUAL(status
, NT_STATUS_PATH_NOT_COVERED
)) {
954 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
959 /* We know this is a valid dfs link. Parse the targetpath. */
960 if (!parse_msdfs_symlink(ctx
, targetpath
,
961 &jucn
->referral_list
,
962 &jucn
->referral_count
)) {
963 DEBUG(3,("get_referred_path: failed to parse symlink "
964 "target %s\n", targetpath
));
965 status
= NT_STATUS_NOT_FOUND
;
969 status
= NT_STATUS_OK
;
971 vfs_ChDir(conn
, oldpath
);
972 SMB_VFS_DISCONNECT(conn
);
978 static int setup_ver2_dfs_referral(const char *pathname
,
980 struct junction_map
*junction
,
983 char* pdata
= *ppdata
;
985 smb_ucs2_t
*uni_requestedpath
= NULL
;
986 int uni_reqpathoffset1
,uni_reqpathoffset2
;
988 int requestedpathlen
=0;
993 DEBUG(10,("Setting up version2 referral\nRequested path:\n"));
995 requestedpathlen
= rpcstr_push_talloc(talloc_tos(),
996 &uni_requestedpath
, pathname
);
997 if (uni_requestedpath
== NULL
|| requestedpathlen
== 0) {
1002 dump_data(0, (unsigned char *)uni_requestedpath
,
1006 DEBUG(10,("ref count = %u\n",junction
->referral_count
));
1008 uni_reqpathoffset1
= REFERRAL_HEADER_SIZE
+
1009 VERSION2_REFERRAL_SIZE
* junction
->referral_count
;
1011 uni_reqpathoffset2
= uni_reqpathoffset1
+ requestedpathlen
;
1013 uni_curroffset
= uni_reqpathoffset2
+ requestedpathlen
;
1015 reply_size
= REFERRAL_HEADER_SIZE
+
1016 VERSION2_REFERRAL_SIZE
*junction
->referral_count
+
1017 2 * requestedpathlen
;
1018 DEBUG(10,("reply_size: %u\n",reply_size
));
1020 /* add up the unicode lengths of all the referral paths */
1021 for(i
=0;i
<junction
->referral_count
;i
++) {
1022 DEBUG(10,("referral %u : %s\n",
1024 junction
->referral_list
[i
].alternate_path
));
1026 (strlen(junction
->referral_list
[i
].alternate_path
)+1)*2;
1029 DEBUG(10,("reply_size = %u\n",reply_size
));
1030 /* add the unexplained 0x16 bytes */
1033 pdata
= (char *)SMB_REALLOC(pdata
,reply_size
);
1035 DEBUG(0,("Realloc failed!\n"));
1040 /* copy in the dfs requested paths.. required for offset calculations */
1041 memcpy(pdata
+uni_reqpathoffset1
,uni_requestedpath
,requestedpathlen
);
1042 memcpy(pdata
+uni_reqpathoffset2
,uni_requestedpath
,requestedpathlen
);
1044 /* create the header */
1045 SSVAL(pdata
,0,requestedpathlen
- 2); /* UCS2 of path consumed minus
1047 /* number of referral in this pkt */
1048 SSVAL(pdata
,2,junction
->referral_count
);
1050 SIVAL(pdata
,4,DFSREF_REFERRAL_SERVER
| DFSREF_STORAGE_SERVER
);
1052 SIVAL(pdata
,4,DFSREF_STORAGE_SERVER
);
1056 /* add the referral elements */
1057 for(i
=0;i
<junction
->referral_count
;i
++) {
1058 struct referral
* ref
= &junction
->referral_list
[i
];
1061 SSVAL(pdata
,offset
,2); /* version 2 */
1062 SSVAL(pdata
,offset
+2,VERSION2_REFERRAL_SIZE
);
1064 SSVAL(pdata
,offset
+4,1);
1066 SSVAL(pdata
,offset
+4,0);
1069 /* ref_flags :use path_consumed bytes? */
1070 SSVAL(pdata
,offset
+6,0);
1071 SIVAL(pdata
,offset
+8,ref
->proximity
);
1072 SIVAL(pdata
,offset
+12,ref
->ttl
);
1074 SSVAL(pdata
,offset
+16,uni_reqpathoffset1
-offset
);
1075 SSVAL(pdata
,offset
+18,uni_reqpathoffset2
-offset
);
1076 /* copy referred path into current offset */
1077 unilen
= rpcstr_push(pdata
+uni_curroffset
,
1078 ref
->alternate_path
,
1079 reply_size
- uni_curroffset
,
1082 SSVAL(pdata
,offset
+20,uni_curroffset
-offset
);
1084 uni_curroffset
+= unilen
;
1085 offset
+= VERSION2_REFERRAL_SIZE
;
1087 /* add in the unexplained 22 (0x16) bytes at the end */
1088 memset(pdata
+uni_curroffset
,'\0',0x16);
1092 static int setup_ver3_dfs_referral(const char *pathname
,
1094 struct junction_map
*junction
,
1097 char *pdata
= *ppdata
;
1099 smb_ucs2_t
*uni_reqpath
= NULL
;
1100 int uni_reqpathoffset1
, uni_reqpathoffset2
;
1107 DEBUG(10,("setting up version3 referral\n"));
1109 reqpathlen
= rpcstr_push_talloc(talloc_tos(), &uni_reqpath
, pathname
);
1110 if (uni_reqpath
== NULL
|| reqpathlen
== 0) {
1115 dump_data(0, (unsigned char *)uni_reqpath
,
1119 uni_reqpathoffset1
= REFERRAL_HEADER_SIZE
+
1120 VERSION3_REFERRAL_SIZE
* junction
->referral_count
;
1121 uni_reqpathoffset2
= uni_reqpathoffset1
+ reqpathlen
;
1122 reply_size
= uni_curroffset
= uni_reqpathoffset2
+ reqpathlen
;
1124 for(i
=0;i
<junction
->referral_count
;i
++) {
1125 DEBUG(10,("referral %u : %s\n",
1127 junction
->referral_list
[i
].alternate_path
));
1129 (strlen(junction
->referral_list
[i
].alternate_path
)+1)*2;
1132 pdata
= (char *)SMB_REALLOC(pdata
,reply_size
);
1134 DEBUG(0,("version3 referral setup:"
1135 "malloc failed for Realloc!\n"));
1140 /* create the header */
1141 SSVAL(pdata
,0,reqpathlen
- 2); /* UCS2 of path consumed minus
1143 SSVAL(pdata
,2,junction
->referral_count
); /* number of referral */
1145 SIVAL(pdata
,4,DFSREF_REFERRAL_SERVER
| DFSREF_STORAGE_SERVER
);
1147 SIVAL(pdata
,4,DFSREF_STORAGE_SERVER
);
1150 /* copy in the reqpaths */
1151 memcpy(pdata
+uni_reqpathoffset1
,uni_reqpath
,reqpathlen
);
1152 memcpy(pdata
+uni_reqpathoffset2
,uni_reqpath
,reqpathlen
);
1155 for(i
=0;i
<junction
->referral_count
;i
++) {
1156 struct referral
* ref
= &(junction
->referral_list
[i
]);
1159 SSVAL(pdata
,offset
,3); /* version 3 */
1160 SSVAL(pdata
,offset
+2,VERSION3_REFERRAL_SIZE
);
1162 SSVAL(pdata
,offset
+4,1);
1164 SSVAL(pdata
,offset
+4,0);
1167 /* ref_flags :use path_consumed bytes? */
1168 SSVAL(pdata
,offset
+6,0);
1169 SIVAL(pdata
,offset
+8,ref
->ttl
);
1171 SSVAL(pdata
,offset
+12,uni_reqpathoffset1
-offset
);
1172 SSVAL(pdata
,offset
+14,uni_reqpathoffset2
-offset
);
1173 /* copy referred path into current offset */
1174 unilen
= rpcstr_push(pdata
+uni_curroffset
,ref
->alternate_path
,
1175 reply_size
- uni_curroffset
,
1176 STR_UNICODE
| STR_TERMINATE
);
1177 SSVAL(pdata
,offset
+16,uni_curroffset
-offset
);
1178 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
1179 memset(pdata
+offset
+18,'\0',16);
1181 uni_curroffset
+= unilen
;
1182 offset
+= VERSION3_REFERRAL_SIZE
;
1187 /******************************************************************
1188 Set up the DFS referral for the dfs pathname. This call returns
1189 the amount of the path covered by this server, and where the
1190 client should be redirected to. This is the meat of the
1191 TRANS2_GET_DFS_REFERRAL call.
1192 ******************************************************************/
1194 int setup_dfs_referral(connection_struct
*orig_conn
,
1195 const char *dfs_path
,
1196 int max_referral_level
,
1197 char **ppdata
, NTSTATUS
*pstatus
)
1199 struct junction_map
*junction
= NULL
;
1200 int consumedcnt
= 0;
1201 bool self_referral
= False
;
1203 char *pathnamep
= NULL
;
1204 char *local_dfs_path
= NULL
;
1207 if (!(ctx
=talloc_init("setup_dfs_referral"))) {
1208 *pstatus
= NT_STATUS_NO_MEMORY
;
1212 /* get the junction entry */
1214 talloc_destroy(ctx
);
1215 *pstatus
= NT_STATUS_NOT_FOUND
;
1220 * Trim pathname sent by client so it begins with only one backslash.
1221 * Two backslashes confuse some dfs clients
1224 local_dfs_path
= talloc_strdup(ctx
,dfs_path
);
1225 if (!local_dfs_path
) {
1226 *pstatus
= NT_STATUS_NO_MEMORY
;
1227 talloc_destroy(ctx
);
1230 pathnamep
= local_dfs_path
;
1231 while (IS_DIRECTORY_SEP(pathnamep
[0]) &&
1232 IS_DIRECTORY_SEP(pathnamep
[1])) {
1236 junction
= TALLOC_ZERO_P(ctx
, struct junction_map
);
1238 *pstatus
= NT_STATUS_NO_MEMORY
;
1239 talloc_destroy(ctx
);
1243 /* The following call can change cwd. */
1244 *pstatus
= get_referred_path(ctx
, pathnamep
, junction
,
1245 &consumedcnt
, &self_referral
);
1246 if (!NT_STATUS_IS_OK(*pstatus
)) {
1247 vfs_ChDir(orig_conn
,orig_conn
->connectpath
);
1248 talloc_destroy(ctx
);
1251 vfs_ChDir(orig_conn
,orig_conn
->connectpath
);
1253 if (!self_referral
) {
1254 pathnamep
[consumedcnt
] = '\0';
1256 if( DEBUGLVL( 3 ) ) {
1258 dbgtext("setup_dfs_referral: Path %s to "
1259 "alternate path(s):",
1261 for(i
=0;i
<junction
->referral_count
;i
++)
1263 junction
->referral_list
[i
].alternate_path
);
1268 /* create the referral depeding on version */
1269 DEBUG(10,("max_referral_level :%d\n",max_referral_level
));
1271 if (max_referral_level
< 2) {
1272 max_referral_level
= 2;
1274 if (max_referral_level
> 3) {
1275 max_referral_level
= 3;
1278 switch(max_referral_level
) {
1280 reply_size
= setup_ver2_dfs_referral(pathnamep
,
1285 reply_size
= setup_ver3_dfs_referral(pathnamep
, ppdata
,
1286 junction
, self_referral
);
1289 DEBUG(0,("setup_dfs_referral: Invalid dfs referral "
1291 max_referral_level
));
1292 talloc_destroy(ctx
);
1293 *pstatus
= NT_STATUS_INVALID_LEVEL
;
1298 DEBUGADD(0,("DFS Referral pdata:\n"));
1299 dump_data(0,(uint8
*)*ppdata
,reply_size
);
1302 talloc_destroy(ctx
);
1303 *pstatus
= NT_STATUS_OK
;
1307 /**********************************************************************
1308 The following functions are called by the NETDFS RPC pipe functions
1309 **********************************************************************/
1311 /*********************************************************************
1312 Creates a junction structure from a DFS pathname
1313 **********************************************************************/
1315 bool create_junction(TALLOC_CTX
*ctx
,
1316 const char *dfs_path
,
1317 struct junction_map
*jucn
)
1321 struct dfs_path
*pdp
= TALLOC_P(ctx
,struct dfs_path
);
1327 status
= parse_dfs_path(NULL
, dfs_path
, False
, pdp
, &dummy
);
1328 if (!NT_STATUS_IS_OK(status
)) {
1332 /* check if path is dfs : validate first token */
1333 if (!is_myname_or_ipaddr(pdp
->hostname
)) {
1334 DEBUG(4,("create_junction: Invalid hostname %s "
1336 pdp
->hostname
, dfs_path
));
1341 /* Check for a non-DFS share */
1342 snum
= lp_servicenumber(pdp
->servicename
);
1344 if(snum
< 0 || !lp_msdfs_root(snum
)) {
1345 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1351 jucn
->service_name
= talloc_strdup(ctx
, pdp
->servicename
);
1352 jucn
->volume_name
= talloc_strdup(ctx
, pdp
->reqpath
);
1353 jucn
->comment
= talloc_strdup(ctx
, lp_comment(snum
));
1356 if (!jucn
->service_name
|| !jucn
->volume_name
|| ! jucn
->comment
) {
1362 /**********************************************************************
1363 Forms a valid Unix pathname from the junction
1364 **********************************************************************/
1366 static bool junction_to_local_path(const struct junction_map
*jucn
,
1368 connection_struct
**conn_out
,
1374 snum
= lp_servicenumber(jucn
->service_name
);
1378 status
= create_conn_struct(talloc_tos(), conn_out
, snum
,
1379 lp_pathname(snum
), NULL
, oldpath
);
1380 if (!NT_STATUS_IS_OK(status
)) {
1384 *pp_path_out
= talloc_asprintf(*conn_out
,
1388 if (!*pp_path_out
) {
1389 vfs_ChDir(*conn_out
, *oldpath
);
1390 SMB_VFS_DISCONNECT(*conn_out
);
1391 conn_free(*conn_out
);
1397 bool create_msdfs_link(const struct junction_map
*jucn
)
1401 char *msdfs_link
= NULL
;
1402 connection_struct
*conn
;
1404 bool insert_comma
= False
;
1407 if(!junction_to_local_path(jucn
, &path
, &conn
, &cwd
)) {
1411 /* Form the msdfs_link contents */
1412 msdfs_link
= talloc_strdup(conn
, "msdfs:");
1416 for(i
=0; i
<jucn
->referral_count
; i
++) {
1417 char *refpath
= jucn
->referral_list
[i
].alternate_path
;
1419 /* Alternate paths always use Windows separators. */
1420 trim_char(refpath
, '\\', '\\');
1421 if(*refpath
== '\0') {
1423 insert_comma
= False
;
1427 if (i
> 0 && insert_comma
) {
1428 msdfs_link
= talloc_asprintf_append_buffer(msdfs_link
,
1432 msdfs_link
= talloc_asprintf_append_buffer(msdfs_link
,
1440 if (!insert_comma
) {
1441 insert_comma
= True
;
1445 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1448 if(SMB_VFS_SYMLINK(conn
, msdfs_link
, path
) < 0) {
1449 if (errno
== EEXIST
) {
1450 struct smb_filename
*smb_fname
= NULL
;
1453 status
= create_synthetic_smb_fname(talloc_tos(), path
,
1456 if (!NT_STATUS_IS_OK(status
)) {
1457 errno
= map_errno_from_nt_status(status
);
1461 if(SMB_VFS_UNLINK(conn
, smb_fname
)!=0) {
1462 TALLOC_FREE(smb_fname
);
1465 TALLOC_FREE(smb_fname
);
1467 if (SMB_VFS_SYMLINK(conn
, msdfs_link
, path
) < 0) {
1468 DEBUG(1,("create_msdfs_link: symlink failed "
1469 "%s -> %s\nError: %s\n",
1470 path
, msdfs_link
, strerror(errno
)));
1478 vfs_ChDir(conn
, cwd
);
1479 SMB_VFS_DISCONNECT(conn
);
1484 bool remove_msdfs_link(const struct junction_map
*jucn
)
1488 connection_struct
*conn
;
1490 struct smb_filename
*smb_fname
= NULL
;
1493 if (!junction_to_local_path(jucn
, &path
, &conn
, &cwd
)) {
1497 status
= create_synthetic_smb_fname(talloc_tos(), path
,
1500 if (!NT_STATUS_IS_OK(status
)) {
1501 errno
= map_errno_from_nt_status(status
);
1505 if( SMB_VFS_UNLINK(conn
, smb_fname
) == 0 ) {
1509 TALLOC_FREE(smb_fname
);
1510 vfs_ChDir(conn
, cwd
);
1511 SMB_VFS_DISCONNECT(conn
);
1516 /*********************************************************************
1517 Return the number of DFS links at the root of this share.
1518 *********************************************************************/
1520 static int count_dfs_links(TALLOC_CTX
*ctx
, int snum
)
1523 SMB_STRUCT_DIR
*dirp
= NULL
;
1524 const char *dname
= NULL
;
1525 char *talloced
= NULL
;
1526 const char *connect_path
= lp_pathname(snum
);
1527 const char *msdfs_proxy
= lp_msdfs_proxy(snum
);
1528 connection_struct
*conn
;
1532 if(*connect_path
== '\0') {
1537 * Fake up a connection struct for the VFS layer.
1540 status
= create_conn_struct(talloc_tos(), &conn
, snum
, connect_path
,
1542 if (!NT_STATUS_IS_OK(status
)) {
1543 DEBUG(3, ("create_conn_struct failed: %s\n",
1544 nt_errstr(status
)));
1548 /* Count a link for the msdfs root - convention */
1551 /* No more links if this is an msdfs proxy. */
1552 if (*msdfs_proxy
!= '\0') {
1556 /* Now enumerate all dfs links */
1557 dirp
= SMB_VFS_OPENDIR(conn
, ".", NULL
, 0);
1562 while ((dname
= vfs_readdirname(conn
, dirp
, NULL
, &talloced
))
1564 if (is_msdfs_link(conn
,
1569 TALLOC_FREE(talloced
);
1572 SMB_VFS_CLOSEDIR(conn
,dirp
);
1575 vfs_ChDir(conn
, cwd
);
1576 SMB_VFS_DISCONNECT(conn
);
1581 /*********************************************************************
1582 *********************************************************************/
1584 static int form_junctions(TALLOC_CTX
*ctx
,
1586 struct junction_map
*jucn
,
1590 SMB_STRUCT_DIR
*dirp
= NULL
;
1591 const char *dname
= NULL
;
1592 char *talloced
= NULL
;
1593 const char *connect_path
= lp_pathname(snum
);
1594 char *service_name
= lp_servicename(snum
);
1595 const char *msdfs_proxy
= lp_msdfs_proxy(snum
);
1596 connection_struct
*conn
;
1597 struct referral
*ref
= NULL
;
1601 if (jn_remain
== 0) {
1605 if(*connect_path
== '\0') {
1610 * Fake up a connection struct for the VFS layer.
1613 status
= create_conn_struct(ctx
, &conn
, snum
, connect_path
, NULL
,
1615 if (!NT_STATUS_IS_OK(status
)) {
1616 DEBUG(3, ("create_conn_struct failed: %s\n",
1617 nt_errstr(status
)));
1621 /* form a junction for the msdfs root - convention
1622 DO NOT REMOVE THIS: NT clients will not work with us
1623 if this is not present
1625 jucn
[cnt
].service_name
= talloc_strdup(ctx
,service_name
);
1626 jucn
[cnt
].volume_name
= talloc_strdup(ctx
, "");
1627 if (!jucn
[cnt
].service_name
|| !jucn
[cnt
].volume_name
) {
1630 jucn
[cnt
].comment
= "";
1631 jucn
[cnt
].referral_count
= 1;
1633 ref
= jucn
[cnt
].referral_list
= TALLOC_ZERO_P(ctx
, struct referral
);
1634 if (jucn
[cnt
].referral_list
== NULL
) {
1639 ref
->ttl
= REFERRAL_TTL
;
1640 if (*msdfs_proxy
!= '\0') {
1641 ref
->alternate_path
= talloc_strdup(ctx
,
1644 ref
->alternate_path
= talloc_asprintf(ctx
,
1646 get_local_machine_name(),
1650 if (!ref
->alternate_path
) {
1655 /* Don't enumerate if we're an msdfs proxy. */
1656 if (*msdfs_proxy
!= '\0') {
1660 /* Now enumerate all dfs links */
1661 dirp
= SMB_VFS_OPENDIR(conn
, ".", NULL
, 0);
1666 while ((dname
= vfs_readdirname(conn
, dirp
, NULL
, &talloced
))
1668 char *link_target
= NULL
;
1669 if (cnt
>= jn_remain
) {
1670 DEBUG(2, ("form_junctions: ran out of MSDFS "
1672 TALLOC_FREE(talloced
);
1675 if (is_msdfs_link_internal(ctx
,
1677 dname
, &link_target
,
1679 if (parse_msdfs_symlink(ctx
,
1681 &jucn
[cnt
].referral_list
,
1682 &jucn
[cnt
].referral_count
)) {
1684 jucn
[cnt
].service_name
= talloc_strdup(ctx
,
1686 jucn
[cnt
].volume_name
= talloc_strdup(ctx
,
1688 if (!jucn
[cnt
].service_name
||
1689 !jucn
[cnt
].volume_name
) {
1690 TALLOC_FREE(talloced
);
1693 jucn
[cnt
].comment
= "";
1696 TALLOC_FREE(link_target
);
1698 TALLOC_FREE(talloced
);
1704 SMB_VFS_CLOSEDIR(conn
,dirp
);
1707 vfs_ChDir(conn
, cwd
);
1712 struct junction_map
*enum_msdfs_links(TALLOC_CTX
*ctx
, size_t *p_num_jn
)
1714 struct junction_map
*jn
= NULL
;
1716 size_t jn_count
= 0;
1720 if(!lp_host_msdfs()) {
1724 /* Ensure all the usershares are loaded. */
1726 load_registry_shares();
1727 sharecount
= load_usershare_shares();
1730 for(i
=0;i
< sharecount
;i
++) {
1731 if(lp_msdfs_root(i
)) {
1732 jn_count
+= count_dfs_links(ctx
, i
);
1735 if (jn_count
== 0) {
1738 jn
= TALLOC_ARRAY(ctx
, struct junction_map
, jn_count
);
1742 for(i
=0; i
< sharecount
; i
++) {
1743 if (*p_num_jn
>= jn_count
) {
1746 if(lp_msdfs_root(i
)) {
1747 *p_num_jn
+= form_junctions(ctx
, i
,
1749 jn_count
- *p_num_jn
);
1755 /******************************************************************************
1756 Core function to resolve a dfs pathname possibly containing a wildcard. If
1757 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1758 detected during dfs resolution.
1759 ******************************************************************************/
1761 NTSTATUS
resolve_dfspath_wcard(TALLOC_CTX
*ctx
,
1762 connection_struct
*conn
,
1764 const char *name_in
,
1767 bool *ppath_contains_wcard
)
1769 bool path_contains_wcard
;
1770 NTSTATUS status
= NT_STATUS_OK
;
1772 if (dfs_pathnames
) {
1773 status
= dfs_redirect(ctx
,
1778 &path_contains_wcard
);
1780 if (NT_STATUS_IS_OK(status
) && ppath_contains_wcard
!= NULL
) {
1781 *ppath_contains_wcard
= path_contains_wcard
;
1785 * Cheat and just return a copy of the in ptr.
1786 * Once srvstr_get_path() uses talloc it'll
1787 * be a talloced ptr anyway.
1789 *pp_name_out
= CONST_DISCARD(char *,name_in
);