2 Unix SMB/Netbios implementation.
4 MSDFS services for Samba
5 Copyright (C) Shirish Kalele 2000
6 Copyright (C) Jeremy Allison 2007
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #define DBGC_CLASS DBGC_MSDFS
25 #include "system/filesys.h"
26 #include "smbd/smbd.h"
27 #include "smbd/globals.h"
30 #include "lib/param/loadparm.h"
31 #include "libcli/security/security.h"
33 /**********************************************************************
34 Parse a DFS pathname of the form \hostname\service\reqpath
35 into the dfs_path structure.
36 If POSIX pathnames is true, the pathname may also be of the
37 form /hostname/service/reqpath.
38 We cope with either here.
40 Unfortunately, due to broken clients who might set the
41 SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
42 send a local path, we have to cope with that too....
44 If conn != NULL then ensure the provided service is
45 the one pointed to by the connection.
47 This version does everything using pointers within one copy of the
48 pathname string, talloced on the struct dfs_path pointer (which
49 must be talloced). This may be too clever to live....
51 **********************************************************************/
53 static NTSTATUS
parse_dfs_path(connection_struct
*conn
,
56 struct dfs_path
*pdp
, /* MUST BE TALLOCED */
57 bool *ppath_contains_wcard
)
59 struct smbd_server_connection
*sconn
= smbd_server_conn
;
64 NTSTATUS status
= NT_STATUS_OK
;
70 * This is the only talloc we should need to do
71 * on the struct dfs_path. All the pointers inside
72 * it should point to offsets within this string.
75 pathname_local
= talloc_strdup(pdp
, pathname
);
76 if (!pathname_local
) {
77 return NT_STATUS_NO_MEMORY
;
79 /* Get a pointer to the terminating '\0' */
80 eos_ptr
= &pathname_local
[strlen(pathname_local
)];
81 p
= temp
= pathname_local
;
83 pdp
->posix_path
= (lp_posix_pathnames() && *pathname
== '/');
85 sepchar
= pdp
->posix_path
? '/' : '\\';
87 if (!sconn
->using_smb2
&& (*pathname
!= sepchar
)) {
88 DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
91 * Possibly client sent a local path by mistake.
92 * Try and convert to a local path.
95 pdp
->hostname
= eos_ptr
; /* "" */
96 pdp
->servicename
= eos_ptr
; /* "" */
98 /* We've got no info about separators. */
99 pdp
->posix_path
= lp_posix_pathnames();
101 DEBUG(10,("parse_dfs_path: trying to convert %s to a "
108 * Safe to use on talloc'ed string as it only shrinks.
109 * It also doesn't affect the eos_ptr.
111 trim_char(temp
,sepchar
,sepchar
);
113 DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
117 /* Parse out hostname. */
118 p
= strchr_m(temp
,sepchar
);
120 DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
123 * Possibly client sent a local path by mistake.
124 * Try and convert to a local path.
127 pdp
->hostname
= eos_ptr
; /* "" */
128 pdp
->servicename
= eos_ptr
; /* "" */
131 DEBUG(10,("parse_dfs_path: trying to convert %s "
137 pdp
->hostname
= temp
;
139 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp
->hostname
));
141 /* Parse out servicename. */
143 p
= strchr_m(servicename
,sepchar
);
148 /* Is this really our servicename ? */
149 if (conn
&& !( strequal(servicename
, lp_servicename(SNUM(conn
)))
150 || (strequal(servicename
, HOMES_NAME
)
151 && strequal(lp_servicename(SNUM(conn
)),
152 get_current_username()) )) ) {
153 DEBUG(10,("parse_dfs_path: %s is not our servicename\n",
157 * Possibly client sent a local path by mistake.
158 * Try and convert to a local path.
161 pdp
->hostname
= eos_ptr
; /* "" */
162 pdp
->servicename
= eos_ptr
; /* "" */
164 /* Repair the path - replace the sepchar's
167 *servicename
= sepchar
;
173 DEBUG(10,("parse_dfs_path: trying to convert %s "
179 pdp
->servicename
= servicename
;
181 DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp
->servicename
));
184 /* Client sent self referral \server\share. */
185 pdp
->reqpath
= eos_ptr
; /* "" */
193 *ppath_contains_wcard
= False
;
197 /* Rest is reqpath. */
198 if (pdp
->posix_path
) {
199 status
= check_path_syntax_posix(pdp
->reqpath
);
202 status
= check_path_syntax_wcard(pdp
->reqpath
,
203 ppath_contains_wcard
);
205 status
= check_path_syntax(pdp
->reqpath
);
209 if (!NT_STATUS_IS_OK(status
)) {
210 DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
211 p
, nt_errstr(status
) ));
215 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp
->reqpath
));
219 /********************************************************
220 Fake up a connection struct for the VFS layer.
221 Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
222 *********************************************************/
224 NTSTATUS
create_conn_struct(TALLOC_CTX
*ctx
,
225 connection_struct
**pconn
,
228 const struct auth_session_info
*session_info
,
231 connection_struct
*conn
;
234 const char *vfs_user
;
236 conn
= talloc_zero(ctx
, connection_struct
);
238 return NT_STATUS_NO_MEMORY
;
241 connpath
= talloc_strdup(conn
, path
);
244 return NT_STATUS_NO_MEMORY
;
246 connpath
= talloc_string_sub(conn
,
249 lp_servicename(snum
));
252 return NT_STATUS_NO_MEMORY
;
255 /* needed for smbd_vfs_init() */
257 if (!(conn
->params
= talloc_zero(conn
, struct share_params
))) {
258 DEBUG(0, ("TALLOC failed\n"));
260 return NT_STATUS_NO_MEMORY
;
263 conn
->params
->service
= snum
;
265 conn
->sconn
= smbd_server_conn
;
266 conn
->sconn
->num_tcons_open
++;
268 if (session_info
!= NULL
) {
269 conn
->session_info
= copy_session_info(conn
, session_info
);
270 if (conn
->session_info
== NULL
) {
271 DEBUG(0, ("copy_serverinfo failed\n"));
273 return NT_STATUS_NO_MEMORY
;
275 vfs_user
= conn
->session_info
->unix_info
->unix_name
;
277 /* use current authenticated user in absence of session_info */
278 vfs_user
= get_current_username();
281 set_conn_connectpath(conn
, connpath
);
284 * New code to check if there's a share security descripter
285 * added from NT server manager. This is done after the
286 * smb.conf checks are done as we need a uid and token. JRA.
289 if (conn
->session_info
) {
290 share_access_check(conn
->session_info
->security_token
,
291 lp_servicename(snum
), MAXIMUM_ALLOWED_ACCESS
,
292 &conn
->share_access
);
294 if ((conn
->share_access
& FILE_WRITE_DATA
) == 0) {
295 if ((conn
->share_access
& FILE_READ_DATA
) == 0) {
296 /* No access, read or write. */
297 DEBUG(0,("create_conn_struct: connection to %s "
298 "denied due to security "
300 lp_servicename(snum
)));
302 return NT_STATUS_ACCESS_DENIED
;
304 conn
->read_only
= true;
308 conn
->share_access
= 0;
309 conn
->read_only
= true;
312 if (!smbd_vfs_init(conn
)) {
313 NTSTATUS status
= map_nt_error_from_unix(errno
);
314 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
319 /* this must be the first filesystem operation that we do */
320 if (SMB_VFS_CONNECT(conn
, lp_servicename(snum
), vfs_user
) < 0) {
321 DEBUG(0,("VFS connect failed!\n"));
323 return NT_STATUS_UNSUCCESSFUL
;
326 conn
->fs_capabilities
= SMB_VFS_FS_CAPABILITIES(conn
, &conn
->ts_res
);
329 * Windows seems to insist on doing trans2getdfsreferral() calls on
330 * the IPC$ share as the anonymous user. If we try to chdir as that
331 * user we will fail.... WTF ? JRA.
334 oldcwd
= vfs_GetWd(ctx
, conn
);
335 if (oldcwd
== NULL
) {
336 NTSTATUS status
= map_nt_error_from_unix(errno
);
337 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno
)));
342 if (vfs_ChDir(conn
,conn
->connectpath
) != 0) {
343 NTSTATUS status
= map_nt_error_from_unix(errno
);
344 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
346 conn
->connectpath
, strerror(errno
) ));
357 /**********************************************************************
358 Parse the contents of a symlink to verify if it is an msdfs referral
359 A valid referral is of the form:
361 msdfs:server1\share1,server2\share2
362 msdfs:server1\share1\pathname,server2\share2\pathname
363 msdfs:server1/share1,server2/share2
364 msdfs:server1/share1/pathname,server2/share2/pathname.
366 Note that the alternate paths returned here must be of the canonicalized
370 \server\share\path\to\file,
372 even in posix path mode. This is because we have no knowledge if the
373 server we're referring to understands posix paths.
374 **********************************************************************/
376 static bool parse_msdfs_symlink(TALLOC_CTX
*ctx
,
378 struct referral
**preflist
,
383 char **alt_path
= NULL
;
385 struct referral
*reflist
;
388 temp
= talloc_strdup(ctx
, target
);
392 prot
= strtok_r(temp
, ":", &saveptr
);
394 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
398 alt_path
= talloc_array(ctx
, char *, MAX_REFERRAL_COUNT
);
403 /* parse out the alternate paths */
404 while((count
<MAX_REFERRAL_COUNT
) &&
405 ((alt_path
[count
] = strtok_r(NULL
, ",", &saveptr
)) != NULL
)) {
409 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count
));
412 reflist
= *preflist
= talloc_zero_array(ctx
,
413 struct referral
, count
);
414 if(reflist
== NULL
) {
415 TALLOC_FREE(alt_path
);
419 reflist
= *preflist
= NULL
;
422 for(i
=0;i
<count
;i
++) {
425 /* Canonicalize link target.
426 * Replace all /'s in the path by a \ */
427 string_replace(alt_path
[i
], '/', '\\');
429 /* Remove leading '\\'s */
431 while (*p
&& (*p
== '\\')) {
435 reflist
[i
].alternate_path
= talloc_asprintf(ctx
,
438 if (!reflist
[i
].alternate_path
) {
442 reflist
[i
].proximity
= 0;
443 reflist
[i
].ttl
= REFERRAL_TTL
;
444 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
445 reflist
[i
].alternate_path
));
450 TALLOC_FREE(alt_path
);
454 /**********************************************************************
455 Returns true if the unix path is a valid msdfs symlink and also
456 returns the target string from inside the link.
457 **********************************************************************/
459 static bool is_msdfs_link_internal(TALLOC_CTX
*ctx
,
460 connection_struct
*conn
,
462 char **pp_link_target
,
463 SMB_STRUCT_STAT
*sbufp
)
465 int referral_len
= 0;
466 #if defined(HAVE_BROKEN_READLINK)
467 char link_target_buf
[PATH_MAX
];
469 char link_target_buf
[7];
472 char *link_target
= NULL
;
473 struct smb_filename smb_fname
;
475 if (pp_link_target
) {
477 link_target
= talloc_array(ctx
, char, bufsize
);
481 *pp_link_target
= link_target
;
483 bufsize
= sizeof(link_target_buf
);
484 link_target
= link_target_buf
;
487 ZERO_STRUCT(smb_fname
);
488 smb_fname
.base_name
= discard_const_p(char, path
);
490 if (SMB_VFS_LSTAT(conn
, &smb_fname
) != 0) {
491 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
495 if (!S_ISLNK(smb_fname
.st
.st_ex_mode
)) {
496 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
501 *sbufp
= smb_fname
.st
;
504 referral_len
= SMB_VFS_READLINK(conn
, path
, link_target
, bufsize
- 1);
505 if (referral_len
== -1) {
506 DEBUG(0,("is_msdfs_link_read_target: Error reading "
507 "msdfs link %s: %s\n",
508 path
, strerror(errno
)));
511 link_target
[referral_len
] = '\0';
513 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path
,
516 if (!strnequal(link_target
, "msdfs:", 6)) {
523 if (link_target
!= link_target_buf
) {
524 TALLOC_FREE(link_target
);
529 /**********************************************************************
530 Returns true if the unix path is a valid msdfs symlink.
531 **********************************************************************/
533 bool is_msdfs_link(connection_struct
*conn
,
535 SMB_STRUCT_STAT
*sbufp
)
537 return is_msdfs_link_internal(talloc_tos(),
544 /*****************************************************************
545 Used by other functions to decide if a dfs path is remote,
546 and to get the list of referred locations for that remote path.
548 search_flag: For findfirsts, dfs links themselves are not
549 redirected, but paths beyond the links are. For normal smb calls,
550 even dfs links need to be redirected.
552 consumedcntp: how much of the dfs path is being redirected. the client
553 should try the remaining path on the redirected server.
555 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
556 link redirect are in targetpath.
557 *****************************************************************/
559 static NTSTATUS
dfs_path_lookup(TALLOC_CTX
*ctx
,
560 connection_struct
*conn
,
561 const char *dfspath
, /* Incoming complete dfs path */
562 const struct dfs_path
*pdp
, /* Parsed out
563 server+share+extrapath. */
564 bool search_flag
, /* Called from a findfirst ? */
566 char **pp_targetpath
)
571 struct smb_filename
*smb_fname
= NULL
;
572 char *canon_dfspath
= NULL
; /* Canonicalized dfs path. (only '/'
575 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
576 conn
->connectpath
, pdp
->reqpath
));
579 * Note the unix path conversion here we're doing we can
580 * throw away. We're looking for a symlink for a dfs
581 * resolution, if we don't find it we'll do another
582 * unix_convert later in the codepath.
583 * If we needed to remember what we'd resolved in
584 * dp->reqpath (as the original code did) we'd
585 * copy (localhost, dp->reqpath) on any code
586 * path below that returns True - but I don't
587 * think this is needed. JRA.
590 status
= unix_convert(ctx
, conn
, pdp
->reqpath
, &smb_fname
,
591 search_flag
? UCF_ALWAYS_ALLOW_WCARD_LCOMP
: 0);
593 if (!NT_STATUS_IS_OK(status
)) {
594 if (!NT_STATUS_EQUAL(status
,
595 NT_STATUS_OBJECT_PATH_NOT_FOUND
)) {
599 /* Create an smb_fname to use below. */
600 status
= create_synthetic_smb_fname(ctx
, pdp
->reqpath
, NULL
,
602 if (!NT_STATUS_IS_OK(status
)) {
607 /* Optimization - check if we can redirect the whole path. */
609 if (is_msdfs_link_internal(ctx
, conn
, smb_fname
->base_name
,
610 pp_targetpath
, NULL
)) {
612 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
613 "for dfs link %s.\n", dfspath
));
614 status
= NT_STATUS_OK
;
618 DEBUG(6,("dfs_path_lookup: %s resolves to a "
619 "valid dfs link %s.\n", dfspath
,
620 pp_targetpath
? *pp_targetpath
: ""));
623 *consumedcntp
= strlen(dfspath
);
625 status
= NT_STATUS_PATH_NOT_COVERED
;
629 /* Prepare to test only for '/' components in the given path,
630 * so if a Windows path replace all '\\' characters with '/'.
631 * For a POSIX DFS path we know all separators are already '/'. */
633 canon_dfspath
= talloc_strdup(ctx
, dfspath
);
634 if (!canon_dfspath
) {
635 status
= NT_STATUS_NO_MEMORY
;
638 if (!pdp
->posix_path
) {
639 string_replace(canon_dfspath
, '\\', '/');
643 * localpath comes out of unix_convert, so it has
644 * no trailing backslash. Make sure that canon_dfspath hasn't either.
645 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
648 trim_char(canon_dfspath
,0,'/');
651 * Redirect if any component in the path is a link.
652 * We do this by walking backwards through the
653 * local path, chopping off the last component
654 * in both the local path and the canonicalized
655 * DFS path. If we hit a DFS link then we're done.
658 p
= strrchr_m(smb_fname
->base_name
, '/');
660 q
= strrchr_m(canon_dfspath
, '/');
669 if (is_msdfs_link_internal(ctx
, conn
,
670 smb_fname
->base_name
, pp_targetpath
,
672 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
673 "parent %s is dfs link\n", dfspath
,
674 smb_fname_str_dbg(smb_fname
)));
677 *consumedcntp
= strlen(canon_dfspath
);
678 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
684 status
= NT_STATUS_PATH_NOT_COVERED
;
688 /* Step back on the filesystem. */
689 p
= strrchr_m(smb_fname
->base_name
, '/');
692 /* And in the canonicalized dfs path. */
693 q
= strrchr_m(canon_dfspath
, '/');
697 status
= NT_STATUS_OK
;
699 TALLOC_FREE(smb_fname
);
703 /*****************************************************************
704 Decides if a dfs pathname should be redirected or not.
705 If not, the pathname is converted to a tcon-relative local unix path
707 search_wcard_flag: this flag performs 2 functions both related
708 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
711 This function can return NT_STATUS_OK, meaning use the returned path as-is
712 (mapped into a local path).
713 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
714 any other NT_STATUS error which is a genuine error to be
715 returned to the client.
716 *****************************************************************/
718 static NTSTATUS
dfs_redirect(TALLOC_CTX
*ctx
,
719 connection_struct
*conn
,
721 bool search_wcard_flag
,
723 bool *ppath_contains_wcard
)
726 struct dfs_path
*pdp
= talloc(ctx
, struct dfs_path
);
729 return NT_STATUS_NO_MEMORY
;
732 status
= parse_dfs_path(conn
, path_in
, search_wcard_flag
, pdp
,
733 ppath_contains_wcard
);
734 if (!NT_STATUS_IS_OK(status
)) {
739 if (pdp
->reqpath
[0] == '\0') {
741 *pp_path_out
= talloc_strdup(ctx
, "");
743 return NT_STATUS_NO_MEMORY
;
745 DEBUG(5,("dfs_redirect: self-referral.\n"));
749 /* If dfs pathname for a non-dfs share, convert to tcon-relative
750 path and return OK */
752 if (!lp_msdfs_root(SNUM(conn
))) {
753 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
756 return NT_STATUS_NO_MEMORY
;
761 /* If it looked like a local path (zero hostname/servicename)
762 * just treat as a tcon-relative path. */
764 if (pdp
->hostname
[0] == '\0' && pdp
->servicename
[0] == '\0') {
765 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
768 return NT_STATUS_NO_MEMORY
;
773 if (!( strequal(pdp
->servicename
, lp_servicename(SNUM(conn
)))
774 || (strequal(pdp
->servicename
, HOMES_NAME
)
775 && strequal(lp_servicename(SNUM(conn
)),
776 conn
->session_info
->unix_info
->sanitized_username
) )) ) {
778 /* The given sharename doesn't match this connection. */
781 return NT_STATUS_OBJECT_PATH_NOT_FOUND
;
784 status
= dfs_path_lookup(ctx
, conn
, path_in
, pdp
,
785 search_wcard_flag
, NULL
, NULL
);
786 if (!NT_STATUS_IS_OK(status
)) {
787 if (NT_STATUS_EQUAL(status
, NT_STATUS_PATH_NOT_COVERED
)) {
788 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in
));
790 DEBUG(10,("dfs_redirect: dfs_path_lookup "
791 "failed for %s with %s\n",
792 path_in
, nt_errstr(status
) ));
797 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in
));
799 /* Form non-dfs tcon-relative path */
800 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
803 return NT_STATUS_NO_MEMORY
;
806 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
813 /**********************************************************************
814 Return a self referral.
815 **********************************************************************/
817 static NTSTATUS
self_ref(TALLOC_CTX
*ctx
,
818 const char *dfs_path
,
819 struct junction_map
*jucn
,
821 bool *self_referralp
)
823 struct referral
*ref
;
825 *self_referralp
= True
;
827 jucn
->referral_count
= 1;
828 if((ref
= talloc_zero(ctx
, struct referral
)) == NULL
) {
829 return NT_STATUS_NO_MEMORY
;
832 ref
->alternate_path
= talloc_strdup(ctx
, dfs_path
);
833 if (!ref
->alternate_path
) {
834 return NT_STATUS_NO_MEMORY
;
837 ref
->ttl
= REFERRAL_TTL
;
838 jucn
->referral_list
= ref
;
839 *consumedcntp
= strlen(dfs_path
);
843 /**********************************************************************
844 Gets valid referrals for a dfs path and fills up the
845 junction_map structure.
846 **********************************************************************/
848 NTSTATUS
get_referred_path(TALLOC_CTX
*ctx
,
849 const char *dfs_path
,
850 struct junction_map
*jucn
,
852 bool *self_referralp
)
854 struct connection_struct
*conn
;
855 char *targetpath
= NULL
;
857 NTSTATUS status
= NT_STATUS_NOT_FOUND
;
859 struct dfs_path
*pdp
= talloc(ctx
, struct dfs_path
);
863 return NT_STATUS_NO_MEMORY
;
866 *self_referralp
= False
;
868 status
= parse_dfs_path(NULL
, dfs_path
, False
, pdp
, &dummy
);
869 if (!NT_STATUS_IS_OK(status
)) {
873 jucn
->service_name
= talloc_strdup(ctx
, pdp
->servicename
);
874 jucn
->volume_name
= talloc_strdup(ctx
, pdp
->reqpath
);
875 if (!jucn
->service_name
|| !jucn
->volume_name
) {
877 return NT_STATUS_NO_MEMORY
;
880 /* Verify the share is a dfs root */
881 snum
= lp_servicenumber(jucn
->service_name
);
883 char *service_name
= NULL
;
884 if ((snum
= find_service(ctx
, jucn
->service_name
, &service_name
)) < 0) {
885 return NT_STATUS_NOT_FOUND
;
888 return NT_STATUS_NO_MEMORY
;
890 TALLOC_FREE(jucn
->service_name
);
891 jucn
->service_name
= talloc_strdup(ctx
, service_name
);
892 if (!jucn
->service_name
) {
894 return NT_STATUS_NO_MEMORY
;
898 if (!lp_msdfs_root(snum
) && (*lp_msdfs_proxy(snum
) == '\0')) {
899 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
901 pdp
->servicename
, dfs_path
));
903 return NT_STATUS_NOT_FOUND
;
907 * Self referrals are tested with a anonymous IPC connection and
908 * a GET_DFS_REFERRAL call to \\server\share. (which means
909 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
910 * into the directory and will fail if it cannot (as the anonymous
911 * user). Cope with this.
914 if (pdp
->reqpath
[0] == '\0') {
916 struct referral
*ref
;
918 if (*lp_msdfs_proxy(snum
) == '\0') {
928 * It's an msdfs proxy share. Redirect to
929 * the configured target share.
932 jucn
->referral_count
= 1;
933 if ((ref
= talloc_zero(ctx
, struct referral
)) == NULL
) {
935 return NT_STATUS_NO_MEMORY
;
938 if (!(tmp
= talloc_strdup(ctx
, lp_msdfs_proxy(snum
)))) {
940 return NT_STATUS_NO_MEMORY
;
943 trim_string(tmp
, "\\", 0);
945 ref
->alternate_path
= talloc_asprintf(ctx
, "\\%s", tmp
);
948 if (!ref
->alternate_path
) {
950 return NT_STATUS_NO_MEMORY
;
953 if (pdp
->reqpath
[0] != '\0') {
954 ref
->alternate_path
= talloc_asprintf_append(
958 if (!ref
->alternate_path
) {
960 return NT_STATUS_NO_MEMORY
;
964 ref
->ttl
= REFERRAL_TTL
;
965 jucn
->referral_list
= ref
;
966 *consumedcntp
= strlen(dfs_path
);
971 status
= create_conn_struct(ctx
, &conn
, snum
, lp_pathname(snum
),
973 if (!NT_STATUS_IS_OK(status
)) {
978 /* If this is a DFS path dfs_lookup should return
979 * NT_STATUS_PATH_NOT_COVERED. */
981 status
= dfs_path_lookup(ctx
, conn
, dfs_path
, pdp
,
982 False
, consumedcntp
, &targetpath
);
984 if (!NT_STATUS_EQUAL(status
, NT_STATUS_PATH_NOT_COVERED
)) {
985 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
990 /* We know this is a valid dfs link. Parse the targetpath. */
991 if (!parse_msdfs_symlink(ctx
, targetpath
,
992 &jucn
->referral_list
,
993 &jucn
->referral_count
)) {
994 DEBUG(3,("get_referred_path: failed to parse symlink "
995 "target %s\n", targetpath
));
996 status
= NT_STATUS_NOT_FOUND
;
1000 status
= NT_STATUS_OK
;
1002 vfs_ChDir(conn
, oldpath
);
1003 SMB_VFS_DISCONNECT(conn
);
1009 static int setup_ver2_dfs_referral(const char *pathname
,
1011 struct junction_map
*junction
,
1014 char* pdata
= *ppdata
;
1016 smb_ucs2_t
*uni_requestedpath
= NULL
;
1017 int uni_reqpathoffset1
,uni_reqpathoffset2
;
1019 int requestedpathlen
=0;
1024 DEBUG(10,("Setting up version2 referral\nRequested path:\n"));
1026 requestedpathlen
= rpcstr_push_talloc(talloc_tos(),
1027 &uni_requestedpath
, pathname
);
1028 if (uni_requestedpath
== NULL
|| requestedpathlen
== 0) {
1033 dump_data(0, (unsigned char *)uni_requestedpath
,
1037 DEBUG(10,("ref count = %u\n",junction
->referral_count
));
1039 uni_reqpathoffset1
= REFERRAL_HEADER_SIZE
+
1040 VERSION2_REFERRAL_SIZE
* junction
->referral_count
;
1042 uni_reqpathoffset2
= uni_reqpathoffset1
+ requestedpathlen
;
1044 uni_curroffset
= uni_reqpathoffset2
+ requestedpathlen
;
1046 reply_size
= REFERRAL_HEADER_SIZE
+
1047 VERSION2_REFERRAL_SIZE
*junction
->referral_count
+
1048 2 * requestedpathlen
;
1049 DEBUG(10,("reply_size: %u\n",reply_size
));
1051 /* add up the unicode lengths of all the referral paths */
1052 for(i
=0;i
<junction
->referral_count
;i
++) {
1053 DEBUG(10,("referral %u : %s\n",
1055 junction
->referral_list
[i
].alternate_path
));
1057 (strlen(junction
->referral_list
[i
].alternate_path
)+1)*2;
1060 DEBUG(10,("reply_size = %u\n",reply_size
));
1061 /* add the unexplained 0x16 bytes */
1064 pdata
= (char *)SMB_REALLOC(pdata
,reply_size
);
1066 DEBUG(0,("Realloc failed!\n"));
1071 /* copy in the dfs requested paths.. required for offset calculations */
1072 memcpy(pdata
+uni_reqpathoffset1
,uni_requestedpath
,requestedpathlen
);
1073 memcpy(pdata
+uni_reqpathoffset2
,uni_requestedpath
,requestedpathlen
);
1075 /* create the header */
1076 SSVAL(pdata
,0,requestedpathlen
- 2); /* UCS2 of path consumed minus
1078 /* number of referral in this pkt */
1079 SSVAL(pdata
,2,junction
->referral_count
);
1081 SIVAL(pdata
,4,DFSREF_REFERRAL_SERVER
| DFSREF_STORAGE_SERVER
);
1083 SIVAL(pdata
,4,DFSREF_STORAGE_SERVER
);
1087 /* add the referral elements */
1088 for(i
=0;i
<junction
->referral_count
;i
++) {
1089 struct referral
* ref
= &junction
->referral_list
[i
];
1092 SSVAL(pdata
,offset
,2); /* version 2 */
1093 SSVAL(pdata
,offset
+2,VERSION2_REFERRAL_SIZE
);
1095 SSVAL(pdata
,offset
+4,1);
1097 SSVAL(pdata
,offset
+4,0);
1100 /* ref_flags :use path_consumed bytes? */
1101 SSVAL(pdata
,offset
+6,0);
1102 SIVAL(pdata
,offset
+8,ref
->proximity
);
1103 SIVAL(pdata
,offset
+12,ref
->ttl
);
1105 SSVAL(pdata
,offset
+16,uni_reqpathoffset1
-offset
);
1106 SSVAL(pdata
,offset
+18,uni_reqpathoffset2
-offset
);
1107 /* copy referred path into current offset */
1108 unilen
= rpcstr_push(pdata
+uni_curroffset
,
1109 ref
->alternate_path
,
1110 reply_size
- uni_curroffset
,
1113 SSVAL(pdata
,offset
+20,uni_curroffset
-offset
);
1115 uni_curroffset
+= unilen
;
1116 offset
+= VERSION2_REFERRAL_SIZE
;
1118 /* add in the unexplained 22 (0x16) bytes at the end */
1119 memset(pdata
+uni_curroffset
,'\0',0x16);
1123 static int setup_ver3_dfs_referral(const char *pathname
,
1125 struct junction_map
*junction
,
1128 char *pdata
= *ppdata
;
1130 smb_ucs2_t
*uni_reqpath
= NULL
;
1131 int uni_reqpathoffset1
, uni_reqpathoffset2
;
1138 DEBUG(10,("setting up version3 referral\n"));
1140 reqpathlen
= rpcstr_push_talloc(talloc_tos(), &uni_reqpath
, pathname
);
1141 if (uni_reqpath
== NULL
|| reqpathlen
== 0) {
1146 dump_data(0, (unsigned char *)uni_reqpath
,
1150 uni_reqpathoffset1
= REFERRAL_HEADER_SIZE
+
1151 VERSION3_REFERRAL_SIZE
* junction
->referral_count
;
1152 uni_reqpathoffset2
= uni_reqpathoffset1
+ reqpathlen
;
1153 reply_size
= uni_curroffset
= uni_reqpathoffset2
+ reqpathlen
;
1155 for(i
=0;i
<junction
->referral_count
;i
++) {
1156 DEBUG(10,("referral %u : %s\n",
1158 junction
->referral_list
[i
].alternate_path
));
1160 (strlen(junction
->referral_list
[i
].alternate_path
)+1)*2;
1163 pdata
= (char *)SMB_REALLOC(pdata
,reply_size
);
1165 DEBUG(0,("version3 referral setup:"
1166 "malloc failed for Realloc!\n"));
1171 /* create the header */
1172 SSVAL(pdata
,0,reqpathlen
- 2); /* UCS2 of path consumed minus
1174 SSVAL(pdata
,2,junction
->referral_count
); /* number of referral */
1176 SIVAL(pdata
,4,DFSREF_REFERRAL_SERVER
| DFSREF_STORAGE_SERVER
);
1178 SIVAL(pdata
,4,DFSREF_STORAGE_SERVER
);
1181 /* copy in the reqpaths */
1182 memcpy(pdata
+uni_reqpathoffset1
,uni_reqpath
,reqpathlen
);
1183 memcpy(pdata
+uni_reqpathoffset2
,uni_reqpath
,reqpathlen
);
1186 for(i
=0;i
<junction
->referral_count
;i
++) {
1187 struct referral
* ref
= &(junction
->referral_list
[i
]);
1190 SSVAL(pdata
,offset
,3); /* version 3 */
1191 SSVAL(pdata
,offset
+2,VERSION3_REFERRAL_SIZE
);
1193 SSVAL(pdata
,offset
+4,1);
1195 SSVAL(pdata
,offset
+4,0);
1198 /* ref_flags :use path_consumed bytes? */
1199 SSVAL(pdata
,offset
+6,0);
1200 SIVAL(pdata
,offset
+8,ref
->ttl
);
1202 SSVAL(pdata
,offset
+12,uni_reqpathoffset1
-offset
);
1203 SSVAL(pdata
,offset
+14,uni_reqpathoffset2
-offset
);
1204 /* copy referred path into current offset */
1205 unilen
= rpcstr_push(pdata
+uni_curroffset
,ref
->alternate_path
,
1206 reply_size
- uni_curroffset
,
1207 STR_UNICODE
| STR_TERMINATE
);
1208 SSVAL(pdata
,offset
+16,uni_curroffset
-offset
);
1209 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
1210 memset(pdata
+offset
+18,'\0',16);
1212 uni_curroffset
+= unilen
;
1213 offset
+= VERSION3_REFERRAL_SIZE
;
1218 /******************************************************************
1219 Set up the DFS referral for the dfs pathname. This call returns
1220 the amount of the path covered by this server, and where the
1221 client should be redirected to. This is the meat of the
1222 TRANS2_GET_DFS_REFERRAL call.
1223 ******************************************************************/
1225 int setup_dfs_referral(connection_struct
*orig_conn
,
1226 const char *dfs_path
,
1227 int max_referral_level
,
1228 char **ppdata
, NTSTATUS
*pstatus
)
1230 struct junction_map
*junction
= NULL
;
1231 int consumedcnt
= 0;
1232 bool self_referral
= False
;
1234 char *pathnamep
= NULL
;
1235 char *local_dfs_path
= NULL
;
1238 if (!(ctx
=talloc_init("setup_dfs_referral"))) {
1239 *pstatus
= NT_STATUS_NO_MEMORY
;
1243 /* get the junction entry */
1245 talloc_destroy(ctx
);
1246 *pstatus
= NT_STATUS_NOT_FOUND
;
1251 * Trim pathname sent by client so it begins with only one backslash.
1252 * Two backslashes confuse some dfs clients
1255 local_dfs_path
= talloc_strdup(ctx
,dfs_path
);
1256 if (!local_dfs_path
) {
1257 *pstatus
= NT_STATUS_NO_MEMORY
;
1258 talloc_destroy(ctx
);
1261 pathnamep
= local_dfs_path
;
1262 while (IS_DIRECTORY_SEP(pathnamep
[0]) &&
1263 IS_DIRECTORY_SEP(pathnamep
[1])) {
1267 junction
= talloc_zero(ctx
, struct junction_map
);
1269 *pstatus
= NT_STATUS_NO_MEMORY
;
1270 talloc_destroy(ctx
);
1274 /* The following call can change cwd. */
1275 *pstatus
= get_referred_path(ctx
, pathnamep
, junction
,
1276 &consumedcnt
, &self_referral
);
1277 if (!NT_STATUS_IS_OK(*pstatus
)) {
1278 vfs_ChDir(orig_conn
,orig_conn
->connectpath
);
1279 talloc_destroy(ctx
);
1282 vfs_ChDir(orig_conn
,orig_conn
->connectpath
);
1284 if (!self_referral
) {
1285 pathnamep
[consumedcnt
] = '\0';
1287 if( DEBUGLVL( 3 ) ) {
1289 dbgtext("setup_dfs_referral: Path %s to "
1290 "alternate path(s):",
1292 for(i
=0;i
<junction
->referral_count
;i
++)
1294 junction
->referral_list
[i
].alternate_path
);
1299 /* create the referral depeding on version */
1300 DEBUG(10,("max_referral_level :%d\n",max_referral_level
));
1302 if (max_referral_level
< 2) {
1303 max_referral_level
= 2;
1305 if (max_referral_level
> 3) {
1306 max_referral_level
= 3;
1309 switch(max_referral_level
) {
1311 reply_size
= setup_ver2_dfs_referral(pathnamep
,
1316 reply_size
= setup_ver3_dfs_referral(pathnamep
, ppdata
,
1317 junction
, self_referral
);
1320 DEBUG(0,("setup_dfs_referral: Invalid dfs referral "
1322 max_referral_level
));
1323 talloc_destroy(ctx
);
1324 *pstatus
= NT_STATUS_INVALID_LEVEL
;
1329 DEBUGADD(0,("DFS Referral pdata:\n"));
1330 dump_data(0,(uint8
*)*ppdata
,reply_size
);
1333 talloc_destroy(ctx
);
1334 *pstatus
= NT_STATUS_OK
;
1338 /**********************************************************************
1339 The following functions are called by the NETDFS RPC pipe functions
1340 **********************************************************************/
1342 /*********************************************************************
1343 Creates a junction structure from a DFS pathname
1344 **********************************************************************/
1346 bool create_junction(TALLOC_CTX
*ctx
,
1347 const char *dfs_path
,
1348 struct junction_map
*jucn
)
1352 struct dfs_path
*pdp
= talloc(ctx
,struct dfs_path
);
1358 status
= parse_dfs_path(NULL
, dfs_path
, False
, pdp
, &dummy
);
1359 if (!NT_STATUS_IS_OK(status
)) {
1363 /* check if path is dfs : validate first token */
1364 if (!is_myname_or_ipaddr(pdp
->hostname
)) {
1365 DEBUG(4,("create_junction: Invalid hostname %s "
1367 pdp
->hostname
, dfs_path
));
1372 /* Check for a non-DFS share */
1373 snum
= lp_servicenumber(pdp
->servicename
);
1375 if(snum
< 0 || !lp_msdfs_root(snum
)) {
1376 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1382 jucn
->service_name
= talloc_strdup(ctx
, pdp
->servicename
);
1383 jucn
->volume_name
= talloc_strdup(ctx
, pdp
->reqpath
);
1384 jucn
->comment
= talloc_strdup(ctx
, lp_comment(snum
));
1387 if (!jucn
->service_name
|| !jucn
->volume_name
|| ! jucn
->comment
) {
1393 /**********************************************************************
1394 Forms a valid Unix pathname from the junction
1395 **********************************************************************/
1397 static bool junction_to_local_path(const struct junction_map
*jucn
,
1399 connection_struct
**conn_out
,
1405 snum
= lp_servicenumber(jucn
->service_name
);
1409 status
= create_conn_struct(talloc_tos(), conn_out
, snum
,
1410 lp_pathname(snum
), NULL
, oldpath
);
1411 if (!NT_STATUS_IS_OK(status
)) {
1415 *pp_path_out
= talloc_asprintf(*conn_out
,
1419 if (!*pp_path_out
) {
1420 vfs_ChDir(*conn_out
, *oldpath
);
1421 SMB_VFS_DISCONNECT(*conn_out
);
1422 conn_free(*conn_out
);
1428 bool create_msdfs_link(const struct junction_map
*jucn
)
1432 char *msdfs_link
= NULL
;
1433 connection_struct
*conn
;
1435 bool insert_comma
= False
;
1438 if(!junction_to_local_path(jucn
, &path
, &conn
, &cwd
)) {
1442 /* Form the msdfs_link contents */
1443 msdfs_link
= talloc_strdup(conn
, "msdfs:");
1447 for(i
=0; i
<jucn
->referral_count
; i
++) {
1448 char *refpath
= jucn
->referral_list
[i
].alternate_path
;
1450 /* Alternate paths always use Windows separators. */
1451 trim_char(refpath
, '\\', '\\');
1452 if(*refpath
== '\0') {
1454 insert_comma
= False
;
1458 if (i
> 0 && insert_comma
) {
1459 msdfs_link
= talloc_asprintf_append_buffer(msdfs_link
,
1463 msdfs_link
= talloc_asprintf_append_buffer(msdfs_link
,
1471 if (!insert_comma
) {
1472 insert_comma
= True
;
1476 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1479 if(SMB_VFS_SYMLINK(conn
, msdfs_link
, path
) < 0) {
1480 if (errno
== EEXIST
) {
1481 struct smb_filename
*smb_fname
= NULL
;
1484 status
= create_synthetic_smb_fname(talloc_tos(), path
,
1487 if (!NT_STATUS_IS_OK(status
)) {
1488 errno
= map_errno_from_nt_status(status
);
1492 if(SMB_VFS_UNLINK(conn
, smb_fname
)!=0) {
1493 TALLOC_FREE(smb_fname
);
1496 TALLOC_FREE(smb_fname
);
1498 if (SMB_VFS_SYMLINK(conn
, msdfs_link
, path
) < 0) {
1499 DEBUG(1,("create_msdfs_link: symlink failed "
1500 "%s -> %s\nError: %s\n",
1501 path
, msdfs_link
, strerror(errno
)));
1509 vfs_ChDir(conn
, cwd
);
1510 SMB_VFS_DISCONNECT(conn
);
1515 bool remove_msdfs_link(const struct junction_map
*jucn
)
1519 connection_struct
*conn
;
1521 struct smb_filename
*smb_fname
= NULL
;
1524 if (!junction_to_local_path(jucn
, &path
, &conn
, &cwd
)) {
1528 status
= create_synthetic_smb_fname(talloc_tos(), path
,
1531 if (!NT_STATUS_IS_OK(status
)) {
1532 errno
= map_errno_from_nt_status(status
);
1536 if( SMB_VFS_UNLINK(conn
, smb_fname
) == 0 ) {
1540 TALLOC_FREE(smb_fname
);
1541 vfs_ChDir(conn
, cwd
);
1542 SMB_VFS_DISCONNECT(conn
);
1547 /*********************************************************************
1548 Return the number of DFS links at the root of this share.
1549 *********************************************************************/
1551 static int count_dfs_links(TALLOC_CTX
*ctx
, int snum
)
1554 SMB_STRUCT_DIR
*dirp
= NULL
;
1555 const char *dname
= NULL
;
1556 char *talloced
= NULL
;
1557 const char *connect_path
= lp_pathname(snum
);
1558 const char *msdfs_proxy
= lp_msdfs_proxy(snum
);
1559 connection_struct
*conn
;
1563 if(*connect_path
== '\0') {
1568 * Fake up a connection struct for the VFS layer.
1571 status
= create_conn_struct(talloc_tos(), &conn
, snum
, connect_path
,
1573 if (!NT_STATUS_IS_OK(status
)) {
1574 DEBUG(3, ("create_conn_struct failed: %s\n",
1575 nt_errstr(status
)));
1579 /* Count a link for the msdfs root - convention */
1582 /* No more links if this is an msdfs proxy. */
1583 if (*msdfs_proxy
!= '\0') {
1587 /* Now enumerate all dfs links */
1588 dirp
= SMB_VFS_OPENDIR(conn
, ".", NULL
, 0);
1593 while ((dname
= vfs_readdirname(conn
, dirp
, NULL
, &talloced
))
1595 if (is_msdfs_link(conn
,
1600 TALLOC_FREE(talloced
);
1603 SMB_VFS_CLOSEDIR(conn
,dirp
);
1606 vfs_ChDir(conn
, cwd
);
1607 SMB_VFS_DISCONNECT(conn
);
1612 /*********************************************************************
1613 *********************************************************************/
1615 static int form_junctions(TALLOC_CTX
*ctx
,
1617 struct junction_map
*jucn
,
1621 SMB_STRUCT_DIR
*dirp
= NULL
;
1622 const char *dname
= NULL
;
1623 char *talloced
= NULL
;
1624 const char *connect_path
= lp_pathname(snum
);
1625 char *service_name
= lp_servicename(snum
);
1626 const char *msdfs_proxy
= lp_msdfs_proxy(snum
);
1627 connection_struct
*conn
;
1628 struct referral
*ref
= NULL
;
1632 if (jn_remain
== 0) {
1636 if(*connect_path
== '\0') {
1641 * Fake up a connection struct for the VFS layer.
1644 status
= create_conn_struct(ctx
, &conn
, snum
, connect_path
, NULL
,
1646 if (!NT_STATUS_IS_OK(status
)) {
1647 DEBUG(3, ("create_conn_struct failed: %s\n",
1648 nt_errstr(status
)));
1652 /* form a junction for the msdfs root - convention
1653 DO NOT REMOVE THIS: NT clients will not work with us
1654 if this is not present
1656 jucn
[cnt
].service_name
= talloc_strdup(ctx
,service_name
);
1657 jucn
[cnt
].volume_name
= talloc_strdup(ctx
, "");
1658 if (!jucn
[cnt
].service_name
|| !jucn
[cnt
].volume_name
) {
1661 jucn
[cnt
].comment
= "";
1662 jucn
[cnt
].referral_count
= 1;
1664 ref
= jucn
[cnt
].referral_list
= talloc_zero(ctx
, struct referral
);
1665 if (jucn
[cnt
].referral_list
== NULL
) {
1670 ref
->ttl
= REFERRAL_TTL
;
1671 if (*msdfs_proxy
!= '\0') {
1672 ref
->alternate_path
= talloc_strdup(ctx
,
1675 ref
->alternate_path
= talloc_asprintf(ctx
,
1677 get_local_machine_name(),
1681 if (!ref
->alternate_path
) {
1686 /* Don't enumerate if we're an msdfs proxy. */
1687 if (*msdfs_proxy
!= '\0') {
1691 /* Now enumerate all dfs links */
1692 dirp
= SMB_VFS_OPENDIR(conn
, ".", NULL
, 0);
1697 while ((dname
= vfs_readdirname(conn
, dirp
, NULL
, &talloced
))
1699 char *link_target
= NULL
;
1700 if (cnt
>= jn_remain
) {
1701 DEBUG(2, ("form_junctions: ran out of MSDFS "
1703 TALLOC_FREE(talloced
);
1706 if (is_msdfs_link_internal(ctx
,
1708 dname
, &link_target
,
1710 if (parse_msdfs_symlink(ctx
,
1712 &jucn
[cnt
].referral_list
,
1713 &jucn
[cnt
].referral_count
)) {
1715 jucn
[cnt
].service_name
= talloc_strdup(ctx
,
1717 jucn
[cnt
].volume_name
= talloc_strdup(ctx
,
1719 if (!jucn
[cnt
].service_name
||
1720 !jucn
[cnt
].volume_name
) {
1721 TALLOC_FREE(talloced
);
1724 jucn
[cnt
].comment
= "";
1727 TALLOC_FREE(link_target
);
1729 TALLOC_FREE(talloced
);
1735 SMB_VFS_CLOSEDIR(conn
,dirp
);
1738 vfs_ChDir(conn
, cwd
);
1743 struct junction_map
*enum_msdfs_links(struct smbd_server_connection
*sconn
,
1744 TALLOC_CTX
*ctx
, size_t *p_num_jn
)
1746 struct junction_map
*jn
= NULL
;
1748 size_t jn_count
= 0;
1752 if(!lp_host_msdfs()) {
1756 /* Ensure all the usershares are loaded. */
1758 load_registry_shares();
1759 sharecount
= load_usershare_shares(sconn
);
1762 for(i
=0;i
< sharecount
;i
++) {
1763 if(lp_msdfs_root(i
)) {
1764 jn_count
+= count_dfs_links(ctx
, i
);
1767 if (jn_count
== 0) {
1770 jn
= talloc_array(ctx
, struct junction_map
, jn_count
);
1774 for(i
=0; i
< sharecount
; i
++) {
1775 if (*p_num_jn
>= jn_count
) {
1778 if(lp_msdfs_root(i
)) {
1779 *p_num_jn
+= form_junctions(ctx
, i
,
1781 jn_count
- *p_num_jn
);
1787 /******************************************************************************
1788 Core function to resolve a dfs pathname possibly containing a wildcard. If
1789 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1790 detected during dfs resolution.
1791 ******************************************************************************/
1793 NTSTATUS
resolve_dfspath_wcard(TALLOC_CTX
*ctx
,
1794 connection_struct
*conn
,
1796 const char *name_in
,
1799 bool *ppath_contains_wcard
)
1801 bool path_contains_wcard
;
1802 NTSTATUS status
= NT_STATUS_OK
;
1804 if (dfs_pathnames
) {
1805 status
= dfs_redirect(ctx
,
1810 &path_contains_wcard
);
1812 if (NT_STATUS_IS_OK(status
) && ppath_contains_wcard
!= NULL
) {
1813 *ppath_contains_wcard
= path_contains_wcard
;
1817 * Cheat and just return a copy of the in ptr.
1818 * Once srvstr_get_path() uses talloc it'll
1819 * be a talloced ptr anyway.
1821 *pp_name_out
= discard_const_p(char, name_in
);