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 can
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.
582 * If we needed to remember what we'd resolved in
583 * dp->reqpath (as the original code did) we'd
584 * copy (localhost, dp->reqpath) on any code
585 * path below that returns True - but I don't
586 * think this is needed. JRA.
589 status
= unix_convert(ctx
, conn
, pdp
->reqpath
, &smb_fname
,
590 search_flag
? UCF_ALWAYS_ALLOW_WCARD_LCOMP
: 0);
592 if (!NT_STATUS_IS_OK(status
)) {
593 if (!NT_STATUS_EQUAL(status
,
594 NT_STATUS_OBJECT_PATH_NOT_FOUND
)) {
598 /* Create an smb_fname to use below. */
599 status
= create_synthetic_smb_fname(ctx
, pdp
->reqpath
, NULL
,
601 if (!NT_STATUS_IS_OK(status
)) {
606 /* Optimization - check if we can redirect the whole path. */
608 if (is_msdfs_link_internal(ctx
, conn
, smb_fname
->base_name
,
609 pp_targetpath
, NULL
)) {
611 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
612 "for dfs link %s.\n", dfspath
));
613 status
= NT_STATUS_OK
;
617 DEBUG(6,("dfs_path_lookup: %s resolves to a "
618 "valid dfs link %s.\n", dfspath
,
619 pp_targetpath
? *pp_targetpath
: ""));
622 *consumedcntp
= strlen(dfspath
);
624 status
= NT_STATUS_PATH_NOT_COVERED
;
628 /* Prepare to test only for '/' components in the given path,
629 * so if a Windows path replace all '\\' characters with '/'.
630 * For a POSIX DFS path we know all separators are already '/'. */
632 canon_dfspath
= talloc_strdup(ctx
, dfspath
);
633 if (!canon_dfspath
) {
634 status
= NT_STATUS_NO_MEMORY
;
637 if (!pdp
->posix_path
) {
638 string_replace(canon_dfspath
, '\\', '/');
642 * localpath comes out of unix_convert, so it has
643 * no trailing backslash. Make sure that canon_dfspath hasn't either.
644 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
647 trim_char(canon_dfspath
,0,'/');
650 * Redirect if any component in the path is a link.
651 * We do this by walking backwards through the
652 * local path, chopping off the last component
653 * in both the local path and the canonicalized
654 * DFS path. If we hit a DFS link then we're done.
657 p
= strrchr_m(smb_fname
->base_name
, '/');
659 q
= strrchr_m(canon_dfspath
, '/');
668 if (is_msdfs_link_internal(ctx
, conn
,
669 smb_fname
->base_name
, pp_targetpath
,
671 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
672 "parent %s is dfs link\n", dfspath
,
673 smb_fname_str_dbg(smb_fname
)));
676 *consumedcntp
= strlen(canon_dfspath
);
677 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
683 status
= NT_STATUS_PATH_NOT_COVERED
;
687 /* Step back on the filesystem. */
688 p
= strrchr_m(smb_fname
->base_name
, '/');
691 /* And in the canonicalized dfs path. */
692 q
= strrchr_m(canon_dfspath
, '/');
696 status
= NT_STATUS_OK
;
698 TALLOC_FREE(smb_fname
);
702 /*****************************************************************
703 Decides if a dfs pathname should be redirected or not.
704 If not, the pathname is converted to a tcon-relative local unix path
706 search_wcard_flag: this flag performs 2 functions both related
707 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
710 This function can return NT_STATUS_OK, meaning use the returned path as-is
711 (mapped into a local path).
712 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
713 any other NT_STATUS error which is a genuine error to be
714 returned to the client.
715 *****************************************************************/
717 static NTSTATUS
dfs_redirect(TALLOC_CTX
*ctx
,
718 connection_struct
*conn
,
720 bool search_wcard_flag
,
722 bool *ppath_contains_wcard
)
725 struct dfs_path
*pdp
= TALLOC_P(ctx
, struct dfs_path
);
728 return NT_STATUS_NO_MEMORY
;
731 status
= parse_dfs_path(conn
, path_in
, search_wcard_flag
, pdp
,
732 ppath_contains_wcard
);
733 if (!NT_STATUS_IS_OK(status
)) {
738 if (pdp
->reqpath
[0] == '\0') {
740 *pp_path_out
= talloc_strdup(ctx
, "");
742 return NT_STATUS_NO_MEMORY
;
744 DEBUG(5,("dfs_redirect: self-referral.\n"));
748 /* If dfs pathname for a non-dfs share, convert to tcon-relative
749 path and return OK */
751 if (!lp_msdfs_root(SNUM(conn
))) {
752 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
755 return NT_STATUS_NO_MEMORY
;
760 /* If it looked like a local path (zero hostname/servicename)
761 * just treat as a tcon-relative path. */
763 if (pdp
->hostname
[0] == '\0' && pdp
->servicename
[0] == '\0') {
764 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
767 return NT_STATUS_NO_MEMORY
;
772 if (!( strequal(pdp
->servicename
, lp_servicename(SNUM(conn
)))
773 || (strequal(pdp
->servicename
, HOMES_NAME
)
774 && strequal(lp_servicename(SNUM(conn
)),
775 conn
->session_info
->sanitized_username
) )) ) {
777 /* The given sharename doesn't match this connection. */
780 return NT_STATUS_OBJECT_PATH_NOT_FOUND
;
783 status
= dfs_path_lookup(ctx
, conn
, path_in
, pdp
,
784 search_wcard_flag
, NULL
, NULL
);
785 if (!NT_STATUS_IS_OK(status
)) {
786 if (NT_STATUS_EQUAL(status
, NT_STATUS_PATH_NOT_COVERED
)) {
787 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in
));
789 DEBUG(10,("dfs_redirect: dfs_path_lookup "
790 "failed for %s with %s\n",
791 path_in
, nt_errstr(status
) ));
796 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in
));
798 /* Form non-dfs tcon-relative path */
799 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
802 return NT_STATUS_NO_MEMORY
;
805 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
812 /**********************************************************************
813 Return a self referral.
814 **********************************************************************/
816 static NTSTATUS
self_ref(TALLOC_CTX
*ctx
,
817 const char *dfs_path
,
818 struct junction_map
*jucn
,
820 bool *self_referralp
)
822 struct referral
*ref
;
824 *self_referralp
= True
;
826 jucn
->referral_count
= 1;
827 if((ref
= TALLOC_ZERO_P(ctx
, struct referral
)) == NULL
) {
828 return NT_STATUS_NO_MEMORY
;
831 ref
->alternate_path
= talloc_strdup(ctx
, dfs_path
);
832 if (!ref
->alternate_path
) {
833 return NT_STATUS_NO_MEMORY
;
836 ref
->ttl
= REFERRAL_TTL
;
837 jucn
->referral_list
= ref
;
838 *consumedcntp
= strlen(dfs_path
);
842 /**********************************************************************
843 Gets valid referrals for a dfs path and fills up the
844 junction_map structure.
845 **********************************************************************/
847 NTSTATUS
get_referred_path(TALLOC_CTX
*ctx
,
848 const char *dfs_path
,
849 struct junction_map
*jucn
,
851 bool *self_referralp
)
853 struct connection_struct
*conn
;
854 char *targetpath
= NULL
;
856 NTSTATUS status
= NT_STATUS_NOT_FOUND
;
858 struct dfs_path
*pdp
= TALLOC_P(ctx
, struct dfs_path
);
862 return NT_STATUS_NO_MEMORY
;
865 *self_referralp
= False
;
867 status
= parse_dfs_path(NULL
, dfs_path
, False
, pdp
, &dummy
);
868 if (!NT_STATUS_IS_OK(status
)) {
872 jucn
->service_name
= talloc_strdup(ctx
, pdp
->servicename
);
873 jucn
->volume_name
= talloc_strdup(ctx
, pdp
->reqpath
);
874 if (!jucn
->service_name
|| !jucn
->volume_name
) {
876 return NT_STATUS_NO_MEMORY
;
879 /* Verify the share is a dfs root */
880 snum
= lp_servicenumber(jucn
->service_name
);
882 char *service_name
= NULL
;
883 if ((snum
= find_service(ctx
, jucn
->service_name
, &service_name
)) < 0) {
884 return NT_STATUS_NOT_FOUND
;
887 return NT_STATUS_NO_MEMORY
;
889 TALLOC_FREE(jucn
->service_name
);
890 jucn
->service_name
= talloc_strdup(ctx
, service_name
);
891 if (!jucn
->service_name
) {
893 return NT_STATUS_NO_MEMORY
;
897 if (!lp_msdfs_root(snum
) && (*lp_msdfs_proxy(snum
) == '\0')) {
898 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
900 pdp
->servicename
, dfs_path
));
902 return NT_STATUS_NOT_FOUND
;
906 * Self referrals are tested with a anonymous IPC connection and
907 * a GET_DFS_REFERRAL call to \\server\share. (which means
908 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
909 * into the directory and will fail if it cannot (as the anonymous
910 * user). Cope with this.
913 if (pdp
->reqpath
[0] == '\0') {
915 struct referral
*ref
;
917 if (*lp_msdfs_proxy(snum
) == '\0') {
927 * It's an msdfs proxy share. Redirect to
928 * the configured target share.
931 jucn
->referral_count
= 1;
932 if ((ref
= TALLOC_ZERO_P(ctx
, struct referral
)) == NULL
) {
934 return NT_STATUS_NO_MEMORY
;
937 if (!(tmp
= talloc_strdup(ctx
, lp_msdfs_proxy(snum
)))) {
939 return NT_STATUS_NO_MEMORY
;
942 trim_string(tmp
, "\\", 0);
944 ref
->alternate_path
= talloc_asprintf(ctx
, "\\%s", tmp
);
947 if (!ref
->alternate_path
) {
949 return NT_STATUS_NO_MEMORY
;
952 if (pdp
->reqpath
[0] != '\0') {
953 ref
->alternate_path
= talloc_asprintf_append(
957 if (!ref
->alternate_path
) {
959 return NT_STATUS_NO_MEMORY
;
963 ref
->ttl
= REFERRAL_TTL
;
964 jucn
->referral_list
= ref
;
965 *consumedcntp
= strlen(dfs_path
);
970 status
= create_conn_struct(ctx
, &conn
, snum
, lp_pathname(snum
),
972 if (!NT_STATUS_IS_OK(status
)) {
977 /* If this is a DFS path dfs_lookup should return
978 * NT_STATUS_PATH_NOT_COVERED. */
980 status
= dfs_path_lookup(ctx
, conn
, dfs_path
, pdp
,
981 False
, consumedcntp
, &targetpath
);
983 if (!NT_STATUS_EQUAL(status
, NT_STATUS_PATH_NOT_COVERED
)) {
984 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
989 /* We know this is a valid dfs link. Parse the targetpath. */
990 if (!parse_msdfs_symlink(ctx
, targetpath
,
991 &jucn
->referral_list
,
992 &jucn
->referral_count
)) {
993 DEBUG(3,("get_referred_path: failed to parse symlink "
994 "target %s\n", targetpath
));
995 status
= NT_STATUS_NOT_FOUND
;
999 status
= NT_STATUS_OK
;
1001 vfs_ChDir(conn
, oldpath
);
1002 SMB_VFS_DISCONNECT(conn
);
1008 static int setup_ver2_dfs_referral(const char *pathname
,
1010 struct junction_map
*junction
,
1013 char* pdata
= *ppdata
;
1015 smb_ucs2_t
*uni_requestedpath
= NULL
;
1016 int uni_reqpathoffset1
,uni_reqpathoffset2
;
1018 int requestedpathlen
=0;
1023 DEBUG(10,("Setting up version2 referral\nRequested path:\n"));
1025 requestedpathlen
= rpcstr_push_talloc(talloc_tos(),
1026 &uni_requestedpath
, pathname
);
1027 if (uni_requestedpath
== NULL
|| requestedpathlen
== 0) {
1032 dump_data(0, (unsigned char *)uni_requestedpath
,
1036 DEBUG(10,("ref count = %u\n",junction
->referral_count
));
1038 uni_reqpathoffset1
= REFERRAL_HEADER_SIZE
+
1039 VERSION2_REFERRAL_SIZE
* junction
->referral_count
;
1041 uni_reqpathoffset2
= uni_reqpathoffset1
+ requestedpathlen
;
1043 uni_curroffset
= uni_reqpathoffset2
+ requestedpathlen
;
1045 reply_size
= REFERRAL_HEADER_SIZE
+
1046 VERSION2_REFERRAL_SIZE
*junction
->referral_count
+
1047 2 * requestedpathlen
;
1048 DEBUG(10,("reply_size: %u\n",reply_size
));
1050 /* add up the unicode lengths of all the referral paths */
1051 for(i
=0;i
<junction
->referral_count
;i
++) {
1052 DEBUG(10,("referral %u : %s\n",
1054 junction
->referral_list
[i
].alternate_path
));
1056 (strlen(junction
->referral_list
[i
].alternate_path
)+1)*2;
1059 DEBUG(10,("reply_size = %u\n",reply_size
));
1060 /* add the unexplained 0x16 bytes */
1063 pdata
= (char *)SMB_REALLOC(pdata
,reply_size
);
1065 DEBUG(0,("Realloc failed!\n"));
1070 /* copy in the dfs requested paths.. required for offset calculations */
1071 memcpy(pdata
+uni_reqpathoffset1
,uni_requestedpath
,requestedpathlen
);
1072 memcpy(pdata
+uni_reqpathoffset2
,uni_requestedpath
,requestedpathlen
);
1074 /* create the header */
1075 SSVAL(pdata
,0,requestedpathlen
- 2); /* UCS2 of path consumed minus
1077 /* number of referral in this pkt */
1078 SSVAL(pdata
,2,junction
->referral_count
);
1080 SIVAL(pdata
,4,DFSREF_REFERRAL_SERVER
| DFSREF_STORAGE_SERVER
);
1082 SIVAL(pdata
,4,DFSREF_STORAGE_SERVER
);
1086 /* add the referral elements */
1087 for(i
=0;i
<junction
->referral_count
;i
++) {
1088 struct referral
* ref
= &junction
->referral_list
[i
];
1091 SSVAL(pdata
,offset
,2); /* version 2 */
1092 SSVAL(pdata
,offset
+2,VERSION2_REFERRAL_SIZE
);
1094 SSVAL(pdata
,offset
+4,1);
1096 SSVAL(pdata
,offset
+4,0);
1099 /* ref_flags :use path_consumed bytes? */
1100 SSVAL(pdata
,offset
+6,0);
1101 SIVAL(pdata
,offset
+8,ref
->proximity
);
1102 SIVAL(pdata
,offset
+12,ref
->ttl
);
1104 SSVAL(pdata
,offset
+16,uni_reqpathoffset1
-offset
);
1105 SSVAL(pdata
,offset
+18,uni_reqpathoffset2
-offset
);
1106 /* copy referred path into current offset */
1107 unilen
= rpcstr_push(pdata
+uni_curroffset
,
1108 ref
->alternate_path
,
1109 reply_size
- uni_curroffset
,
1112 SSVAL(pdata
,offset
+20,uni_curroffset
-offset
);
1114 uni_curroffset
+= unilen
;
1115 offset
+= VERSION2_REFERRAL_SIZE
;
1117 /* add in the unexplained 22 (0x16) bytes at the end */
1118 memset(pdata
+uni_curroffset
,'\0',0x16);
1122 static int setup_ver3_dfs_referral(const char *pathname
,
1124 struct junction_map
*junction
,
1127 char *pdata
= *ppdata
;
1129 smb_ucs2_t
*uni_reqpath
= NULL
;
1130 int uni_reqpathoffset1
, uni_reqpathoffset2
;
1137 DEBUG(10,("setting up version3 referral\n"));
1139 reqpathlen
= rpcstr_push_talloc(talloc_tos(), &uni_reqpath
, pathname
);
1140 if (uni_reqpath
== NULL
|| reqpathlen
== 0) {
1145 dump_data(0, (unsigned char *)uni_reqpath
,
1149 uni_reqpathoffset1
= REFERRAL_HEADER_SIZE
+
1150 VERSION3_REFERRAL_SIZE
* junction
->referral_count
;
1151 uni_reqpathoffset2
= uni_reqpathoffset1
+ reqpathlen
;
1152 reply_size
= uni_curroffset
= uni_reqpathoffset2
+ reqpathlen
;
1154 for(i
=0;i
<junction
->referral_count
;i
++) {
1155 DEBUG(10,("referral %u : %s\n",
1157 junction
->referral_list
[i
].alternate_path
));
1159 (strlen(junction
->referral_list
[i
].alternate_path
)+1)*2;
1162 pdata
= (char *)SMB_REALLOC(pdata
,reply_size
);
1164 DEBUG(0,("version3 referral setup:"
1165 "malloc failed for Realloc!\n"));
1170 /* create the header */
1171 SSVAL(pdata
,0,reqpathlen
- 2); /* UCS2 of path consumed minus
1173 SSVAL(pdata
,2,junction
->referral_count
); /* number of referral */
1175 SIVAL(pdata
,4,DFSREF_REFERRAL_SERVER
| DFSREF_STORAGE_SERVER
);
1177 SIVAL(pdata
,4,DFSREF_STORAGE_SERVER
);
1180 /* copy in the reqpaths */
1181 memcpy(pdata
+uni_reqpathoffset1
,uni_reqpath
,reqpathlen
);
1182 memcpy(pdata
+uni_reqpathoffset2
,uni_reqpath
,reqpathlen
);
1185 for(i
=0;i
<junction
->referral_count
;i
++) {
1186 struct referral
* ref
= &(junction
->referral_list
[i
]);
1189 SSVAL(pdata
,offset
,3); /* version 3 */
1190 SSVAL(pdata
,offset
+2,VERSION3_REFERRAL_SIZE
);
1192 SSVAL(pdata
,offset
+4,1);
1194 SSVAL(pdata
,offset
+4,0);
1197 /* ref_flags :use path_consumed bytes? */
1198 SSVAL(pdata
,offset
+6,0);
1199 SIVAL(pdata
,offset
+8,ref
->ttl
);
1201 SSVAL(pdata
,offset
+12,uni_reqpathoffset1
-offset
);
1202 SSVAL(pdata
,offset
+14,uni_reqpathoffset2
-offset
);
1203 /* copy referred path into current offset */
1204 unilen
= rpcstr_push(pdata
+uni_curroffset
,ref
->alternate_path
,
1205 reply_size
- uni_curroffset
,
1206 STR_UNICODE
| STR_TERMINATE
);
1207 SSVAL(pdata
,offset
+16,uni_curroffset
-offset
);
1208 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
1209 memset(pdata
+offset
+18,'\0',16);
1211 uni_curroffset
+= unilen
;
1212 offset
+= VERSION3_REFERRAL_SIZE
;
1217 /******************************************************************
1218 Set up the DFS referral for the dfs pathname. This call returns
1219 the amount of the path covered by this server, and where the
1220 client should be redirected to. This is the meat of the
1221 TRANS2_GET_DFS_REFERRAL call.
1222 ******************************************************************/
1224 int setup_dfs_referral(connection_struct
*orig_conn
,
1225 const char *dfs_path
,
1226 int max_referral_level
,
1227 char **ppdata
, NTSTATUS
*pstatus
)
1229 struct junction_map
*junction
= NULL
;
1230 int consumedcnt
= 0;
1231 bool self_referral
= False
;
1233 char *pathnamep
= NULL
;
1234 char *local_dfs_path
= NULL
;
1237 if (!(ctx
=talloc_init("setup_dfs_referral"))) {
1238 *pstatus
= NT_STATUS_NO_MEMORY
;
1242 /* get the junction entry */
1244 talloc_destroy(ctx
);
1245 *pstatus
= NT_STATUS_NOT_FOUND
;
1250 * Trim pathname sent by client so it begins with only one backslash.
1251 * Two backslashes confuse some dfs clients
1254 local_dfs_path
= talloc_strdup(ctx
,dfs_path
);
1255 if (!local_dfs_path
) {
1256 *pstatus
= NT_STATUS_NO_MEMORY
;
1257 talloc_destroy(ctx
);
1260 pathnamep
= local_dfs_path
;
1261 while (IS_DIRECTORY_SEP(pathnamep
[0]) &&
1262 IS_DIRECTORY_SEP(pathnamep
[1])) {
1266 junction
= TALLOC_ZERO_P(ctx
, struct junction_map
);
1268 *pstatus
= NT_STATUS_NO_MEMORY
;
1269 talloc_destroy(ctx
);
1273 /* The following call can change cwd. */
1274 *pstatus
= get_referred_path(ctx
, pathnamep
, junction
,
1275 &consumedcnt
, &self_referral
);
1276 if (!NT_STATUS_IS_OK(*pstatus
)) {
1277 vfs_ChDir(orig_conn
,orig_conn
->connectpath
);
1278 talloc_destroy(ctx
);
1281 vfs_ChDir(orig_conn
,orig_conn
->connectpath
);
1283 if (!self_referral
) {
1284 pathnamep
[consumedcnt
] = '\0';
1286 if( DEBUGLVL( 3 ) ) {
1288 dbgtext("setup_dfs_referral: Path %s to "
1289 "alternate path(s):",
1291 for(i
=0;i
<junction
->referral_count
;i
++)
1293 junction
->referral_list
[i
].alternate_path
);
1298 /* create the referral depeding on version */
1299 DEBUG(10,("max_referral_level :%d\n",max_referral_level
));
1301 if (max_referral_level
< 2) {
1302 max_referral_level
= 2;
1304 if (max_referral_level
> 3) {
1305 max_referral_level
= 3;
1308 switch(max_referral_level
) {
1310 reply_size
= setup_ver2_dfs_referral(pathnamep
,
1315 reply_size
= setup_ver3_dfs_referral(pathnamep
, ppdata
,
1316 junction
, self_referral
);
1319 DEBUG(0,("setup_dfs_referral: Invalid dfs referral "
1321 max_referral_level
));
1322 talloc_destroy(ctx
);
1323 *pstatus
= NT_STATUS_INVALID_LEVEL
;
1328 DEBUGADD(0,("DFS Referral pdata:\n"));
1329 dump_data(0,(uint8
*)*ppdata
,reply_size
);
1332 talloc_destroy(ctx
);
1333 *pstatus
= NT_STATUS_OK
;
1337 /**********************************************************************
1338 The following functions are called by the NETDFS RPC pipe functions
1339 **********************************************************************/
1341 /*********************************************************************
1342 Creates a junction structure from a DFS pathname
1343 **********************************************************************/
1345 bool create_junction(TALLOC_CTX
*ctx
,
1346 const char *dfs_path
,
1347 struct junction_map
*jucn
)
1351 struct dfs_path
*pdp
= TALLOC_P(ctx
,struct dfs_path
);
1357 status
= parse_dfs_path(NULL
, dfs_path
, False
, pdp
, &dummy
);
1358 if (!NT_STATUS_IS_OK(status
)) {
1362 /* check if path is dfs : validate first token */
1363 if (!is_myname_or_ipaddr(pdp
->hostname
)) {
1364 DEBUG(4,("create_junction: Invalid hostname %s "
1366 pdp
->hostname
, dfs_path
));
1371 /* Check for a non-DFS share */
1372 snum
= lp_servicenumber(pdp
->servicename
);
1374 if(snum
< 0 || !lp_msdfs_root(snum
)) {
1375 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1381 jucn
->service_name
= talloc_strdup(ctx
, pdp
->servicename
);
1382 jucn
->volume_name
= talloc_strdup(ctx
, pdp
->reqpath
);
1383 jucn
->comment
= talloc_strdup(ctx
, lp_comment(snum
));
1386 if (!jucn
->service_name
|| !jucn
->volume_name
|| ! jucn
->comment
) {
1392 /**********************************************************************
1393 Forms a valid Unix pathname from the junction
1394 **********************************************************************/
1396 static bool junction_to_local_path(const struct junction_map
*jucn
,
1398 connection_struct
**conn_out
,
1404 snum
= lp_servicenumber(jucn
->service_name
);
1408 status
= create_conn_struct(talloc_tos(), conn_out
, snum
,
1409 lp_pathname(snum
), NULL
, oldpath
);
1410 if (!NT_STATUS_IS_OK(status
)) {
1414 *pp_path_out
= talloc_asprintf(*conn_out
,
1418 if (!*pp_path_out
) {
1419 vfs_ChDir(*conn_out
, *oldpath
);
1420 SMB_VFS_DISCONNECT(*conn_out
);
1421 conn_free(*conn_out
);
1427 bool create_msdfs_link(const struct junction_map
*jucn
)
1431 char *msdfs_link
= NULL
;
1432 connection_struct
*conn
;
1434 bool insert_comma
= False
;
1437 if(!junction_to_local_path(jucn
, &path
, &conn
, &cwd
)) {
1441 /* Form the msdfs_link contents */
1442 msdfs_link
= talloc_strdup(conn
, "msdfs:");
1446 for(i
=0; i
<jucn
->referral_count
; i
++) {
1447 char *refpath
= jucn
->referral_list
[i
].alternate_path
;
1449 /* Alternate paths always use Windows separators. */
1450 trim_char(refpath
, '\\', '\\');
1451 if(*refpath
== '\0') {
1453 insert_comma
= False
;
1457 if (i
> 0 && insert_comma
) {
1458 msdfs_link
= talloc_asprintf_append_buffer(msdfs_link
,
1462 msdfs_link
= talloc_asprintf_append_buffer(msdfs_link
,
1470 if (!insert_comma
) {
1471 insert_comma
= True
;
1475 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1478 if(SMB_VFS_SYMLINK(conn
, msdfs_link
, path
) < 0) {
1479 if (errno
== EEXIST
) {
1480 struct smb_filename
*smb_fname
= NULL
;
1483 status
= create_synthetic_smb_fname(talloc_tos(), path
,
1486 if (!NT_STATUS_IS_OK(status
)) {
1487 errno
= map_errno_from_nt_status(status
);
1491 if(SMB_VFS_UNLINK(conn
, smb_fname
)!=0) {
1492 TALLOC_FREE(smb_fname
);
1495 TALLOC_FREE(smb_fname
);
1497 if (SMB_VFS_SYMLINK(conn
, msdfs_link
, path
) < 0) {
1498 DEBUG(1,("create_msdfs_link: symlink failed "
1499 "%s -> %s\nError: %s\n",
1500 path
, msdfs_link
, strerror(errno
)));
1508 vfs_ChDir(conn
, cwd
);
1509 SMB_VFS_DISCONNECT(conn
);
1514 bool remove_msdfs_link(const struct junction_map
*jucn
)
1518 connection_struct
*conn
;
1520 struct smb_filename
*smb_fname
= NULL
;
1523 if (!junction_to_local_path(jucn
, &path
, &conn
, &cwd
)) {
1527 status
= create_synthetic_smb_fname(talloc_tos(), path
,
1530 if (!NT_STATUS_IS_OK(status
)) {
1531 errno
= map_errno_from_nt_status(status
);
1535 if( SMB_VFS_UNLINK(conn
, smb_fname
) == 0 ) {
1539 TALLOC_FREE(smb_fname
);
1540 vfs_ChDir(conn
, cwd
);
1541 SMB_VFS_DISCONNECT(conn
);
1546 /*********************************************************************
1547 Return the number of DFS links at the root of this share.
1548 *********************************************************************/
1550 static int count_dfs_links(TALLOC_CTX
*ctx
, int snum
)
1553 SMB_STRUCT_DIR
*dirp
= NULL
;
1554 const char *dname
= NULL
;
1555 char *talloced
= NULL
;
1556 const char *connect_path
= lp_pathname(snum
);
1557 const char *msdfs_proxy
= lp_msdfs_proxy(snum
);
1558 connection_struct
*conn
;
1562 if(*connect_path
== '\0') {
1567 * Fake up a connection struct for the VFS layer.
1570 status
= create_conn_struct(talloc_tos(), &conn
, snum
, connect_path
,
1572 if (!NT_STATUS_IS_OK(status
)) {
1573 DEBUG(3, ("create_conn_struct failed: %s\n",
1574 nt_errstr(status
)));
1578 /* Count a link for the msdfs root - convention */
1581 /* No more links if this is an msdfs proxy. */
1582 if (*msdfs_proxy
!= '\0') {
1586 /* Now enumerate all dfs links */
1587 dirp
= SMB_VFS_OPENDIR(conn
, ".", NULL
, 0);
1592 while ((dname
= vfs_readdirname(conn
, dirp
, NULL
, &talloced
))
1594 if (is_msdfs_link(conn
,
1599 TALLOC_FREE(talloced
);
1602 SMB_VFS_CLOSEDIR(conn
,dirp
);
1605 vfs_ChDir(conn
, cwd
);
1606 SMB_VFS_DISCONNECT(conn
);
1611 /*********************************************************************
1612 *********************************************************************/
1614 static int form_junctions(TALLOC_CTX
*ctx
,
1616 struct junction_map
*jucn
,
1620 SMB_STRUCT_DIR
*dirp
= NULL
;
1621 const char *dname
= NULL
;
1622 char *talloced
= NULL
;
1623 const char *connect_path
= lp_pathname(snum
);
1624 char *service_name
= lp_servicename(snum
);
1625 const char *msdfs_proxy
= lp_msdfs_proxy(snum
);
1626 connection_struct
*conn
;
1627 struct referral
*ref
= NULL
;
1631 if (jn_remain
== 0) {
1635 if(*connect_path
== '\0') {
1640 * Fake up a connection struct for the VFS layer.
1643 status
= create_conn_struct(ctx
, &conn
, snum
, connect_path
, NULL
,
1645 if (!NT_STATUS_IS_OK(status
)) {
1646 DEBUG(3, ("create_conn_struct failed: %s\n",
1647 nt_errstr(status
)));
1651 /* form a junction for the msdfs root - convention
1652 DO NOT REMOVE THIS: NT clients will not work with us
1653 if this is not present
1655 jucn
[cnt
].service_name
= talloc_strdup(ctx
,service_name
);
1656 jucn
[cnt
].volume_name
= talloc_strdup(ctx
, "");
1657 if (!jucn
[cnt
].service_name
|| !jucn
[cnt
].volume_name
) {
1660 jucn
[cnt
].comment
= "";
1661 jucn
[cnt
].referral_count
= 1;
1663 ref
= jucn
[cnt
].referral_list
= TALLOC_ZERO_P(ctx
, struct referral
);
1664 if (jucn
[cnt
].referral_list
== NULL
) {
1669 ref
->ttl
= REFERRAL_TTL
;
1670 if (*msdfs_proxy
!= '\0') {
1671 ref
->alternate_path
= talloc_strdup(ctx
,
1674 ref
->alternate_path
= talloc_asprintf(ctx
,
1676 get_local_machine_name(),
1680 if (!ref
->alternate_path
) {
1685 /* Don't enumerate if we're an msdfs proxy. */
1686 if (*msdfs_proxy
!= '\0') {
1690 /* Now enumerate all dfs links */
1691 dirp
= SMB_VFS_OPENDIR(conn
, ".", NULL
, 0);
1696 while ((dname
= vfs_readdirname(conn
, dirp
, NULL
, &talloced
))
1698 char *link_target
= NULL
;
1699 if (cnt
>= jn_remain
) {
1700 DEBUG(2, ("form_junctions: ran out of MSDFS "
1702 TALLOC_FREE(talloced
);
1705 if (is_msdfs_link_internal(ctx
,
1707 dname
, &link_target
,
1709 if (parse_msdfs_symlink(ctx
,
1711 &jucn
[cnt
].referral_list
,
1712 &jucn
[cnt
].referral_count
)) {
1714 jucn
[cnt
].service_name
= talloc_strdup(ctx
,
1716 jucn
[cnt
].volume_name
= talloc_strdup(ctx
,
1718 if (!jucn
[cnt
].service_name
||
1719 !jucn
[cnt
].volume_name
) {
1720 TALLOC_FREE(talloced
);
1723 jucn
[cnt
].comment
= "";
1726 TALLOC_FREE(link_target
);
1728 TALLOC_FREE(talloced
);
1734 SMB_VFS_CLOSEDIR(conn
,dirp
);
1737 vfs_ChDir(conn
, cwd
);
1742 struct junction_map
*enum_msdfs_links(TALLOC_CTX
*ctx
, size_t *p_num_jn
)
1744 struct junction_map
*jn
= NULL
;
1746 size_t jn_count
= 0;
1750 if(!lp_host_msdfs()) {
1754 /* Ensure all the usershares are loaded. */
1756 load_registry_shares();
1757 sharecount
= load_usershare_shares();
1760 for(i
=0;i
< sharecount
;i
++) {
1761 if(lp_msdfs_root(i
)) {
1762 jn_count
+= count_dfs_links(ctx
, i
);
1765 if (jn_count
== 0) {
1768 jn
= TALLOC_ARRAY(ctx
, struct junction_map
, jn_count
);
1772 for(i
=0; i
< sharecount
; i
++) {
1773 if (*p_num_jn
>= jn_count
) {
1776 if(lp_msdfs_root(i
)) {
1777 *p_num_jn
+= form_junctions(ctx
, i
,
1779 jn_count
- *p_num_jn
);
1785 /******************************************************************************
1786 Core function to resolve a dfs pathname possibly containing a wildcard. If
1787 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1788 detected during dfs resolution.
1789 ******************************************************************************/
1791 NTSTATUS
resolve_dfspath_wcard(TALLOC_CTX
*ctx
,
1792 connection_struct
*conn
,
1794 const char *name_in
,
1797 bool *ppath_contains_wcard
)
1799 bool path_contains_wcard
;
1800 NTSTATUS status
= NT_STATUS_OK
;
1802 if (dfs_pathnames
) {
1803 status
= dfs_redirect(ctx
,
1808 &path_contains_wcard
);
1810 if (NT_STATUS_IS_OK(status
) && ppath_contains_wcard
!= NULL
) {
1811 *ppath_contains_wcard
= path_contains_wcard
;
1815 * Cheat and just return a copy of the in ptr.
1816 * Once srvstr_get_path() uses talloc it'll
1817 * be a talloced ptr anyway.
1819 *pp_name_out
= CONST_DISCARD(char *,name_in
);