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",
977 if (NT_STATUS_IS_OK(status
)) {
979 * We are in an error path here (we
980 * know it's not a DFS path), but
981 * dfs_path_lookup() can return
982 * NT_STATUS_OK. Ensure we always
983 * return a valid error code.
985 * #9588 - ACLs are not inherited to directories
988 status
= NT_STATUS_NOT_FOUND
;
993 /* We know this is a valid dfs link. Parse the targetpath. */
994 if (!parse_msdfs_symlink(ctx
, targetpath
,
995 &jucn
->referral_list
,
996 &jucn
->referral_count
)) {
997 DEBUG(3,("get_referred_path: failed to parse symlink "
998 "target %s\n", targetpath
));
999 status
= NT_STATUS_NOT_FOUND
;
1003 status
= NT_STATUS_OK
;
1005 vfs_ChDir(conn
, oldpath
);
1006 SMB_VFS_DISCONNECT(conn
);
1012 static int setup_ver2_dfs_referral(const char *pathname
,
1014 struct junction_map
*junction
,
1017 char* pdata
= *ppdata
;
1019 smb_ucs2_t
*uni_requestedpath
= NULL
;
1020 int uni_reqpathoffset1
,uni_reqpathoffset2
;
1022 int requestedpathlen
=0;
1027 DEBUG(10,("Setting up version2 referral\nRequested path:\n"));
1029 requestedpathlen
= rpcstr_push_talloc(talloc_tos(),
1030 &uni_requestedpath
, pathname
);
1031 if (uni_requestedpath
== NULL
|| requestedpathlen
== 0) {
1036 dump_data(0, (unsigned char *)uni_requestedpath
,
1040 DEBUG(10,("ref count = %u\n",junction
->referral_count
));
1042 uni_reqpathoffset1
= REFERRAL_HEADER_SIZE
+
1043 VERSION2_REFERRAL_SIZE
* junction
->referral_count
;
1045 uni_reqpathoffset2
= uni_reqpathoffset1
+ requestedpathlen
;
1047 uni_curroffset
= uni_reqpathoffset2
+ requestedpathlen
;
1049 reply_size
= REFERRAL_HEADER_SIZE
+
1050 VERSION2_REFERRAL_SIZE
*junction
->referral_count
+
1051 2 * requestedpathlen
;
1052 DEBUG(10,("reply_size: %u\n",reply_size
));
1054 /* add up the unicode lengths of all the referral paths */
1055 for(i
=0;i
<junction
->referral_count
;i
++) {
1056 DEBUG(10,("referral %u : %s\n",
1058 junction
->referral_list
[i
].alternate_path
));
1060 (strlen(junction
->referral_list
[i
].alternate_path
)+1)*2;
1063 DEBUG(10,("reply_size = %u\n",reply_size
));
1064 /* add the unexplained 0x16 bytes */
1067 pdata
= (char *)SMB_REALLOC(pdata
,reply_size
);
1069 DEBUG(0,("Realloc failed!\n"));
1074 /* copy in the dfs requested paths.. required for offset calculations */
1075 memcpy(pdata
+uni_reqpathoffset1
,uni_requestedpath
,requestedpathlen
);
1076 memcpy(pdata
+uni_reqpathoffset2
,uni_requestedpath
,requestedpathlen
);
1078 /* create the header */
1079 SSVAL(pdata
,0,requestedpathlen
- 2); /* UCS2 of path consumed minus
1081 /* number of referral in this pkt */
1082 SSVAL(pdata
,2,junction
->referral_count
);
1084 SIVAL(pdata
,4,DFSREF_REFERRAL_SERVER
| DFSREF_STORAGE_SERVER
);
1086 SIVAL(pdata
,4,DFSREF_STORAGE_SERVER
);
1090 /* add the referral elements */
1091 for(i
=0;i
<junction
->referral_count
;i
++) {
1092 struct referral
* ref
= &junction
->referral_list
[i
];
1095 SSVAL(pdata
,offset
,2); /* version 2 */
1096 SSVAL(pdata
,offset
+2,VERSION2_REFERRAL_SIZE
);
1098 SSVAL(pdata
,offset
+4,1);
1100 SSVAL(pdata
,offset
+4,0);
1103 /* ref_flags :use path_consumed bytes? */
1104 SSVAL(pdata
,offset
+6,0);
1105 SIVAL(pdata
,offset
+8,ref
->proximity
);
1106 SIVAL(pdata
,offset
+12,ref
->ttl
);
1108 SSVAL(pdata
,offset
+16,uni_reqpathoffset1
-offset
);
1109 SSVAL(pdata
,offset
+18,uni_reqpathoffset2
-offset
);
1110 /* copy referred path into current offset */
1111 unilen
= rpcstr_push(pdata
+uni_curroffset
,
1112 ref
->alternate_path
,
1113 reply_size
- uni_curroffset
,
1116 SSVAL(pdata
,offset
+20,uni_curroffset
-offset
);
1118 uni_curroffset
+= unilen
;
1119 offset
+= VERSION2_REFERRAL_SIZE
;
1121 /* add in the unexplained 22 (0x16) bytes at the end */
1122 memset(pdata
+uni_curroffset
,'\0',0x16);
1126 static int setup_ver3_dfs_referral(const char *pathname
,
1128 struct junction_map
*junction
,
1131 char *pdata
= *ppdata
;
1133 smb_ucs2_t
*uni_reqpath
= NULL
;
1134 int uni_reqpathoffset1
, uni_reqpathoffset2
;
1141 DEBUG(10,("setting up version3 referral\n"));
1143 reqpathlen
= rpcstr_push_talloc(talloc_tos(), &uni_reqpath
, pathname
);
1144 if (uni_reqpath
== NULL
|| reqpathlen
== 0) {
1149 dump_data(0, (unsigned char *)uni_reqpath
,
1153 uni_reqpathoffset1
= REFERRAL_HEADER_SIZE
+
1154 VERSION3_REFERRAL_SIZE
* junction
->referral_count
;
1155 uni_reqpathoffset2
= uni_reqpathoffset1
+ reqpathlen
;
1156 reply_size
= uni_curroffset
= uni_reqpathoffset2
+ reqpathlen
;
1158 for(i
=0;i
<junction
->referral_count
;i
++) {
1159 DEBUG(10,("referral %u : %s\n",
1161 junction
->referral_list
[i
].alternate_path
));
1163 (strlen(junction
->referral_list
[i
].alternate_path
)+1)*2;
1166 pdata
= (char *)SMB_REALLOC(pdata
,reply_size
);
1168 DEBUG(0,("version3 referral setup:"
1169 "malloc failed for Realloc!\n"));
1174 /* create the header */
1175 SSVAL(pdata
,0,reqpathlen
- 2); /* UCS2 of path consumed minus
1177 SSVAL(pdata
,2,junction
->referral_count
); /* number of referral */
1179 SIVAL(pdata
,4,DFSREF_REFERRAL_SERVER
| DFSREF_STORAGE_SERVER
);
1181 SIVAL(pdata
,4,DFSREF_STORAGE_SERVER
);
1184 /* copy in the reqpaths */
1185 memcpy(pdata
+uni_reqpathoffset1
,uni_reqpath
,reqpathlen
);
1186 memcpy(pdata
+uni_reqpathoffset2
,uni_reqpath
,reqpathlen
);
1189 for(i
=0;i
<junction
->referral_count
;i
++) {
1190 struct referral
* ref
= &(junction
->referral_list
[i
]);
1193 SSVAL(pdata
,offset
,3); /* version 3 */
1194 SSVAL(pdata
,offset
+2,VERSION3_REFERRAL_SIZE
);
1196 SSVAL(pdata
,offset
+4,1);
1198 SSVAL(pdata
,offset
+4,0);
1201 /* ref_flags :use path_consumed bytes? */
1202 SSVAL(pdata
,offset
+6,0);
1203 SIVAL(pdata
,offset
+8,ref
->ttl
);
1205 SSVAL(pdata
,offset
+12,uni_reqpathoffset1
-offset
);
1206 SSVAL(pdata
,offset
+14,uni_reqpathoffset2
-offset
);
1207 /* copy referred path into current offset */
1208 unilen
= rpcstr_push(pdata
+uni_curroffset
,ref
->alternate_path
,
1209 reply_size
- uni_curroffset
,
1210 STR_UNICODE
| STR_TERMINATE
);
1211 SSVAL(pdata
,offset
+16,uni_curroffset
-offset
);
1212 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
1213 memset(pdata
+offset
+18,'\0',16);
1215 uni_curroffset
+= unilen
;
1216 offset
+= VERSION3_REFERRAL_SIZE
;
1221 /******************************************************************
1222 Set up the DFS referral for the dfs pathname. This call returns
1223 the amount of the path covered by this server, and where the
1224 client should be redirected to. This is the meat of the
1225 TRANS2_GET_DFS_REFERRAL call.
1226 ******************************************************************/
1228 int setup_dfs_referral(connection_struct
*orig_conn
,
1229 const char *dfs_path
,
1230 int max_referral_level
,
1231 char **ppdata
, NTSTATUS
*pstatus
)
1233 struct junction_map
*junction
= NULL
;
1234 int consumedcnt
= 0;
1235 bool self_referral
= False
;
1237 char *pathnamep
= NULL
;
1238 char *local_dfs_path
= NULL
;
1241 if (!(ctx
=talloc_init("setup_dfs_referral"))) {
1242 *pstatus
= NT_STATUS_NO_MEMORY
;
1246 /* get the junction entry */
1248 talloc_destroy(ctx
);
1249 *pstatus
= NT_STATUS_NOT_FOUND
;
1254 * Trim pathname sent by client so it begins with only one backslash.
1255 * Two backslashes confuse some dfs clients
1258 local_dfs_path
= talloc_strdup(ctx
,dfs_path
);
1259 if (!local_dfs_path
) {
1260 *pstatus
= NT_STATUS_NO_MEMORY
;
1261 talloc_destroy(ctx
);
1264 pathnamep
= local_dfs_path
;
1265 while (IS_DIRECTORY_SEP(pathnamep
[0]) &&
1266 IS_DIRECTORY_SEP(pathnamep
[1])) {
1270 junction
= TALLOC_ZERO_P(ctx
, struct junction_map
);
1272 *pstatus
= NT_STATUS_NO_MEMORY
;
1273 talloc_destroy(ctx
);
1277 /* The following call can change cwd. */
1278 *pstatus
= get_referred_path(ctx
, pathnamep
, junction
,
1279 &consumedcnt
, &self_referral
);
1280 if (!NT_STATUS_IS_OK(*pstatus
)) {
1281 vfs_ChDir(orig_conn
,orig_conn
->connectpath
);
1282 talloc_destroy(ctx
);
1285 vfs_ChDir(orig_conn
,orig_conn
->connectpath
);
1287 if (!self_referral
) {
1288 pathnamep
[consumedcnt
] = '\0';
1290 if( DEBUGLVL( 3 ) ) {
1292 dbgtext("setup_dfs_referral: Path %s to "
1293 "alternate path(s):",
1295 for(i
=0;i
<junction
->referral_count
;i
++)
1297 junction
->referral_list
[i
].alternate_path
);
1302 /* create the referral depeding on version */
1303 DEBUG(10,("max_referral_level :%d\n",max_referral_level
));
1305 if (max_referral_level
< 2) {
1306 max_referral_level
= 2;
1308 if (max_referral_level
> 3) {
1309 max_referral_level
= 3;
1312 switch(max_referral_level
) {
1314 reply_size
= setup_ver2_dfs_referral(pathnamep
,
1319 reply_size
= setup_ver3_dfs_referral(pathnamep
, ppdata
,
1320 junction
, self_referral
);
1323 DEBUG(0,("setup_dfs_referral: Invalid dfs referral "
1325 max_referral_level
));
1326 talloc_destroy(ctx
);
1327 *pstatus
= NT_STATUS_INVALID_LEVEL
;
1332 DEBUGADD(0,("DFS Referral pdata:\n"));
1333 dump_data(0,(uint8
*)*ppdata
,reply_size
);
1336 talloc_destroy(ctx
);
1337 *pstatus
= NT_STATUS_OK
;
1341 /**********************************************************************
1342 The following functions are called by the NETDFS RPC pipe functions
1343 **********************************************************************/
1345 /*********************************************************************
1346 Creates a junction structure from a DFS pathname
1347 **********************************************************************/
1349 bool create_junction(TALLOC_CTX
*ctx
,
1350 const char *dfs_path
,
1351 struct junction_map
*jucn
)
1355 struct dfs_path
*pdp
= TALLOC_P(ctx
,struct dfs_path
);
1361 status
= parse_dfs_path(NULL
, dfs_path
, False
, pdp
, &dummy
);
1362 if (!NT_STATUS_IS_OK(status
)) {
1366 /* check if path is dfs : validate first token */
1367 if (!is_myname_or_ipaddr(pdp
->hostname
)) {
1368 DEBUG(4,("create_junction: Invalid hostname %s "
1370 pdp
->hostname
, dfs_path
));
1375 /* Check for a non-DFS share */
1376 snum
= lp_servicenumber(pdp
->servicename
);
1378 if(snum
< 0 || !lp_msdfs_root(snum
)) {
1379 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1385 jucn
->service_name
= talloc_strdup(ctx
, pdp
->servicename
);
1386 jucn
->volume_name
= talloc_strdup(ctx
, pdp
->reqpath
);
1387 jucn
->comment
= talloc_strdup(ctx
, lp_comment(snum
));
1390 if (!jucn
->service_name
|| !jucn
->volume_name
|| ! jucn
->comment
) {
1396 /**********************************************************************
1397 Forms a valid Unix pathname from the junction
1398 **********************************************************************/
1400 static bool junction_to_local_path(const struct junction_map
*jucn
,
1402 connection_struct
**conn_out
,
1408 snum
= lp_servicenumber(jucn
->service_name
);
1412 status
= create_conn_struct(talloc_tos(), conn_out
, snum
,
1413 lp_pathname(snum
), NULL
, oldpath
);
1414 if (!NT_STATUS_IS_OK(status
)) {
1418 *pp_path_out
= talloc_asprintf(*conn_out
,
1422 if (!*pp_path_out
) {
1423 vfs_ChDir(*conn_out
, *oldpath
);
1424 SMB_VFS_DISCONNECT(*conn_out
);
1425 conn_free(*conn_out
);
1431 bool create_msdfs_link(const struct junction_map
*jucn
)
1435 char *msdfs_link
= NULL
;
1436 connection_struct
*conn
;
1438 bool insert_comma
= False
;
1441 if(!junction_to_local_path(jucn
, &path
, &conn
, &cwd
)) {
1445 /* Form the msdfs_link contents */
1446 msdfs_link
= talloc_strdup(conn
, "msdfs:");
1450 for(i
=0; i
<jucn
->referral_count
; i
++) {
1451 char *refpath
= jucn
->referral_list
[i
].alternate_path
;
1453 /* Alternate paths always use Windows separators. */
1454 trim_char(refpath
, '\\', '\\');
1455 if(*refpath
== '\0') {
1457 insert_comma
= False
;
1461 if (i
> 0 && insert_comma
) {
1462 msdfs_link
= talloc_asprintf_append_buffer(msdfs_link
,
1466 msdfs_link
= talloc_asprintf_append_buffer(msdfs_link
,
1474 if (!insert_comma
) {
1475 insert_comma
= True
;
1479 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1482 if(SMB_VFS_SYMLINK(conn
, msdfs_link
, path
) < 0) {
1483 if (errno
== EEXIST
) {
1484 struct smb_filename
*smb_fname
= NULL
;
1487 status
= create_synthetic_smb_fname(talloc_tos(), path
,
1490 if (!NT_STATUS_IS_OK(status
)) {
1491 errno
= map_errno_from_nt_status(status
);
1495 if(SMB_VFS_UNLINK(conn
, smb_fname
)!=0) {
1496 TALLOC_FREE(smb_fname
);
1499 TALLOC_FREE(smb_fname
);
1501 if (SMB_VFS_SYMLINK(conn
, msdfs_link
, path
) < 0) {
1502 DEBUG(1,("create_msdfs_link: symlink failed "
1503 "%s -> %s\nError: %s\n",
1504 path
, msdfs_link
, strerror(errno
)));
1512 vfs_ChDir(conn
, cwd
);
1513 SMB_VFS_DISCONNECT(conn
);
1518 bool remove_msdfs_link(const struct junction_map
*jucn
)
1522 connection_struct
*conn
;
1524 struct smb_filename
*smb_fname
= NULL
;
1527 if (!junction_to_local_path(jucn
, &path
, &conn
, &cwd
)) {
1531 status
= create_synthetic_smb_fname(talloc_tos(), path
,
1534 if (!NT_STATUS_IS_OK(status
)) {
1535 errno
= map_errno_from_nt_status(status
);
1539 if( SMB_VFS_UNLINK(conn
, smb_fname
) == 0 ) {
1543 TALLOC_FREE(smb_fname
);
1544 vfs_ChDir(conn
, cwd
);
1545 SMB_VFS_DISCONNECT(conn
);
1550 /*********************************************************************
1551 Return the number of DFS links at the root of this share.
1552 *********************************************************************/
1554 static int count_dfs_links(TALLOC_CTX
*ctx
, int snum
)
1557 SMB_STRUCT_DIR
*dirp
= NULL
;
1558 const char *dname
= NULL
;
1559 char *talloced
= NULL
;
1560 const char *connect_path
= lp_pathname(snum
);
1561 const char *msdfs_proxy
= lp_msdfs_proxy(snum
);
1562 connection_struct
*conn
;
1566 if(*connect_path
== '\0') {
1571 * Fake up a connection struct for the VFS layer.
1574 status
= create_conn_struct(talloc_tos(), &conn
, snum
, connect_path
,
1576 if (!NT_STATUS_IS_OK(status
)) {
1577 DEBUG(3, ("create_conn_struct failed: %s\n",
1578 nt_errstr(status
)));
1582 /* Count a link for the msdfs root - convention */
1585 /* No more links if this is an msdfs proxy. */
1586 if (*msdfs_proxy
!= '\0') {
1590 /* Now enumerate all dfs links */
1591 dirp
= SMB_VFS_OPENDIR(conn
, ".", NULL
, 0);
1596 while ((dname
= vfs_readdirname(conn
, dirp
, NULL
, &talloced
))
1598 if (is_msdfs_link(conn
,
1603 TALLOC_FREE(talloced
);
1606 SMB_VFS_CLOSEDIR(conn
,dirp
);
1609 vfs_ChDir(conn
, cwd
);
1610 SMB_VFS_DISCONNECT(conn
);
1615 /*********************************************************************
1616 *********************************************************************/
1618 static int form_junctions(TALLOC_CTX
*ctx
,
1620 struct junction_map
*jucn
,
1624 SMB_STRUCT_DIR
*dirp
= NULL
;
1625 const char *dname
= NULL
;
1626 char *talloced
= NULL
;
1627 const char *connect_path
= lp_pathname(snum
);
1628 char *service_name
= lp_servicename(snum
);
1629 const char *msdfs_proxy
= lp_msdfs_proxy(snum
);
1630 connection_struct
*conn
;
1631 struct referral
*ref
= NULL
;
1635 if (jn_remain
== 0) {
1639 if(*connect_path
== '\0') {
1644 * Fake up a connection struct for the VFS layer.
1647 status
= create_conn_struct(ctx
, &conn
, snum
, connect_path
, NULL
,
1649 if (!NT_STATUS_IS_OK(status
)) {
1650 DEBUG(3, ("create_conn_struct failed: %s\n",
1651 nt_errstr(status
)));
1655 /* form a junction for the msdfs root - convention
1656 DO NOT REMOVE THIS: NT clients will not work with us
1657 if this is not present
1659 jucn
[cnt
].service_name
= talloc_strdup(ctx
,service_name
);
1660 jucn
[cnt
].volume_name
= talloc_strdup(ctx
, "");
1661 if (!jucn
[cnt
].service_name
|| !jucn
[cnt
].volume_name
) {
1664 jucn
[cnt
].comment
= "";
1665 jucn
[cnt
].referral_count
= 1;
1667 ref
= jucn
[cnt
].referral_list
= TALLOC_ZERO_P(ctx
, struct referral
);
1668 if (jucn
[cnt
].referral_list
== NULL
) {
1673 ref
->ttl
= REFERRAL_TTL
;
1674 if (*msdfs_proxy
!= '\0') {
1675 ref
->alternate_path
= talloc_strdup(ctx
,
1678 ref
->alternate_path
= talloc_asprintf(ctx
,
1680 get_local_machine_name(),
1684 if (!ref
->alternate_path
) {
1689 /* Don't enumerate if we're an msdfs proxy. */
1690 if (*msdfs_proxy
!= '\0') {
1694 /* Now enumerate all dfs links */
1695 dirp
= SMB_VFS_OPENDIR(conn
, ".", NULL
, 0);
1700 while ((dname
= vfs_readdirname(conn
, dirp
, NULL
, &talloced
))
1702 char *link_target
= NULL
;
1703 if (cnt
>= jn_remain
) {
1704 DEBUG(2, ("form_junctions: ran out of MSDFS "
1706 TALLOC_FREE(talloced
);
1709 if (is_msdfs_link_internal(ctx
,
1711 dname
, &link_target
,
1713 if (parse_msdfs_symlink(ctx
,
1715 &jucn
[cnt
].referral_list
,
1716 &jucn
[cnt
].referral_count
)) {
1718 jucn
[cnt
].service_name
= talloc_strdup(ctx
,
1720 jucn
[cnt
].volume_name
= talloc_strdup(ctx
,
1722 if (!jucn
[cnt
].service_name
||
1723 !jucn
[cnt
].volume_name
) {
1724 TALLOC_FREE(talloced
);
1727 jucn
[cnt
].comment
= "";
1730 TALLOC_FREE(link_target
);
1732 TALLOC_FREE(talloced
);
1738 SMB_VFS_CLOSEDIR(conn
,dirp
);
1741 vfs_ChDir(conn
, cwd
);
1746 struct junction_map
*enum_msdfs_links(TALLOC_CTX
*ctx
, size_t *p_num_jn
)
1748 struct junction_map
*jn
= NULL
;
1750 size_t jn_count
= 0;
1754 if(!lp_host_msdfs()) {
1758 /* Ensure all the usershares are loaded. */
1760 load_registry_shares();
1761 sharecount
= load_usershare_shares();
1764 for(i
=0;i
< sharecount
;i
++) {
1765 if(lp_msdfs_root(i
)) {
1766 jn_count
+= count_dfs_links(ctx
, i
);
1769 if (jn_count
== 0) {
1772 jn
= TALLOC_ARRAY(ctx
, struct junction_map
, jn_count
);
1776 for(i
=0; i
< sharecount
; i
++) {
1777 if (*p_num_jn
>= jn_count
) {
1780 if(lp_msdfs_root(i
)) {
1781 *p_num_jn
+= form_junctions(ctx
, i
,
1783 jn_count
- *p_num_jn
);
1789 /******************************************************************************
1790 Core function to resolve a dfs pathname possibly containing a wildcard. If
1791 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1792 detected during dfs resolution.
1793 ******************************************************************************/
1795 NTSTATUS
resolve_dfspath_wcard(TALLOC_CTX
*ctx
,
1796 connection_struct
*conn
,
1798 const char *name_in
,
1801 bool *ppath_contains_wcard
)
1803 bool path_contains_wcard
;
1804 NTSTATUS status
= NT_STATUS_OK
;
1806 if (dfs_pathnames
) {
1807 status
= dfs_redirect(ctx
,
1812 &path_contains_wcard
);
1814 if (NT_STATUS_IS_OK(status
) && ppath_contains_wcard
!= NULL
) {
1815 *ppath_contains_wcard
= path_contains_wcard
;
1819 * Cheat and just return a copy of the in ptr.
1820 * Once srvstr_get_path() uses talloc it'll
1821 * be a talloced ptr anyway.
1823 *pp_name_out
= CONST_DISCARD(char *,name_in
);