2 Unix SMB/Netbios implementation.
4 MSDFS services for Samba
5 Copyright (C) Shirish Kalele 2000
6 Copyright (C) Jeremy Allison 2007
7 Copyright (C) Robin McCorkell 2015
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #define DBGC_CLASS DBGC_MSDFS
26 #include "system/filesys.h"
27 #include "smbd/smbd.h"
28 #include "smbd/globals.h"
31 #include "../auth/auth_util.h"
32 #include "lib/param/loadparm.h"
33 #include "libcli/security/security.h"
34 #include "librpc/gen_ndr/ndr_dfsblobs.h"
35 #include "lib/tsocket/tsocket.h"
36 #include "lib/global_contexts.h"
37 #include "source3/lib/substitute.h"
39 /**********************************************************************
40 Function to determine if a given sharename matches a connection.
41 **********************************************************************/
43 static bool msdfs_servicename_matches_connection(struct connection_struct
*conn
,
44 const char *servicename
,
47 const struct loadparm_substitution
*lp_sub
=
48 loadparm_s3_global_substitution();
49 char *conn_servicename
= NULL
;
55 conn_servicename
= lp_servicename(talloc_tos(), lp_sub
, snum
);
56 if (conn_servicename
== NULL
) {
57 DBG_ERR("lp_servicename() failed, OOM!\n");
61 if (strequal(servicename
, conn_servicename
)) {
65 if (strequal(servicename
, HOMES_NAME
)) {
69 if (strequal(vfs_user
, conn_servicename
)) {
74 TALLOC_FREE(conn_servicename
);
78 /**********************************************************************
79 Parse a DFS pathname of the form(s)
81 \hostname\service - self referral
82 \hostname\service\remainingpath - Windows referral path
84 FIXME! Should we also parse:
85 \hostname\service/remainingpath - POSIX referral path
86 as currently nothing uses this ?
88 into the dfs_path components. Strict form.
90 Checks DFS path starts with separator.
91 Checks hostname is ours.
92 Ensures servicename (share) is sent, and
93 if so, terminates the name or is followed by
96 If returned, remainingpath is untouched. Caller must call
97 check_path_syntaxXXX() on it.
99 Called by all non-fileserver processing (DFS RPC, FSCTL_DFS_GET_REFERRALS)
100 etc. Errors out on any inconsistency in the path.
101 **********************************************************************/
103 static NTSTATUS
parse_dfs_path_strict(TALLOC_CTX
*ctx
,
104 const char *pathname
,
107 char **_remaining_path
)
109 char *pathname_local
= NULL
;
111 const char *hostname
= NULL
;
112 const char *servicename
= NULL
;
113 const char *reqpath
= NULL
;
114 bool my_hostname
= false;
117 DBG_DEBUG("path = |%s|\n", pathname
);
119 pathname_local
= talloc_strdup(talloc_tos(), pathname
);
120 if (pathname_local
== NULL
) {
121 return NT_STATUS_NO_MEMORY
;
124 * parse_dfs_path_strict() is called from
125 * get_referred_path() and create_junction()
126 * which use Windows DFS paths of \server\share.
130 * Strict DFS paths *must* start with the
131 * path separator '\\'.
134 if (pathname_local
[0] != '\\') {
135 DBG_ERR("path %s doesn't start with \\\n",
137 status
= NT_STATUS_NOT_FOUND
;
142 /* Parse out hostname. */
143 p
= strchr(pathname_local
+ 1, '\\');
145 DBG_ERR("can't parse hostname from path %s\n",
147 status
= NT_STATUS_NOT_FOUND
;
151 hostname
= &pathname_local
[1];
153 DBG_DEBUG("hostname: %s\n", hostname
);
155 /* Is this really our hostname ? */
156 my_hostname
= is_myname_or_ipaddr(hostname
);
158 DBG_ERR("Hostname %s is not ours.\n",
160 status
= NT_STATUS_NOT_FOUND
;
167 * Find the end of servicename by looking for
168 * a directory separator character. The character
169 * should be '\\' for a Windows path.
170 * If there is no separator, then this is a self-referral
171 * of "\server\share".
174 p
= strchr(servicename
, '\\');
179 DBG_DEBUG("servicename: %s\n", servicename
);
182 /* Client sent self referral "\server\share". */
185 /* Step past the '\0' we just replaced '\\' with. */
189 DBG_DEBUG("rest of the path: %s\n", reqpath
);
191 if (_hostname
!= NULL
) {
192 *_hostname
= talloc_strdup(ctx
, hostname
);
193 if (*_hostname
== NULL
) {
194 status
= NT_STATUS_NO_MEMORY
;
198 if (_servicename
!= NULL
) {
199 *_servicename
= talloc_strdup(ctx
, servicename
);
200 if (*_servicename
== NULL
) {
201 status
= NT_STATUS_NO_MEMORY
;
205 if (_remaining_path
!= NULL
) {
206 *_remaining_path
= talloc_strdup(ctx
, reqpath
);
207 if (*_remaining_path
== NULL
) {
208 status
= NT_STATUS_NO_MEMORY
;
213 status
= NT_STATUS_OK
;
215 TALLOC_FREE(pathname_local
);
219 /**********************************************************************
220 Parse a DFS pathname of the form /hostname/service/reqpath
221 into the dfs_path structure.
223 NB. srvstr_get_path_internal() now *always* calls
224 check_path_syntax_XXX() on an incoming name, so
225 the path separator is now always '/', even from
228 Unfortunately, due to broken clients who might set the
229 SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
230 send a local path, we have to cope with that too....
232 If conn != NULL then ensure the provided service is
233 the one pointed to by the connection.
235 This version does everything using pointers within one copy of the
236 pathname string, talloced on the struct dfs_path pointer (which
237 must be talloced). This may be too clever to live....
239 **********************************************************************/
241 static NTSTATUS
parse_dfs_path(TALLOC_CTX
*ctx
,
242 connection_struct
*conn
,
243 const char *pathname
,
246 char **_remaining_path
)
248 char *hostname
= NULL
;
249 char *pathname_local
= NULL
;
251 char *servicename
= NULL
;
252 char *reqpath
= NULL
;
253 char *eos_ptr
= NULL
;
254 bool servicename_matches
= false;
255 bool using_smb1
= !conn
->sconn
->using_smb2
;
257 pathname_local
= talloc_strdup(ctx
, pathname
);
258 if (pathname_local
== NULL
) {
259 return NT_STATUS_NO_MEMORY
;
262 * parse_dfs_path() is only called from
263 * dfs_filename_convert() with SMB1/2/3 DFS
264 * names. Ensure we only have to cope with
267 string_replace(pathname_local
, '\\', '/');
269 /* Get a pointer to the terminating '\0' */
270 eos_ptr
= &pathname_local
[strlen(pathname_local
)];
274 * SMB1 DFS paths sent to the fileserver should start with
275 * the path separator '/'. However, libsmbclient libraries
276 * will set the DFS bit on SMB1 calls and then send non-DFS
277 * paths. We must cope with this.
279 * Note SMB2 paths sent to the fileserver never start with
280 * the path separator '/'.
283 if (using_smb1
&& (*p
!= '/')) {
284 DBG_ERR("path %s doesn't start with /\n", p
);
286 * Possibly client sent a local path by mistake.
287 * Try and convert to a local path.
288 * Note that this is an SMB1-only fallback
289 * to cope with known broken SMB1 clients.
292 hostname
= eos_ptr
; /* "" */
293 servicename
= eos_ptr
; /* "" */
295 DBG_ERR("trying to convert %s to a local path\n", p
);
300 * Safe to use on talloc'ed string as it only shrinks.
301 * It also doesn't affect the eos_ptr.
303 trim_char(p
, '/', '/');
305 DBG_DEBUG("p = |%s| after trimming /'s\n", p
);
308 /* Parse out hostname. */
311 DBG_ERR("can't parse hostname from path %s\n", pathname_local
);
313 * Possibly client sent a local path by mistake.
314 * Try and convert to a local path.
317 hostname
= eos_ptr
; /* "" */
318 servicename
= eos_ptr
; /* "" */
321 DBG_ERR("trying to convert %s to a local path\n", p
);
325 hostname
= pathname_local
;
327 DBG_DEBUG("hostname: %s\n", hostname
);
329 /* Parse out servicename. */
331 p
= strchr(servicename
, '/');
336 /* Is this really our servicename ? */
337 servicename_matches
= msdfs_servicename_matches_connection(
340 get_current_username());
342 if (!servicename_matches
) {
343 DBG_ERR("%s is not our servicename\n", servicename
);
346 * Possibly client sent a local path by mistake.
347 * Try and convert to a local path.
350 /* Repair the path - replace the sepchar's
358 hostname
= eos_ptr
; /* "" */
359 servicename
= eos_ptr
; /* "" */
362 DBG_ERR("trying to convert %s to a local path\n",
367 servicename
= servicename
;
369 DBG_DEBUG("servicename: %s\n", servicename
);
372 /* Client sent self referral \server\share. */
373 reqpath
= eos_ptr
; /* "" */
382 * As check_path_syntax_XXX() has already been
383 * called we know this is a normal path containing
391 DBG_DEBUG("rest of the path: %s\n", reqpath
);
393 if (_hostname
!= NULL
) {
394 *_hostname
= talloc_strdup(ctx
, hostname
);
395 if (*_hostname
== NULL
) {
396 return NT_STATUS_NO_MEMORY
;
399 if (_servicename
!= NULL
) {
400 *_servicename
= talloc_strdup(ctx
, servicename
);
401 if (*_servicename
== NULL
) {
402 return NT_STATUS_NO_MEMORY
;
405 if (_remaining_path
!= NULL
) {
406 *_remaining_path
= talloc_strdup(ctx
, reqpath
);
407 if (*_remaining_path
== NULL
) {
408 return NT_STATUS_NO_MEMORY
;
411 TALLOC_FREE(pathname_local
);
415 /********************************************************
416 Fake up a connection struct for the VFS layer, for use in
417 applications (such as the python bindings), that do not want the
418 global working directory changed under them.
420 SMB_VFS_CONNECT requires root privileges.
421 *********************************************************/
423 static NTSTATUS
create_conn_struct_as_root(TALLOC_CTX
*ctx
,
424 struct tevent_context
*ev
,
425 struct messaging_context
*msg
,
426 connection_struct
**pconn
,
429 const struct auth_session_info
*session_info
)
431 connection_struct
*conn
;
433 const char *vfs_user
;
434 struct smbd_server_connection
*sconn
;
435 const char *servicename
= lp_const_servicename(snum
);
438 sconn
= talloc_zero(ctx
, struct smbd_server_connection
);
440 return NT_STATUS_NO_MEMORY
;
444 sconn
->msg_ctx
= msg
;
446 conn
= conn_new(sconn
);
449 return NT_STATUS_NO_MEMORY
;
452 /* Now we have conn, we need to make sconn a child of conn,
453 * for a proper talloc tree */
454 talloc_steal(conn
, sconn
);
456 if (snum
== -1 && servicename
== NULL
) {
457 servicename
= "Unknown Service (snum == -1)";
460 connpath
= talloc_strdup(conn
, path
);
463 return NT_STATUS_NO_MEMORY
;
465 connpath
= talloc_string_sub(conn
,
471 return NT_STATUS_NO_MEMORY
;
474 /* needed for smbd_vfs_init() */
476 conn
->params
->service
= snum
;
477 conn
->cnum
= TID_FIELD_INVALID
;
479 SMB_ASSERT(session_info
!= NULL
);
481 conn
->session_info
= copy_session_info(conn
, session_info
);
482 if (conn
->session_info
== NULL
) {
483 DBG_ERR("copy_serverinfo failed\n");
485 return NT_STATUS_NO_MEMORY
;
488 /* unix_info could be NULL in session_info */
489 if (conn
->session_info
->unix_info
!= NULL
) {
490 vfs_user
= conn
->session_info
->unix_info
->unix_name
;
492 vfs_user
= get_current_username();
495 conn_setup_case_options(conn
);
497 set_conn_connectpath(conn
, connpath
);
500 * New code to check if there's a share security descriptor
501 * added from NT server manager. This is done after the
502 * smb.conf checks are done as we need a uid and token. JRA.
505 share_access_check(conn
->session_info
->security_token
,
507 MAXIMUM_ALLOWED_ACCESS
,
508 &conn
->share_access
);
510 if ((conn
->share_access
& FILE_WRITE_DATA
) == 0) {
511 if ((conn
->share_access
& FILE_READ_DATA
) == 0) {
512 /* No access, read or write. */
513 DBG_WARNING("connection to %s "
514 "denied due to security "
518 return NT_STATUS_ACCESS_DENIED
;
520 conn
->read_only
= true;
523 if (!smbd_vfs_init(conn
)) {
524 NTSTATUS status
= map_nt_error_from_unix(errno
);
525 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
530 /* this must be the first filesystem operation that we do */
531 if (SMB_VFS_CONNECT(conn
, servicename
, vfs_user
) < 0) {
532 DEBUG(0,("VFS connect failed!\n"));
534 return NT_STATUS_UNSUCCESSFUL
;
537 ok
= canonicalize_connect_path(conn
);
539 DBG_ERR("Failed to canonicalize sharepath\n");
541 return NT_STATUS_ACCESS_DENIED
;
544 conn
->fs_capabilities
= SMB_VFS_FS_CAPABILITIES(conn
, &conn
->ts_res
);
545 conn
->tcon_done
= true;
546 *pconn
= talloc_move(ctx
, &conn
);
551 static int conn_struct_tos_destructor(struct conn_struct_tos
*c
)
553 if (c
->oldcwd_fname
!= NULL
) {
554 vfs_ChDir(c
->conn
, c
->oldcwd_fname
);
555 TALLOC_FREE(c
->oldcwd_fname
);
557 SMB_VFS_DISCONNECT(c
->conn
);
562 /********************************************************
563 Fake up a connection struct for the VFS layer, for use in
564 applications (such as the python bindings), that do not want the
565 global working directory changed under them.
567 SMB_VFS_CONNECT requires root privileges.
568 This temporary uses become_root() and unbecome_root().
570 But further impersonation has to be cone by the caller.
571 *********************************************************/
572 NTSTATUS
create_conn_struct_tos(struct messaging_context
*msg
,
575 const struct auth_session_info
*session_info
,
576 struct conn_struct_tos
**_c
)
578 struct conn_struct_tos
*c
= NULL
;
579 struct tevent_context
*ev
= NULL
;
584 c
= talloc_zero(talloc_tos(), struct conn_struct_tos
);
586 return NT_STATUS_NO_MEMORY
;
589 ev
= samba_tevent_context_init(c
);
592 return NT_STATUS_NO_MEMORY
;
596 status
= create_conn_struct_as_root(c
,
604 if (!NT_STATUS_IS_OK(status
)) {
609 talloc_set_destructor(c
, conn_struct_tos_destructor
);
615 /********************************************************
616 Fake up a connection struct for the VFS layer.
617 Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
619 See also the comment for create_conn_struct_tos() above!
621 The CWD change is reverted by the destructor of
622 conn_struct_tos when the current talloc_tos() is destroyed.
623 *********************************************************/
624 NTSTATUS
create_conn_struct_tos_cwd(struct messaging_context
*msg
,
627 const struct auth_session_info
*session_info
,
628 struct conn_struct_tos
**_c
)
630 struct conn_struct_tos
*c
= NULL
;
631 struct smb_filename smb_fname_connectpath
= {0};
636 status
= create_conn_struct_tos(msg
,
641 if (!NT_STATUS_IS_OK(status
)) {
646 * Windows seems to insist on doing trans2getdfsreferral() calls on
647 * the IPC$ share as the anonymous user. If we try to chdir as that
648 * user we will fail.... WTF ? JRA.
651 c
->oldcwd_fname
= vfs_GetWd(c
, c
->conn
);
652 if (c
->oldcwd_fname
== NULL
) {
653 status
= map_nt_error_from_unix(errno
);
654 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno
)));
659 smb_fname_connectpath
= (struct smb_filename
) {
660 .base_name
= c
->conn
->connectpath
663 if (vfs_ChDir(c
->conn
, &smb_fname_connectpath
) != 0) {
664 status
= map_nt_error_from_unix(errno
);
665 DBG_NOTICE("Can't ChDir to new conn path %s. "
667 c
->conn
->connectpath
, strerror(errno
));
668 TALLOC_FREE(c
->oldcwd_fname
);
677 /********************************************************
678 Fake up a connection struct for the VFS layer.
679 This takes an TALLOC_CTX and tevent_context from the
680 caller and the resulting connection_struct is stable
681 across the lifetime of mem_ctx and ev.
683 Note: this performs a vfs connect and changes cwd.
685 See also the comment for create_conn_struct_tos() above!
686 *********************************************************/
688 NTSTATUS
create_conn_struct_cwd(TALLOC_CTX
*mem_ctx
,
689 struct tevent_context
*ev
,
690 struct messaging_context
*msg
,
691 const struct auth_session_info
*session_info
,
694 struct connection_struct
**c
)
699 status
= create_conn_struct_as_root(mem_ctx
,
710 static void shuffle_strlist(char **list
, int count
)
716 for (i
= count
; i
> 1; i
--) {
717 r
= generate_random() % i
;
725 /**********************************************************************
726 Parse the contents of a symlink to verify if it is an msdfs referral
727 A valid referral is of the form:
729 msdfs:server1\share1,server2\share2
730 msdfs:server1\share1\pathname,server2\share2\pathname
731 msdfs:server1/share1,server2/share2
732 msdfs:server1/share1/pathname,server2/share2/pathname.
734 Note that the alternate paths returned here must be of the canonicalized
738 \server\share\path\to\file,
740 even in posix path mode. This is because we have no knowledge if the
741 server we're referring to understands posix paths.
742 **********************************************************************/
744 bool parse_msdfs_symlink(TALLOC_CTX
*ctx
,
745 bool shuffle_referrals
,
747 struct referral
**ppreflist
,
752 char **alt_path
= NULL
;
754 struct referral
*reflist
= NULL
;
757 temp
= talloc_strdup(ctx
, target
);
761 prot
= strtok_r(temp
, ":", &saveptr
);
763 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
768 alt_path
= talloc_array(ctx
, char *, MAX_REFERRAL_COUNT
);
774 /* parse out the alternate paths */
775 while((count
<MAX_REFERRAL_COUNT
) &&
776 ((alt_path
[count
] = strtok_r(NULL
, ",", &saveptr
)) != NULL
)) {
780 /* shuffle alternate paths */
781 if (shuffle_referrals
) {
782 shuffle_strlist(alt_path
, count
);
785 DBG_DEBUG("count=%zu\n", count
);
788 reflist
= talloc_zero_array(ctx
,
789 struct referral
, count
);
790 if(reflist
== NULL
) {
792 TALLOC_FREE(alt_path
);
799 for(i
=0;i
<count
;i
++) {
802 /* Canonicalize link target.
803 * Replace all /'s in the path by a \ */
804 string_replace(alt_path
[i
], '/', '\\');
806 /* Remove leading '\\'s */
808 while (*p
&& (*p
== '\\')) {
812 reflist
[i
].alternate_path
= talloc_asprintf(reflist
,
815 if (!reflist
[i
].alternate_path
) {
817 TALLOC_FREE(alt_path
);
818 TALLOC_FREE(reflist
);
822 reflist
[i
].proximity
= 0;
823 reflist
[i
].ttl
= REFERRAL_TTL
;
824 DBG_DEBUG("Created alt path: %s\n",
825 reflist
[i
].alternate_path
);
828 if (ppreflist
!= NULL
) {
829 *ppreflist
= reflist
;
831 TALLOC_FREE(reflist
);
833 if (prefcount
!= NULL
) {
837 TALLOC_FREE(alt_path
);
841 /**********************************************************************
842 Returns true if the unix path is a valid msdfs symlink.
843 **********************************************************************/
845 bool is_msdfs_link(struct files_struct
*dirfsp
,
846 struct smb_filename
*atname
)
848 NTSTATUS status
= SMB_VFS_READ_DFS_PATHAT(dirfsp
->conn
,
854 return (NT_STATUS_IS_OK(status
));
857 /*****************************************************************
858 Used by other functions to decide if a dfs path is remote,
859 and to get the list of referred locations for that remote path.
861 consumedcntp: how much of the dfs path is being redirected. the client
862 should try the remaining path on the redirected server.
863 *****************************************************************/
865 static NTSTATUS
dfs_path_lookup(TALLOC_CTX
*ctx
,
866 connection_struct
*conn
,
867 const char *dfspath
, /* Incoming complete dfs path */
868 const char *reqpath
, /* Parsed out remaining path. */
870 size_t *consumedcntp
,
871 struct referral
**ppreflist
,
872 size_t *preferral_count
)
875 struct smb_filename
*parent_smb_fname
= NULL
;
876 struct smb_filename
*smb_fname_rel
= NULL
;
878 char *local_pathname
= NULL
;
879 char *last_component
= NULL
;
881 size_t removed_components
= 0;
882 bool posix
= (ucf_flags
& UCF_POSIX_PATHNAMES
);
884 char *canon_dfspath
= NULL
;
886 DBG_DEBUG("Conn path = %s reqpath = %s\n", conn
->connectpath
, reqpath
);
888 local_pathname
= talloc_strdup(ctx
, reqpath
);
889 if (local_pathname
== NULL
) {
890 status
= NT_STATUS_NO_MEMORY
;
894 /* We know reqpath isn't a DFS path. */
895 ucf_flags
&= ~UCF_DFS_PATHNAME
;
897 if (ucf_flags
& UCF_GMT_PATHNAME
) {
898 extract_snapshot_token(local_pathname
, &twrp
);
899 ucf_flags
&= ~UCF_GMT_PATHNAME
;
903 * We should have been given a DFS path to resolve.
904 * This should return NT_STATUS_PATH_NOT_COVERED.
906 * Do a pathname walk, stripping off components
907 * until we get NT_STATUS_OK instead of
908 * NT_STATUS_PATH_NOT_COVERED.
910 * Fail on any other error.
914 TALLOC_CTX
*frame
= NULL
;
915 struct files_struct
*dirfsp
= NULL
;
916 struct smb_filename
*smb_fname_walk
= NULL
;
918 TALLOC_FREE(parent_smb_fname
);
921 * Use a local stackframe as filename_convert_dirfsp()
922 * opens handles on the last two components in the path.
923 * Allow these to be freed as we step back through
924 * the local_pathname.
926 frame
= talloc_stackframe();
927 status
= filename_convert_dirfsp(frame
,
934 /* If we got a name, save it. */
935 if (smb_fname_walk
!= NULL
) {
936 parent_smb_fname
= talloc_move(ctx
, &smb_fname_walk
);
940 if (!NT_STATUS_EQUAL(status
, NT_STATUS_PATH_NOT_COVERED
)) {
942 * For any other status than NT_STATUS_PATH_NOT_COVERED
943 * (including NT_STATUS_OK) we exit the walk.
944 * If it's an error we catch it outside the loop.
949 /* Step back one component and save it off as last_component. */
950 TALLOC_FREE(last_component
);
951 p
= strrchr(local_pathname
, '/');
954 * We removed all components.
955 * Go around once more to make
956 * sure we can open the root '\0'.
958 last_component
= talloc_strdup(ctx
, local_pathname
);
959 *local_pathname
= '\0';
961 last_component
= talloc_strdup(ctx
, p
+1);
964 if (last_component
== NULL
) {
965 status
= NT_STATUS_NO_MEMORY
;
968 /* Integer wrap check. */
969 if (removed_components
+ 1 < removed_components
) {
970 status
= NT_STATUS_INVALID_PARAMETER
;
973 removed_components
++;
976 if (!NT_STATUS_IS_OK(status
)) {
977 DBG_DEBUG("dfspath = %s. reqpath = %s. Error %s.\n",
984 if (parent_smb_fname
->fsp
== NULL
) {
985 /* Unable to open parent. */
986 DBG_DEBUG("dfspath = %s. reqpath = %s. "
987 "Unable to open parent directory (%s).\n",
990 smb_fname_str_dbg(parent_smb_fname
));
991 status
= NT_STATUS_OBJECT_PATH_NOT_FOUND
;
995 if (removed_components
== 0) {
997 * We never got NT_STATUS_PATH_NOT_COVERED.
998 * There was no DFS redirect.
1000 DBG_DEBUG("dfspath = %s. reqpath = %s. "
1001 "No removed components.\n",
1004 status
= NT_STATUS_OBJECT_PATH_NOT_FOUND
;
1009 * One of the removed_components was the MSDFS link
1010 * at the end. We need to count this in the resolved
1011 * path below, so remove one from removed_components.
1013 removed_components
--;
1016 * Now parent_smb_fname->fsp is the parent directory dirfsp,
1017 * last_component is the untranslated MS-DFS link name.
1018 * Search for it in the parent directory to get the real
1021 status
= get_real_filename_at(parent_smb_fname
->fsp
,
1026 if (!NT_STATUS_IS_OK(status
)) {
1027 DBG_DEBUG("dfspath = %s. reqpath = %s "
1028 "get_real_filename_at(%s, %s) error (%s)\n",
1031 smb_fname_str_dbg(parent_smb_fname
),
1037 smb_fname_rel
= synthetic_smb_fname(ctx
,
1042 posix
? SMB_FILENAME_POSIX_PATH
: 0);
1043 if (smb_fname_rel
== NULL
) {
1044 status
= NT_STATUS_NO_MEMORY
;
1048 /* Get the referral to return. */
1049 status
= SMB_VFS_READ_DFS_PATHAT(conn
,
1051 parent_smb_fname
->fsp
,
1055 if (!NT_STATUS_IS_OK(status
)) {
1056 DBG_DEBUG("dfspath = %s. reqpath = %s. "
1057 "SMB_VFS_READ_DFS_PATHAT(%s, %s) error (%s)\n",
1060 smb_fname_str_dbg(parent_smb_fname
),
1061 smb_fname_str_dbg(smb_fname_rel
),
1067 * Now we must work out how much of the
1068 * given pathname we consumed.
1070 canon_dfspath
= talloc_strdup(ctx
, dfspath
);
1071 if (!canon_dfspath
) {
1072 status
= NT_STATUS_NO_MEMORY
;
1075 /* Canonicalize the raw dfspath. */
1076 string_replace(canon_dfspath
, '\\', '/');
1079 * reqpath comes out of parse_dfs_path(), so it has
1080 * no trailing backslash. Make sure that canon_dfspath hasn't either.
1082 trim_char(canon_dfspath
, 0, '/');
1084 DBG_DEBUG("Unconsumed path: %s\n", canon_dfspath
);
1086 while (removed_components
> 0) {
1087 p
= strrchr(canon_dfspath
, '/');
1091 removed_components
--;
1092 if (p
== NULL
&& removed_components
!= 0) {
1093 DBG_ERR("Component mismatch. path = %s, "
1094 "%zu components left\n",
1096 removed_components
);
1097 status
= NT_STATUS_OBJECT_PATH_NOT_FOUND
;
1101 *consumedcntp
= strlen(canon_dfspath
);
1102 DBG_DEBUG("Path consumed: %s (%zu)\n", canon_dfspath
, *consumedcntp
);
1103 status
= NT_STATUS_OK
;
1107 TALLOC_FREE(parent_smb_fname
);
1108 TALLOC_FREE(local_pathname
);
1109 TALLOC_FREE(last_component
);
1110 TALLOC_FREE(atname
);
1111 TALLOC_FREE(smb_fname_rel
);
1112 TALLOC_FREE(canon_dfspath
);
1116 /*****************************************************************
1117 Decides if a dfs pathname should be redirected or not.
1118 If not, the pathname is converted to a tcon-relative local unix path
1119 This is now a simple wrapper around parse_dfs_path()
1120 as it does all the required checks.
1121 *****************************************************************/
1123 NTSTATUS
dfs_filename_convert(TALLOC_CTX
*ctx
,
1124 connection_struct
*conn
,
1126 const char *dfs_path_in
,
1129 char *reqpath
= NULL
;
1133 * We must use the non-strict version of parse_dfs_path for
1134 * pathnames sent to the fileserver over SMB1/2/3.
1135 * libsmbclient callers always set the FLAGS2_DFS_PATHNAMES
1136 * but then don't send a DFS path in (for example) FindFirst
1137 * or other calls. This is a problem with our client libraries
1138 * for both SMB1 and SMB2+ and will remain so whilst broken
1139 * versions of libsmbclient are being used.
1142 status
= parse_dfs_path(ctx
,
1145 NULL
, /* hostname */
1146 NULL
, /* servicename */
1148 if (!NT_STATUS_IS_OK(status
)) {
1153 * If parse_dfs_path fell back to a local path
1154 * after skipping hostname or servicename, ensure
1155 * we still have called check_path_syntax()
1156 * on the full returned local path. check_path_syntax()
1157 * is idempotent so this is safe.
1159 if (ucf_flags
& UCF_POSIX_PATHNAMES
) {
1160 status
= check_path_syntax_posix(reqpath
);
1162 status
= check_path_syntax(reqpath
);
1164 if (!NT_STATUS_IS_OK(status
)) {
1168 * Previous (and current logic) just ignores
1169 * the server, share components if a DFS
1170 * path is sent on a non-DFS share except to
1171 * check that they match an existing share. Should
1172 * we tighten this up to return an error here ?
1174 *pp_path_out
= reqpath
;
1175 return NT_STATUS_OK
;
1178 /**********************************************************************
1179 Return a self referral.
1180 **********************************************************************/
1182 static NTSTATUS
self_ref(TALLOC_CTX
*ctx
,
1183 const char *dfs_path
,
1184 struct junction_map
*jucn
,
1185 size_t *consumedcntp
,
1186 bool *self_referralp
)
1188 struct referral
*ref
;
1190 *self_referralp
= True
;
1192 jucn
->referral_count
= 1;
1193 if((ref
= talloc_zero(ctx
, struct referral
)) == NULL
) {
1194 return NT_STATUS_NO_MEMORY
;
1197 ref
->alternate_path
= talloc_strdup(ctx
, dfs_path
);
1198 if (!ref
->alternate_path
) {
1200 return NT_STATUS_NO_MEMORY
;
1203 ref
->ttl
= REFERRAL_TTL
;
1204 jucn
->referral_list
= ref
;
1205 *consumedcntp
= strlen(dfs_path
);
1206 return NT_STATUS_OK
;
1209 /**********************************************************************
1210 Gets valid referrals for a dfs path and fills up the
1211 junction_map structure.
1212 **********************************************************************/
1214 NTSTATUS
get_referred_path(TALLOC_CTX
*ctx
,
1215 struct auth_session_info
*session_info
,
1216 const char *dfs_path
,
1217 const struct tsocket_address
*remote_address
,
1218 const struct tsocket_address
*local_address
,
1219 struct junction_map
*jucn
,
1220 size_t *consumedcntp
,
1221 bool *self_referralp
)
1223 TALLOC_CTX
*frame
= talloc_stackframe();
1224 const struct loadparm_substitution
*lp_sub
=
1225 loadparm_s3_global_substitution();
1226 struct conn_struct_tos
*c
= NULL
;
1227 struct connection_struct
*conn
= NULL
;
1228 char *servicename
= NULL
;
1229 char *reqpath
= NULL
;
1231 NTSTATUS status
= NT_STATUS_NOT_FOUND
;
1233 *self_referralp
= False
;
1235 status
= parse_dfs_path_strict(
1238 NULL
, /* hostname */
1241 if (!NT_STATUS_IS_OK(status
)) {
1246 /* Path referrals are always non-POSIX. */
1247 status
= check_path_syntax(reqpath
);
1248 if (!NT_STATUS_IS_OK(status
)) {
1253 jucn
->service_name
= talloc_strdup(ctx
, servicename
);
1254 jucn
->volume_name
= talloc_strdup(ctx
, reqpath
);
1255 if (!jucn
->service_name
|| !jucn
->volume_name
) {
1257 return NT_STATUS_NO_MEMORY
;
1260 /* Verify the share is a dfs root */
1261 snum
= lp_servicenumber(jucn
->service_name
);
1263 char *service_name
= NULL
;
1264 if ((snum
= find_service(ctx
, jucn
->service_name
, &service_name
)) < 0) {
1266 return NT_STATUS_NOT_FOUND
;
1268 if (!service_name
) {
1270 return NT_STATUS_NO_MEMORY
;
1272 TALLOC_FREE(jucn
->service_name
);
1273 jucn
->service_name
= talloc_strdup(ctx
, service_name
);
1274 if (!jucn
->service_name
) {
1276 return NT_STATUS_NO_MEMORY
;
1280 if (!lp_msdfs_root(snum
) && (*lp_msdfs_proxy(talloc_tos(), lp_sub
, snum
) == '\0')) {
1281 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
1283 servicename
, dfs_path
));
1285 return NT_STATUS_NOT_FOUND
;
1289 * Self referrals are tested with a anonymous IPC connection and
1290 * a GET_DFS_REFERRAL call to \\server\share. (which means
1291 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
1292 * into the directory and will fail if it cannot (as the anonymous
1293 * user). Cope with this.
1296 if (reqpath
[0] == '\0') {
1298 struct referral
*ref
;
1301 if (*lp_msdfs_proxy(talloc_tos(), lp_sub
, snum
) == '\0') {
1303 return self_ref(ctx
,
1311 * It's an msdfs proxy share. Redirect to
1312 * the configured target share.
1315 tmp
= talloc_asprintf(frame
, "msdfs:%s",
1316 lp_msdfs_proxy(frame
, lp_sub
, snum
));
1319 return NT_STATUS_NO_MEMORY
;
1322 if (!parse_msdfs_symlink(ctx
,
1323 lp_msdfs_shuffle_referrals(snum
),
1328 return NT_STATUS_INVALID_PARAMETER
;
1330 jucn
->referral_count
= refcount
;
1331 jucn
->referral_list
= ref
;
1332 *consumedcntp
= strlen(dfs_path
);
1334 return NT_STATUS_OK
;
1337 status
= create_conn_struct_tos_cwd(global_messaging_context(),
1339 lp_path(frame
, lp_sub
, snum
),
1342 if (!NT_STATUS_IS_OK(status
)) {
1351 * The remote and local address should be passed down to
1352 * create_conn_struct_cwd.
1354 if (conn
->sconn
->remote_address
== NULL
) {
1355 conn
->sconn
->remote_address
=
1356 tsocket_address_copy(remote_address
, conn
->sconn
);
1357 if (conn
->sconn
->remote_address
== NULL
) {
1359 return NT_STATUS_NO_MEMORY
;
1362 if (conn
->sconn
->local_address
== NULL
) {
1363 conn
->sconn
->local_address
=
1364 tsocket_address_copy(local_address
, conn
->sconn
);
1365 if (conn
->sconn
->local_address
== NULL
) {
1367 return NT_STATUS_NO_MEMORY
;
1371 status
= dfs_path_lookup(ctx
,
1377 &jucn
->referral_list
,
1378 &jucn
->referral_count
);
1380 if (!NT_STATUS_IS_OK(status
)) {
1381 DBG_NOTICE("No valid referrals for path %s (%s)\n",
1390 /******************************************************************
1391 Set up the DFS referral for the dfs pathname. This call returns
1392 the amount of the path covered by this server, and where the
1393 client should be redirected to. This is the meat of the
1394 TRANS2_GET_DFS_REFERRAL call.
1395 ******************************************************************/
1397 int setup_dfs_referral(connection_struct
*orig_conn
,
1398 const char *dfs_path
,
1399 int max_referral_level
,
1400 char **ppdata
, NTSTATUS
*pstatus
)
1402 char *pdata
= *ppdata
;
1404 struct dfs_GetDFSReferral
*r
;
1405 DATA_BLOB blob
= data_blob_null
;
1407 enum ndr_err_code ndr_err
;
1409 r
= talloc_zero(talloc_tos(), struct dfs_GetDFSReferral
);
1411 *pstatus
= NT_STATUS_NO_MEMORY
;
1415 r
->in
.req
.max_referral_level
= max_referral_level
;
1416 r
->in
.req
.servername
= talloc_strdup(r
, dfs_path
);
1417 if (r
->in
.req
.servername
== NULL
) {
1419 *pstatus
= NT_STATUS_NO_MEMORY
;
1423 status
= SMB_VFS_GET_DFS_REFERRALS(orig_conn
, r
);
1424 if (!NT_STATUS_IS_OK(status
)) {
1430 ndr_err
= ndr_push_struct_blob(&blob
, r
,
1432 (ndr_push_flags_fn_t
)ndr_push_dfs_referral_resp
);
1433 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1435 *pstatus
= NT_STATUS_INVALID_PARAMETER
;
1439 pdata
= (char *)SMB_REALLOC(pdata
, blob
.length
);
1442 DEBUG(0,("referral setup:"
1443 "malloc failed for Realloc!\n"));
1447 reply_size
= blob
.length
;
1448 memcpy(pdata
, blob
.data
, blob
.length
);
1451 *pstatus
= NT_STATUS_OK
;
1455 /**********************************************************************
1456 The following functions are called by the NETDFS RPC pipe functions
1457 **********************************************************************/
1459 /*********************************************************************
1460 Creates a junction structure from a DFS pathname
1461 **********************************************************************/
1463 bool create_junction(TALLOC_CTX
*ctx
,
1464 const char *dfs_path
,
1465 struct junction_map
*jucn
)
1467 const struct loadparm_substitution
*lp_sub
=
1468 loadparm_s3_global_substitution();
1470 char *servicename
= NULL
;
1471 char *reqpath
= NULL
;
1474 status
= parse_dfs_path_strict(
1480 if (!NT_STATUS_IS_OK(status
)) {
1484 /* Check for a non-DFS share */
1485 snum
= lp_servicenumber(servicename
);
1487 if(snum
< 0 || !lp_msdfs_root(snum
)) {
1488 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1493 /* Junction create paths are always non-POSIX. */
1494 status
= check_path_syntax(reqpath
);
1495 if (!NT_STATUS_IS_OK(status
)) {
1499 jucn
->service_name
= talloc_strdup(ctx
, servicename
);
1500 jucn
->volume_name
= talloc_strdup(ctx
, reqpath
);
1501 jucn
->comment
= lp_comment(ctx
, lp_sub
, snum
);
1503 if (!jucn
->service_name
|| !jucn
->volume_name
|| ! jucn
->comment
) {
1509 /**********************************************************************
1510 Forms a valid Unix pathname from the junction
1511 **********************************************************************/
1513 static bool junction_to_local_path_tos(const struct junction_map
*jucn
,
1514 struct auth_session_info
*session_info
,
1516 connection_struct
**conn_out
)
1518 const struct loadparm_substitution
*lp_sub
=
1519 loadparm_s3_global_substitution();
1520 struct conn_struct_tos
*c
= NULL
;
1522 char *path_out
= NULL
;
1525 snum
= lp_servicenumber(jucn
->service_name
);
1529 status
= create_conn_struct_tos_cwd(global_messaging_context(),
1531 lp_path(talloc_tos(), lp_sub
, snum
),
1534 if (!NT_STATUS_IS_OK(status
)) {
1538 path_out
= talloc_asprintf(c
,
1540 lp_path(talloc_tos(), lp_sub
, snum
),
1542 if (path_out
== NULL
) {
1546 *pp_path_out
= path_out
;
1547 *conn_out
= c
->conn
;
1552 * Create a msdfs string in Samba format we can store
1553 * in a filesystem object (currently a symlink).
1556 char *msdfs_link_string(TALLOC_CTX
*ctx
,
1557 const struct referral
*reflist
,
1558 size_t referral_count
)
1560 char *refpath
= NULL
;
1561 bool insert_comma
= false;
1562 char *msdfs_link
= NULL
;
1565 /* Form the msdfs_link contents */
1566 msdfs_link
= talloc_strdup(ctx
, "msdfs:");
1567 if (msdfs_link
== NULL
) {
1571 for( i
= 0; i
< referral_count
; i
++) {
1572 refpath
= talloc_strdup(ctx
, reflist
[i
].alternate_path
);
1574 if (refpath
== NULL
) {
1578 /* Alternate paths always use Windows separators. */
1579 trim_char(refpath
, '\\', '\\');
1580 if (*refpath
== '\0') {
1582 insert_comma
= false;
1586 if (i
> 0 && insert_comma
) {
1587 msdfs_link
= talloc_asprintf_append_buffer(msdfs_link
,
1591 msdfs_link
= talloc_asprintf_append_buffer(msdfs_link
,
1596 if (msdfs_link
== NULL
) {
1600 if (!insert_comma
) {
1601 insert_comma
= true;
1604 TALLOC_FREE(refpath
);
1611 TALLOC_FREE(refpath
);
1612 TALLOC_FREE(msdfs_link
);
1616 bool create_msdfs_link(const struct junction_map
*jucn
,
1617 struct auth_session_info
*session_info
)
1619 TALLOC_CTX
*frame
= talloc_stackframe();
1621 connection_struct
*conn
;
1622 struct smb_filename
*smb_fname
= NULL
;
1623 struct smb_filename
*parent_fname
= NULL
;
1624 struct smb_filename
*at_fname
= NULL
;
1629 ok
= junction_to_local_path_tos(jucn
, session_info
, &path
, &conn
);
1634 if (!CAN_WRITE(conn
)) {
1635 const struct loadparm_substitution
*lp_sub
=
1636 loadparm_s3_global_substitution();
1637 int snum
= lp_servicenumber(jucn
->service_name
);
1639 DBG_WARNING("Can't create DFS entry on read-only share %s\n",
1640 lp_servicename(frame
, lp_sub
, snum
));
1644 smb_fname
= synthetic_smb_fname(frame
,
1650 if (smb_fname
== NULL
) {
1654 status
= parent_pathref(frame
,
1659 if (!NT_STATUS_IS_OK(status
)) {
1663 status
= SMB_VFS_CREATE_DFS_PATHAT(conn
,
1666 jucn
->referral_list
,
1667 jucn
->referral_count
);
1668 if (!NT_STATUS_IS_OK(status
)) {
1669 if (NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_COLLISION
)) {
1670 int retval
= SMB_VFS_UNLINKAT(conn
,
1678 status
= SMB_VFS_CREATE_DFS_PATHAT(conn
,
1681 jucn
->referral_list
,
1682 jucn
->referral_count
);
1683 if (!NT_STATUS_IS_OK(status
)) {
1684 DBG_WARNING("SMB_VFS_CREATE_DFS_PATHAT failed "
1699 bool remove_msdfs_link(const struct junction_map
*jucn
,
1700 struct auth_session_info
*session_info
)
1702 TALLOC_CTX
*frame
= talloc_stackframe();
1704 connection_struct
*conn
;
1706 struct smb_filename
*smb_fname
;
1707 struct smb_filename
*parent_fname
= NULL
;
1708 struct smb_filename
*at_fname
= NULL
;
1713 ok
= junction_to_local_path_tos(jucn
, session_info
, &path
, &conn
);
1719 if (!CAN_WRITE(conn
)) {
1720 const struct loadparm_substitution
*lp_sub
=
1721 loadparm_s3_global_substitution();
1722 int snum
= lp_servicenumber(jucn
->service_name
);
1724 DBG_WARNING("Can't remove DFS entry on read-only share %s\n",
1725 lp_servicename(frame
, lp_sub
, snum
));
1730 smb_fname
= synthetic_smb_fname(frame
,
1736 if (smb_fname
== NULL
) {
1742 status
= parent_pathref(frame
,
1747 if (!NT_STATUS_IS_OK(status
)) {
1752 retval
= SMB_VFS_UNLINKAT(conn
,
1764 /*********************************************************************
1765 Return the number of DFS links at the root of this share.
1766 *********************************************************************/
1768 static size_t count_dfs_links(TALLOC_CTX
*ctx
,
1769 struct auth_session_info
*session_info
,
1772 TALLOC_CTX
*frame
= talloc_stackframe();
1773 const struct loadparm_substitution
*lp_sub
=
1774 loadparm_s3_global_substitution();
1776 const char *dname
= NULL
;
1777 char *talloced
= NULL
;
1778 const char *connect_path
= lp_path(frame
, lp_sub
, snum
);
1779 const char *msdfs_proxy
= lp_msdfs_proxy(frame
, lp_sub
, snum
);
1780 struct conn_struct_tos
*c
= NULL
;
1781 connection_struct
*conn
= NULL
;
1783 struct smb_filename
*smb_fname
= NULL
;
1784 struct smb_Dir
*dir_hnd
= NULL
;
1787 if(*connect_path
== '\0') {
1793 * Fake up a connection struct for the VFS layer.
1796 status
= create_conn_struct_tos_cwd(global_messaging_context(),
1801 if (!NT_STATUS_IS_OK(status
)) {
1802 DEBUG(3, ("create_conn_struct failed: %s\n",
1803 nt_errstr(status
)));
1809 /* Count a link for the msdfs root - convention */
1812 /* No more links if this is an msdfs proxy. */
1813 if (*msdfs_proxy
!= '\0') {
1817 smb_fname
= synthetic_smb_fname(frame
,
1823 if (smb_fname
== NULL
) {
1827 /* Now enumerate all dfs links */
1828 status
= OpenDir(frame
,
1834 if (!NT_STATUS_IS_OK(status
)) {
1835 errno
= map_errno_from_nt_status(status
);
1839 while ((dname
= ReadDirName(dir_hnd
, &offset
, NULL
, &talloced
))
1842 struct smb_filename
*smb_dname
=
1843 synthetic_smb_fname(frame
,
1849 if (smb_dname
== NULL
) {
1852 if (is_msdfs_link(dir_hnd_fetch_fsp(dir_hnd
), smb_dname
)) {
1853 if (cnt
+ 1 < cnt
) {
1859 TALLOC_FREE(talloced
);
1860 TALLOC_FREE(smb_dname
);
1868 /*********************************************************************
1869 *********************************************************************/
1871 static int form_junctions(TALLOC_CTX
*ctx
,
1872 struct auth_session_info
*session_info
,
1874 struct junction_map
*jucn
,
1877 TALLOC_CTX
*frame
= talloc_stackframe();
1878 const struct loadparm_substitution
*lp_sub
=
1879 loadparm_s3_global_substitution();
1881 const char *dname
= NULL
;
1882 char *talloced
= NULL
;
1883 const char *connect_path
= lp_path(frame
, lp_sub
, snum
);
1884 char *service_name
= lp_servicename(frame
, lp_sub
, snum
);
1885 const char *msdfs_proxy
= lp_msdfs_proxy(frame
, lp_sub
, snum
);
1886 struct conn_struct_tos
*c
= NULL
;
1887 connection_struct
*conn
= NULL
;
1888 struct referral
*ref
= NULL
;
1889 struct smb_filename
*smb_fname
= NULL
;
1890 struct smb_Dir
*dir_hnd
= NULL
;
1894 if (jn_remain
== 0) {
1899 if(*connect_path
== '\0') {
1905 * Fake up a connection struct for the VFS layer.
1908 status
= create_conn_struct_tos_cwd(global_messaging_context(),
1913 if (!NT_STATUS_IS_OK(status
)) {
1914 DEBUG(3, ("create_conn_struct failed: %s\n",
1915 nt_errstr(status
)));
1921 /* form a junction for the msdfs root - convention
1922 DO NOT REMOVE THIS: NT clients will not work with us
1923 if this is not present
1925 jucn
[cnt
].service_name
= talloc_strdup(ctx
,service_name
);
1926 jucn
[cnt
].volume_name
= talloc_strdup(ctx
, "");
1927 if (!jucn
[cnt
].service_name
|| !jucn
[cnt
].volume_name
) {
1930 jucn
[cnt
].comment
= "";
1931 jucn
[cnt
].referral_count
= 1;
1933 ref
= jucn
[cnt
].referral_list
= talloc_zero(ctx
, struct referral
);
1934 if (jucn
[cnt
].referral_list
== NULL
) {
1939 ref
->ttl
= REFERRAL_TTL
;
1940 if (*msdfs_proxy
!= '\0') {
1941 ref
->alternate_path
= talloc_strdup(ctx
,
1944 ref
->alternate_path
= talloc_asprintf(ctx
,
1946 get_local_machine_name(),
1950 if (!ref
->alternate_path
) {
1955 /* Don't enumerate if we're an msdfs proxy. */
1956 if (*msdfs_proxy
!= '\0') {
1960 smb_fname
= synthetic_smb_fname(frame
,
1966 if (smb_fname
== NULL
) {
1970 /* Now enumerate all dfs links */
1971 status
= OpenDir(frame
,
1977 if (!NT_STATUS_IS_OK(status
)) {
1978 errno
= map_errno_from_nt_status(status
);
1982 while ((dname
= ReadDirName(dir_hnd
, &offset
, NULL
, &talloced
))
1985 struct smb_filename
*smb_dname
= NULL
;
1987 if (cnt
>= jn_remain
) {
1988 DEBUG(2, ("form_junctions: ran out of MSDFS "
1990 TALLOC_FREE(talloced
);
1993 smb_dname
= synthetic_smb_fname(talloc_tos(),
1999 if (smb_dname
== NULL
) {
2000 TALLOC_FREE(talloced
);
2004 status
= SMB_VFS_READ_DFS_PATHAT(conn
,
2008 &jucn
[cnt
].referral_list
,
2009 &jucn
[cnt
].referral_count
);
2011 if (NT_STATUS_IS_OK(status
)) {
2012 jucn
[cnt
].service_name
= talloc_strdup(ctx
,
2014 jucn
[cnt
].volume_name
= talloc_strdup(ctx
, dname
);
2015 if (!jucn
[cnt
].service_name
|| !jucn
[cnt
].volume_name
) {
2016 TALLOC_FREE(talloced
);
2019 jucn
[cnt
].comment
= "";
2022 TALLOC_FREE(talloced
);
2023 TALLOC_FREE(smb_dname
);
2031 struct junction_map
*enum_msdfs_links(TALLOC_CTX
*ctx
,
2032 struct auth_session_info
*session_info
,
2035 struct junction_map
*jn
= NULL
;
2037 size_t jn_count
= 0;
2041 if(!lp_host_msdfs()) {
2045 /* Ensure all the usershares are loaded. */
2047 load_registry_shares();
2048 sharecount
= load_usershare_shares(NULL
, connections_snum_used
);
2051 for(i
=0;i
< sharecount
;i
++) {
2052 if(lp_msdfs_root(i
)) {
2053 jn_count
+= count_dfs_links(ctx
, session_info
, i
);
2056 if (jn_count
== 0) {
2059 jn
= talloc_array(ctx
, struct junction_map
, jn_count
);
2063 for(i
=0; i
< sharecount
; i
++) {
2064 if (*p_num_jn
>= jn_count
) {
2067 if(lp_msdfs_root(i
)) {
2068 *p_num_jn
+= form_junctions(ctx
,
2072 jn_count
- *p_num_jn
);