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
26 extern uint32 global_client_caps
;
28 /**********************************************************************
29 Parse a DFS pathname of the form \hostname\service\reqpath
30 into the dfs_path structure.
31 If POSIX pathnames is true, the pathname may also be of the
32 form /hostname/service/reqpath.
33 We cope with either here.
35 Unfortunately, due to broken clients who might set the
36 SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
37 send a local path, we have to cope with that too....
39 If conn != NULL then ensure the provided service is
40 the one pointed to by the connection.
42 This version does everything using pointers within one copy of the
43 pathname string, talloced on the struct dfs_path pointer (which
44 must be talloced). This may be too clever to live....
46 **********************************************************************/
48 static NTSTATUS
parse_dfs_path(connection_struct
*conn
,
51 struct dfs_path
*pdp
, /* MUST BE TALLOCED */
52 bool *ppath_contains_wcard
)
58 NTSTATUS status
= NT_STATUS_OK
;
64 * This is the only talloc we should need to do
65 * on the struct dfs_path. All the pointers inside
66 * it should point to offsets within this string.
69 pathname_local
= talloc_strdup(pdp
, pathname
);
70 if (!pathname_local
) {
71 return NT_STATUS_NO_MEMORY
;
73 /* Get a pointer to the terminating '\0' */
74 eos_ptr
= &pathname_local
[strlen(pathname_local
)];
75 p
= temp
= pathname_local
;
77 pdp
->posix_path
= (lp_posix_pathnames() && *pathname
== '/');
79 sepchar
= pdp
->posix_path
? '/' : '\\';
81 if (*pathname
!= sepchar
) {
82 DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
85 * Possibly client sent a local path by mistake.
86 * Try and convert to a local path.
89 pdp
->hostname
= eos_ptr
; /* "" */
90 pdp
->servicename
= eos_ptr
; /* "" */
92 /* We've got no info about separators. */
93 pdp
->posix_path
= lp_posix_pathnames();
95 DEBUG(10,("parse_dfs_path: trying to convert %s to a "
102 * Safe to use on talloc'ed string as it only shrinks.
103 * It also doesn't affect the eos_ptr.
105 trim_char(temp
,sepchar
,sepchar
);
107 DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
111 /* Parse out hostname. */
112 p
= strchr_m(temp
,sepchar
);
114 DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
117 * Possibly client sent a local path by mistake.
118 * Try and convert to a local path.
121 pdp
->hostname
= eos_ptr
; /* "" */
122 pdp
->servicename
= eos_ptr
; /* "" */
125 DEBUG(10,("parse_dfs_path: trying to convert %s "
131 pdp
->hostname
= temp
;
133 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp
->hostname
));
135 /* Parse out servicename. */
137 p
= strchr_m(servicename
,sepchar
);
142 /* Is this really our servicename ? */
143 if (conn
&& !( strequal(servicename
, lp_servicename(SNUM(conn
)))
144 || (strequal(servicename
, HOMES_NAME
)
145 && strequal(lp_servicename(SNUM(conn
)),
146 get_current_username()) )) ) {
147 DEBUG(10,("parse_dfs_path: %s is not our servicename\n",
151 * Possibly client sent a local path by mistake.
152 * Try and convert to a local path.
155 pdp
->hostname
= eos_ptr
; /* "" */
156 pdp
->servicename
= eos_ptr
; /* "" */
158 /* Repair the path - replace the sepchar's
161 *servicename
= sepchar
;
167 DEBUG(10,("parse_dfs_path: trying to convert %s "
173 pdp
->servicename
= servicename
;
175 DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp
->servicename
));
178 /* Client sent self referral \server\share. */
179 pdp
->reqpath
= eos_ptr
; /* "" */
187 *ppath_contains_wcard
= False
;
191 /* Rest is reqpath. */
192 if (pdp
->posix_path
) {
193 status
= check_path_syntax_posix(pdp
->reqpath
);
196 status
= check_path_syntax_wcard(pdp
->reqpath
,
197 ppath_contains_wcard
);
199 status
= check_path_syntax(pdp
->reqpath
);
203 if (!NT_STATUS_IS_OK(status
)) {
204 DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
205 p
, nt_errstr(status
) ));
209 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp
->reqpath
));
213 /********************************************************
214 Fake up a connection struct for the VFS layer.
215 Note this CHANGES CWD !!!! JRA.
216 *********************************************************/
218 static NTSTATUS
create_conn_struct(TALLOC_CTX
*ctx
,
219 connection_struct
*conn
,
227 connpath
= talloc_strdup(ctx
, path
);
229 return NT_STATUS_NO_MEMORY
;
231 connpath
= talloc_string_sub(ctx
,
234 lp_servicename(snum
));
236 return NT_STATUS_NO_MEMORY
;
239 /* needed for smbd_vfs_init() */
241 if ((conn
->mem_ctx
=talloc_init("connection_struct")) == NULL
) {
242 DEBUG(0,("talloc_init(connection_struct) failed!\n"));
243 return NT_STATUS_NO_MEMORY
;
246 if (!(conn
->params
= TALLOC_ZERO_P(conn
->mem_ctx
,
247 struct share_params
))) {
248 DEBUG(0, ("TALLOC failed\n"));
249 return NT_STATUS_NO_MEMORY
;
252 conn
->params
->service
= snum
;
254 set_conn_connectpath(conn
, connpath
);
256 if (!smbd_vfs_init(conn
)) {
257 NTSTATUS status
= map_nt_error_from_unix(errno
);
258 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
259 conn_free_internal(conn
);
263 conn
->fs_capabilities
= SMB_VFS_FS_CAPABILITIES(conn
);
266 * Windows seems to insist on doing trans2getdfsreferral() calls on
267 * the IPC$ share as the anonymous user. If we try to chdir as that
268 * user we will fail.... WTF ? JRA.
271 if (vfs_ChDir(conn
,conn
->connectpath
) != 0) {
272 NTSTATUS status
= map_nt_error_from_unix(errno
);
273 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
275 conn
->connectpath
, strerror(errno
) ));
276 conn_free_internal(conn
);
283 /**********************************************************************
284 Parse the contents of a symlink to verify if it is an msdfs referral
285 A valid referral is of the form:
287 msdfs:server1\share1,server2\share2
288 msdfs:server1\share1\pathname,server2\share2\pathname
289 msdfs:server1/share1,server2/share2
290 msdfs:server1/share1/pathname,server2/share2/pathname.
292 Note that the alternate paths returned here must be of the canonicalized
296 \server\share\path\to\file,
298 even in posix path mode. This is because we have no knowledge if the
299 server we're referring to understands posix paths.
300 **********************************************************************/
302 static bool parse_msdfs_symlink(TALLOC_CTX
*ctx
,
304 struct referral
**preflist
,
309 char **alt_path
= NULL
;
311 struct referral
*reflist
;
314 temp
= talloc_strdup(ctx
, target
);
318 prot
= strtok_r(temp
, ":", &saveptr
);
320 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
324 alt_path
= TALLOC_ARRAY(ctx
, char *, MAX_REFERRAL_COUNT
);
329 /* parse out the alternate paths */
330 while((count
<MAX_REFERRAL_COUNT
) &&
331 ((alt_path
[count
] = strtok_r(NULL
, ",", &saveptr
)) != NULL
)) {
335 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count
));
338 reflist
= *preflist
= TALLOC_ZERO_ARRAY(ctx
,
339 struct referral
, count
);
340 if(reflist
== NULL
) {
341 TALLOC_FREE(alt_path
);
345 reflist
= *preflist
= NULL
;
348 for(i
=0;i
<count
;i
++) {
351 /* Canonicalize link target.
352 * Replace all /'s in the path by a \ */
353 string_replace(alt_path
[i
], '/', '\\');
355 /* Remove leading '\\'s */
357 while (*p
&& (*p
== '\\')) {
361 reflist
[i
].alternate_path
= talloc_asprintf(ctx
,
364 if (!reflist
[i
].alternate_path
) {
368 reflist
[i
].proximity
= 0;
369 reflist
[i
].ttl
= REFERRAL_TTL
;
370 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
371 reflist
[i
].alternate_path
));
376 TALLOC_FREE(alt_path
);
380 /**********************************************************************
381 Returns true if the unix path is a valid msdfs symlink and also
382 returns the target string from inside the link.
383 **********************************************************************/
385 static bool is_msdfs_link_internal(TALLOC_CTX
*ctx
,
386 connection_struct
*conn
,
388 char **pp_link_target
,
389 SMB_STRUCT_STAT
*sbufp
)
392 int referral_len
= 0;
393 char link_target_buf
[7];
395 char *link_target
= NULL
;
397 if (pp_link_target
) {
399 link_target
= TALLOC_ARRAY(ctx
, char, bufsize
);
403 *pp_link_target
= link_target
;
405 bufsize
= sizeof(link_target_buf
);
406 link_target
= link_target_buf
;
413 if (SMB_VFS_LSTAT(conn
, path
, sbufp
) != 0) {
414 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
419 if (!S_ISLNK(sbufp
->st_mode
)) {
420 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
425 referral_len
= SMB_VFS_READLINK(conn
, path
, link_target
, bufsize
- 1);
426 if (referral_len
== -1) {
427 DEBUG(0,("is_msdfs_link_read_target: Error reading "
428 "msdfs link %s: %s\n",
429 path
, strerror(errno
)));
432 link_target
[referral_len
] = '\0';
434 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path
,
437 if (!strnequal(link_target
, "msdfs:", 6)) {
444 if (link_target
!= link_target_buf
) {
445 TALLOC_FREE(link_target
);
450 /**********************************************************************
451 Returns true if the unix path is a valid msdfs symlink.
452 **********************************************************************/
454 bool is_msdfs_link(connection_struct
*conn
,
456 SMB_STRUCT_STAT
*sbufp
)
458 return is_msdfs_link_internal(talloc_tos(),
465 /*****************************************************************
466 Used by other functions to decide if a dfs path is remote,
467 and to get the list of referred locations for that remote path.
469 search_flag: For findfirsts, dfs links themselves are not
470 redirected, but paths beyond the links are. For normal smb calls,
471 even dfs links need to be redirected.
473 consumedcntp: how much of the dfs path is being redirected. the client
474 should try the remaining path on the redirected server.
476 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
477 link redirect are in targetpath.
478 *****************************************************************/
480 static NTSTATUS
dfs_path_lookup(TALLOC_CTX
*ctx
,
481 connection_struct
*conn
,
482 const char *dfspath
, /* Incoming complete dfs path */
483 const struct dfs_path
*pdp
, /* Parsed out
484 server+share+extrapath. */
485 bool search_flag
, /* Called from a findfirst ? */
487 char **pp_targetpath
)
491 SMB_STRUCT_STAT sbuf
;
493 char *localpath
= NULL
;
494 char *canon_dfspath
= NULL
; /* Canonicalized dfs path. (only '/'
497 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
498 conn
->connectpath
, pdp
->reqpath
));
501 * Note the unix path conversion here we're doing we can
502 * throw away. We're looking for a symlink for a dfs
503 * resolution, if we don't find it we'll do another
504 * unix_convert later in the codepath.
505 * If we needed to remember what we'd resolved in
506 * dp->reqpath (as the original code did) we'd
507 * copy (localhost, dp->reqpath) on any code
508 * path below that returns True - but I don't
509 * think this is needed. JRA.
512 status
= unix_convert(ctx
, conn
, pdp
->reqpath
, search_flag
, &localpath
,
514 if (!NT_STATUS_IS_OK(status
) && !NT_STATUS_EQUAL(status
,
515 NT_STATUS_OBJECT_PATH_NOT_FOUND
)) {
519 /* Optimization - check if we can redirect the whole path. */
521 if (is_msdfs_link_internal(ctx
, conn
, localpath
, pp_targetpath
, NULL
)) {
523 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
524 "for dfs link %s.\n", dfspath
));
528 DEBUG(6,("dfs_path_lookup: %s resolves to a "
529 "valid dfs link %s.\n", dfspath
,
530 pp_targetpath
? *pp_targetpath
: ""));
533 *consumedcntp
= strlen(dfspath
);
535 return NT_STATUS_PATH_NOT_COVERED
;
538 /* Prepare to test only for '/' components in the given path,
539 * so if a Windows path replace all '\\' characters with '/'.
540 * For a POSIX DFS path we know all separators are already '/'. */
542 canon_dfspath
= talloc_strdup(ctx
, dfspath
);
543 if (!canon_dfspath
) {
544 return NT_STATUS_NO_MEMORY
;
546 if (!pdp
->posix_path
) {
547 string_replace(canon_dfspath
, '\\', '/');
551 * localpath comes out of unix_convert, so it has
552 * no trailing backslash. Make sure that canon_dfspath hasn't either.
553 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
556 trim_char(canon_dfspath
,0,'/');
559 * Redirect if any component in the path is a link.
560 * We do this by walking backwards through the
561 * local path, chopping off the last component
562 * in both the local path and the canonicalized
563 * DFS path. If we hit a DFS link then we're done.
566 p
= strrchr_m(localpath
, '/');
568 q
= strrchr_m(canon_dfspath
, '/');
577 if (is_msdfs_link_internal(ctx
, conn
,
578 localpath
, pp_targetpath
, NULL
)) {
579 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
580 "parent %s is dfs link\n", dfspath
, localpath
));
583 *consumedcntp
= strlen(canon_dfspath
);
584 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
590 return NT_STATUS_PATH_NOT_COVERED
;
593 /* Step back on the filesystem. */
594 p
= strrchr_m(localpath
, '/');
597 /* And in the canonicalized dfs path. */
598 q
= strrchr_m(canon_dfspath
, '/');
605 /*****************************************************************
606 Decides if a dfs pathname should be redirected or not.
607 If not, the pathname is converted to a tcon-relative local unix path
609 search_wcard_flag: this flag performs 2 functions both related
610 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
613 This function can return NT_STATUS_OK, meaning use the returned path as-is
614 (mapped into a local path).
615 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
616 any other NT_STATUS error which is a genuine error to be
617 returned to the client.
618 *****************************************************************/
620 static NTSTATUS
dfs_redirect(TALLOC_CTX
*ctx
,
621 connection_struct
*conn
,
623 bool search_wcard_flag
,
625 bool *ppath_contains_wcard
)
628 struct dfs_path
*pdp
= TALLOC_P(ctx
, struct dfs_path
);
631 return NT_STATUS_NO_MEMORY
;
634 status
= parse_dfs_path(conn
, path_in
, search_wcard_flag
, pdp
,
635 ppath_contains_wcard
);
636 if (!NT_STATUS_IS_OK(status
)) {
641 if (pdp
->reqpath
[0] == '\0') {
643 *pp_path_out
= talloc_strdup(ctx
, "");
645 return NT_STATUS_NO_MEMORY
;
647 DEBUG(5,("dfs_redirect: self-referral.\n"));
651 /* If dfs pathname for a non-dfs share, convert to tcon-relative
652 path and return OK */
654 if (!lp_msdfs_root(SNUM(conn
))) {
655 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
658 return NT_STATUS_NO_MEMORY
;
663 /* If it looked like a local path (zero hostname/servicename)
664 * just treat as a tcon-relative path. */
666 if (pdp
->hostname
[0] == '\0' && pdp
->servicename
[0] == '\0') {
667 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
670 return NT_STATUS_NO_MEMORY
;
675 status
= dfs_path_lookup(ctx
, conn
, path_in
, pdp
,
676 search_wcard_flag
, NULL
, NULL
);
677 if (!NT_STATUS_IS_OK(status
)) {
678 if (NT_STATUS_EQUAL(status
, NT_STATUS_PATH_NOT_COVERED
)) {
679 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in
));
681 DEBUG(10,("dfs_redirect: dfs_path_lookup "
682 "failed for %s with %s\n",
683 path_in
, nt_errstr(status
) ));
688 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in
));
690 /* Form non-dfs tcon-relative path */
691 *pp_path_out
= talloc_strdup(ctx
, pdp
->reqpath
);
694 return NT_STATUS_NO_MEMORY
;
697 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
704 /**********************************************************************
705 Return a self referral.
706 **********************************************************************/
708 static NTSTATUS
self_ref(TALLOC_CTX
*ctx
,
709 const char *dfs_path
,
710 struct junction_map
*jucn
,
712 bool *self_referralp
)
714 struct referral
*ref
;
716 *self_referralp
= True
;
718 jucn
->referral_count
= 1;
719 if((ref
= TALLOC_ZERO_P(ctx
, struct referral
)) == NULL
) {
720 return NT_STATUS_NO_MEMORY
;
723 ref
->alternate_path
= talloc_strdup(ctx
, dfs_path
);
724 if (!ref
->alternate_path
) {
725 return NT_STATUS_NO_MEMORY
;
728 ref
->ttl
= REFERRAL_TTL
;
729 jucn
->referral_list
= ref
;
730 *consumedcntp
= strlen(dfs_path
);
734 /**********************************************************************
735 Gets valid referrals for a dfs path and fills up the
736 junction_map structure.
737 **********************************************************************/
739 NTSTATUS
get_referred_path(TALLOC_CTX
*ctx
,
740 const char *dfs_path
,
741 struct junction_map
*jucn
,
743 bool *self_referralp
)
745 struct connection_struct conns
;
746 struct connection_struct
*conn
= &conns
;
747 char *targetpath
= NULL
;
749 NTSTATUS status
= NT_STATUS_NOT_FOUND
;
751 struct dfs_path
*pdp
= TALLOC_P(ctx
, struct dfs_path
);
754 return NT_STATUS_NO_MEMORY
;
758 *self_referralp
= False
;
760 status
= parse_dfs_path(NULL
, dfs_path
, False
, pdp
, &dummy
);
761 if (!NT_STATUS_IS_OK(status
)) {
765 jucn
->service_name
= talloc_strdup(ctx
, pdp
->servicename
);
766 jucn
->volume_name
= talloc_strdup(ctx
, pdp
->reqpath
);
767 if (!jucn
->service_name
|| !jucn
->volume_name
) {
769 return NT_STATUS_NO_MEMORY
;
772 /* Verify the share is a dfs root */
773 snum
= lp_servicenumber(jucn
->service_name
);
775 fstring service_name
;
776 fstrcpy(service_name
, jucn
->service_name
);
777 if ((snum
= find_service(service_name
)) < 0) {
778 return NT_STATUS_NOT_FOUND
;
780 TALLOC_FREE(jucn
->service_name
);
781 jucn
->service_name
= talloc_strdup(ctx
, service_name
);
782 if (!jucn
->service_name
) {
784 return NT_STATUS_NO_MEMORY
;
788 if (!lp_msdfs_root(snum
) && (*lp_msdfs_proxy(snum
) == '\0')) {
789 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
791 pdp
->servicename
, dfs_path
));
793 return NT_STATUS_NOT_FOUND
;
797 * Self referrals are tested with a anonymous IPC connection and
798 * a GET_DFS_REFERRAL call to \\server\share. (which means
799 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
800 * into the directory and will fail if it cannot (as the anonymous
801 * user). Cope with this.
804 if (pdp
->reqpath
[0] == '\0') {
806 struct referral
*ref
;
808 if (*lp_msdfs_proxy(snum
) == '\0') {
818 * It's an msdfs proxy share. Redirect to
819 * the configured target share.
822 jucn
->referral_count
= 1;
823 if ((ref
= TALLOC_ZERO_P(ctx
, struct referral
)) == NULL
) {
825 return NT_STATUS_NO_MEMORY
;
828 if (!(tmp
= talloc_strdup(ctx
, lp_msdfs_proxy(snum
)))) {
830 return NT_STATUS_NO_MEMORY
;
833 trim_string(tmp
, "\\", 0);
835 ref
->alternate_path
= talloc_asprintf(ctx
, "\\%s", tmp
);
838 if (!ref
->alternate_path
) {
840 return NT_STATUS_NO_MEMORY
;
843 if (pdp
->reqpath
[0] != '\0') {
844 ref
->alternate_path
= talloc_asprintf_append(
848 if (!ref
->alternate_path
) {
850 return NT_STATUS_NO_MEMORY
;
854 ref
->ttl
= REFERRAL_TTL
;
855 jucn
->referral_list
= ref
;
856 *consumedcntp
= strlen(dfs_path
);
861 status
= create_conn_struct(ctx
, conn
, snum
, lp_pathname(snum
));
862 if (!NT_STATUS_IS_OK(status
)) {
867 /* If this is a DFS path dfs_lookup should return
868 * NT_STATUS_PATH_NOT_COVERED. */
870 status
= dfs_path_lookup(ctx
, conn
, dfs_path
, pdp
,
871 False
, consumedcntp
, &targetpath
);
873 if (!NT_STATUS_EQUAL(status
, NT_STATUS_PATH_NOT_COVERED
)) {
874 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
876 conn_free_internal(conn
);
881 /* We know this is a valid dfs link. Parse the targetpath. */
882 if (!parse_msdfs_symlink(ctx
, targetpath
,
883 &jucn
->referral_list
,
884 &jucn
->referral_count
)) {
885 DEBUG(3,("get_referred_path: failed to parse symlink "
886 "target %s\n", targetpath
));
887 conn_free_internal(conn
);
889 return NT_STATUS_NOT_FOUND
;
892 conn_free_internal(conn
);
897 static int setup_ver2_dfs_referral(const char *pathname
,
899 struct junction_map
*junction
,
902 char* pdata
= *ppdata
;
904 smb_ucs2_t
*uni_requestedpath
= NULL
;
905 int uni_reqpathoffset1
,uni_reqpathoffset2
;
907 int requestedpathlen
=0;
912 DEBUG(10,("Setting up version2 referral\nRequested path:\n"));
914 requestedpathlen
= rpcstr_push_talloc(talloc_tos(),
915 &uni_requestedpath
, pathname
);
916 if (uni_requestedpath
== NULL
|| requestedpathlen
== 0) {
921 dump_data(0, (unsigned char *)uni_requestedpath
,
925 DEBUG(10,("ref count = %u\n",junction
->referral_count
));
927 uni_reqpathoffset1
= REFERRAL_HEADER_SIZE
+
928 VERSION2_REFERRAL_SIZE
* junction
->referral_count
;
930 uni_reqpathoffset2
= uni_reqpathoffset1
+ requestedpathlen
;
932 uni_curroffset
= uni_reqpathoffset2
+ requestedpathlen
;
934 reply_size
= REFERRAL_HEADER_SIZE
+
935 VERSION2_REFERRAL_SIZE
*junction
->referral_count
+
936 2 * requestedpathlen
;
937 DEBUG(10,("reply_size: %u\n",reply_size
));
939 /* add up the unicode lengths of all the referral paths */
940 for(i
=0;i
<junction
->referral_count
;i
++) {
941 DEBUG(10,("referral %u : %s\n",
943 junction
->referral_list
[i
].alternate_path
));
945 (strlen(junction
->referral_list
[i
].alternate_path
)+1)*2;
948 DEBUG(10,("reply_size = %u\n",reply_size
));
949 /* add the unexplained 0x16 bytes */
952 pdata
= (char *)SMB_REALLOC(pdata
,reply_size
);
954 DEBUG(0,("Realloc failed!\n"));
959 /* copy in the dfs requested paths.. required for offset calculations */
960 memcpy(pdata
+uni_reqpathoffset1
,uni_requestedpath
,requestedpathlen
);
961 memcpy(pdata
+uni_reqpathoffset2
,uni_requestedpath
,requestedpathlen
);
963 /* create the header */
964 SSVAL(pdata
,0,requestedpathlen
- 2); /* UCS2 of path consumed minus
966 /* number of referral in this pkt */
967 SSVAL(pdata
,2,junction
->referral_count
);
969 SIVAL(pdata
,4,DFSREF_REFERRAL_SERVER
| DFSREF_STORAGE_SERVER
);
971 SIVAL(pdata
,4,DFSREF_STORAGE_SERVER
);
975 /* add the referral elements */
976 for(i
=0;i
<junction
->referral_count
;i
++) {
977 struct referral
* ref
= &junction
->referral_list
[i
];
980 SSVAL(pdata
,offset
,2); /* version 2 */
981 SSVAL(pdata
,offset
+2,VERSION2_REFERRAL_SIZE
);
983 SSVAL(pdata
,offset
+4,1);
985 SSVAL(pdata
,offset
+4,0);
988 /* ref_flags :use path_consumed bytes? */
989 SSVAL(pdata
,offset
+6,0);
990 SIVAL(pdata
,offset
+8,ref
->proximity
);
991 SIVAL(pdata
,offset
+12,ref
->ttl
);
993 SSVAL(pdata
,offset
+16,uni_reqpathoffset1
-offset
);
994 SSVAL(pdata
,offset
+18,uni_reqpathoffset2
-offset
);
995 /* copy referred path into current offset */
996 unilen
= rpcstr_push(pdata
+uni_curroffset
,
998 reply_size
- uni_curroffset
,
1001 SSVAL(pdata
,offset
+20,uni_curroffset
-offset
);
1003 uni_curroffset
+= unilen
;
1004 offset
+= VERSION2_REFERRAL_SIZE
;
1006 /* add in the unexplained 22 (0x16) bytes at the end */
1007 memset(pdata
+uni_curroffset
,'\0',0x16);
1011 static int setup_ver3_dfs_referral(const char *pathname
,
1013 struct junction_map
*junction
,
1016 char *pdata
= *ppdata
;
1018 smb_ucs2_t
*uni_reqpath
= NULL
;
1019 int uni_reqpathoffset1
, uni_reqpathoffset2
;
1026 DEBUG(10,("setting up version3 referral\n"));
1028 reqpathlen
= rpcstr_push_talloc(talloc_tos(), &uni_reqpath
, pathname
);
1029 if (uni_reqpath
== NULL
|| reqpathlen
== 0) {
1034 dump_data(0, (unsigned char *)uni_reqpath
,
1038 uni_reqpathoffset1
= REFERRAL_HEADER_SIZE
+
1039 VERSION3_REFERRAL_SIZE
* junction
->referral_count
;
1040 uni_reqpathoffset2
= uni_reqpathoffset1
+ reqpathlen
;
1041 reply_size
= uni_curroffset
= uni_reqpathoffset2
+ reqpathlen
;
1043 for(i
=0;i
<junction
->referral_count
;i
++) {
1044 DEBUG(10,("referral %u : %s\n",
1046 junction
->referral_list
[i
].alternate_path
));
1048 (strlen(junction
->referral_list
[i
].alternate_path
)+1)*2;
1051 pdata
= (char *)SMB_REALLOC(pdata
,reply_size
);
1053 DEBUG(0,("version3 referral setup:"
1054 "malloc failed for Realloc!\n"));
1059 /* create the header */
1060 SSVAL(pdata
,0,reqpathlen
- 2); /* UCS2 of path consumed minus
1062 SSVAL(pdata
,2,junction
->referral_count
); /* number of referral */
1064 SIVAL(pdata
,4,DFSREF_REFERRAL_SERVER
| DFSREF_STORAGE_SERVER
);
1066 SIVAL(pdata
,4,DFSREF_STORAGE_SERVER
);
1069 /* copy in the reqpaths */
1070 memcpy(pdata
+uni_reqpathoffset1
,uni_reqpath
,reqpathlen
);
1071 memcpy(pdata
+uni_reqpathoffset2
,uni_reqpath
,reqpathlen
);
1074 for(i
=0;i
<junction
->referral_count
;i
++) {
1075 struct referral
* ref
= &(junction
->referral_list
[i
]);
1078 SSVAL(pdata
,offset
,3); /* version 3 */
1079 SSVAL(pdata
,offset
+2,VERSION3_REFERRAL_SIZE
);
1081 SSVAL(pdata
,offset
+4,1);
1083 SSVAL(pdata
,offset
+4,0);
1086 /* ref_flags :use path_consumed bytes? */
1087 SSVAL(pdata
,offset
+6,0);
1088 SIVAL(pdata
,offset
+8,ref
->ttl
);
1090 SSVAL(pdata
,offset
+12,uni_reqpathoffset1
-offset
);
1091 SSVAL(pdata
,offset
+14,uni_reqpathoffset2
-offset
);
1092 /* copy referred path into current offset */
1093 unilen
= rpcstr_push(pdata
+uni_curroffset
,ref
->alternate_path
,
1094 reply_size
- uni_curroffset
,
1095 STR_UNICODE
| STR_TERMINATE
);
1096 SSVAL(pdata
,offset
+16,uni_curroffset
-offset
);
1097 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
1098 memset(pdata
+offset
+18,'\0',16);
1100 uni_curroffset
+= unilen
;
1101 offset
+= VERSION3_REFERRAL_SIZE
;
1106 /******************************************************************
1107 Set up the DFS referral for the dfs pathname. This call returns
1108 the amount of the path covered by this server, and where the
1109 client should be redirected to. This is the meat of the
1110 TRANS2_GET_DFS_REFERRAL call.
1111 ******************************************************************/
1113 int setup_dfs_referral(connection_struct
*orig_conn
,
1114 const char *dfs_path
,
1115 int max_referral_level
,
1116 char **ppdata
, NTSTATUS
*pstatus
)
1118 struct junction_map
*junction
= NULL
;
1119 int consumedcnt
= 0;
1120 bool self_referral
= False
;
1122 char *pathnamep
= NULL
;
1123 char *local_dfs_path
= NULL
;
1126 if (!(ctx
=talloc_init("setup_dfs_referral"))) {
1127 *pstatus
= NT_STATUS_NO_MEMORY
;
1131 /* get the junction entry */
1133 talloc_destroy(ctx
);
1134 *pstatus
= NT_STATUS_NOT_FOUND
;
1139 * Trim pathname sent by client so it begins with only one backslash.
1140 * Two backslashes confuse some dfs clients
1143 local_dfs_path
= talloc_strdup(ctx
,dfs_path
);
1144 if (!local_dfs_path
) {
1145 *pstatus
= NT_STATUS_NO_MEMORY
;
1146 talloc_destroy(ctx
);
1149 pathnamep
= local_dfs_path
;
1150 while (IS_DIRECTORY_SEP(pathnamep
[0]) &&
1151 IS_DIRECTORY_SEP(pathnamep
[1])) {
1155 junction
= TALLOC_ZERO_P(ctx
, struct junction_map
);
1157 *pstatus
= NT_STATUS_NO_MEMORY
;
1158 talloc_destroy(ctx
);
1162 /* The following call can change cwd. */
1163 *pstatus
= get_referred_path(ctx
, pathnamep
, junction
,
1164 &consumedcnt
, &self_referral
);
1165 if (!NT_STATUS_IS_OK(*pstatus
)) {
1166 vfs_ChDir(orig_conn
,orig_conn
->connectpath
);
1167 talloc_destroy(ctx
);
1170 vfs_ChDir(orig_conn
,orig_conn
->connectpath
);
1172 if (!self_referral
) {
1173 pathnamep
[consumedcnt
] = '\0';
1175 if( DEBUGLVL( 3 ) ) {
1177 dbgtext("setup_dfs_referral: Path %s to "
1178 "alternate path(s):",
1180 for(i
=0;i
<junction
->referral_count
;i
++)
1182 junction
->referral_list
[i
].alternate_path
);
1187 /* create the referral depeding on version */
1188 DEBUG(10,("max_referral_level :%d\n",max_referral_level
));
1190 if (max_referral_level
< 2) {
1191 max_referral_level
= 2;
1193 if (max_referral_level
> 3) {
1194 max_referral_level
= 3;
1197 switch(max_referral_level
) {
1199 reply_size
= setup_ver2_dfs_referral(pathnamep
,
1204 reply_size
= setup_ver3_dfs_referral(pathnamep
, ppdata
,
1205 junction
, self_referral
);
1208 DEBUG(0,("setup_dfs_referral: Invalid dfs referral "
1210 max_referral_level
));
1211 talloc_destroy(ctx
);
1212 *pstatus
= NT_STATUS_INVALID_LEVEL
;
1217 DEBUGADD(0,("DFS Referral pdata:\n"));
1218 dump_data(0,(uint8
*)*ppdata
,reply_size
);
1221 talloc_destroy(ctx
);
1222 *pstatus
= NT_STATUS_OK
;
1226 /**********************************************************************
1227 The following functions are called by the NETDFS RPC pipe functions
1228 **********************************************************************/
1230 /*********************************************************************
1231 Creates a junction structure from a DFS pathname
1232 **********************************************************************/
1234 bool create_junction(TALLOC_CTX
*ctx
,
1235 const char *dfs_path
,
1236 struct junction_map
*jucn
)
1240 struct dfs_path
*pdp
= TALLOC_P(ctx
,struct dfs_path
);
1246 status
= parse_dfs_path(NULL
, dfs_path
, False
, pdp
, &dummy
);
1247 if (!NT_STATUS_IS_OK(status
)) {
1251 /* check if path is dfs : validate first token */
1252 if (!is_myname_or_ipaddr(pdp
->hostname
)) {
1253 DEBUG(4,("create_junction: Invalid hostname %s "
1255 pdp
->hostname
, dfs_path
));
1260 /* Check for a non-DFS share */
1261 snum
= lp_servicenumber(pdp
->servicename
);
1263 if(snum
< 0 || !lp_msdfs_root(snum
)) {
1264 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1270 jucn
->service_name
= talloc_strdup(ctx
, pdp
->servicename
);
1271 jucn
->volume_name
= talloc_strdup(ctx
, pdp
->reqpath
);
1272 jucn
->comment
= talloc_strdup(ctx
, lp_comment(snum
));
1275 if (!jucn
->service_name
|| !jucn
->volume_name
|| ! jucn
->comment
) {
1281 /**********************************************************************
1282 Forms a valid Unix pathname from the junction
1283 **********************************************************************/
1285 static bool junction_to_local_path(const struct junction_map
*jucn
,
1287 connection_struct
*conn_out
)
1291 snum
= lp_servicenumber(jucn
->service_name
);
1295 if (!NT_STATUS_IS_OK(create_conn_struct(talloc_tos(),
1297 lp_pathname(snum
)))) {
1301 *pp_path_out
= talloc_asprintf(conn_out
->mem_ctx
,
1305 if (!*pp_path_out
) {
1311 bool create_msdfs_link(const struct junction_map
*jucn
)
1314 char *msdfs_link
= NULL
;
1315 connection_struct conns
;
1316 connection_struct
*conn
= &conns
;
1318 bool insert_comma
= False
;
1323 if(!junction_to_local_path(jucn
, &path
, conn
)) {
1327 /* Form the msdfs_link contents */
1328 msdfs_link
= talloc_strdup(conn
->mem_ctx
, "msdfs:");
1332 for(i
=0; i
<jucn
->referral_count
; i
++) {
1333 char *refpath
= jucn
->referral_list
[i
].alternate_path
;
1335 /* Alternate paths always use Windows separators. */
1336 trim_char(refpath
, '\\', '\\');
1337 if(*refpath
== '\0') {
1339 insert_comma
= False
;
1343 if (i
> 0 && insert_comma
) {
1344 msdfs_link
= talloc_asprintf_append_buffer(msdfs_link
,
1348 msdfs_link
= talloc_asprintf_append_buffer(msdfs_link
,
1356 if (!insert_comma
) {
1357 insert_comma
= True
;
1361 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1364 if(SMB_VFS_SYMLINK(conn
, msdfs_link
, path
) < 0) {
1365 if (errno
== EEXIST
) {
1366 if(SMB_VFS_UNLINK(conn
,path
)!=0) {
1370 if (SMB_VFS_SYMLINK(conn
, msdfs_link
, path
) < 0) {
1371 DEBUG(1,("create_msdfs_link: symlink failed "
1372 "%s -> %s\nError: %s\n",
1373 path
, msdfs_link
, strerror(errno
)));
1382 conn_free_internal(conn
);
1386 bool remove_msdfs_link(const struct junction_map
*jucn
)
1389 connection_struct conns
;
1390 connection_struct
*conn
= &conns
;
1395 if( junction_to_local_path(jucn
, &path
, conn
) ) {
1396 if( SMB_VFS_UNLINK(conn
, path
) == 0 ) {
1401 conn_free_internal(conn
);
1405 /*********************************************************************
1406 Return the number of DFS links at the root of this share.
1407 *********************************************************************/
1409 static int count_dfs_links(TALLOC_CTX
*ctx
, int snum
)
1412 SMB_STRUCT_DIR
*dirp
= NULL
;
1414 const char *connect_path
= lp_pathname(snum
);
1415 const char *msdfs_proxy
= lp_msdfs_proxy(snum
);
1416 connection_struct conn
;
1420 if(*connect_path
== '\0') {
1425 * Fake up a connection struct for the VFS layer.
1428 if (!NT_STATUS_IS_OK(create_conn_struct(talloc_tos(),
1429 &conn
, snum
, connect_path
))) {
1433 /* Count a link for the msdfs root - convention */
1436 /* No more links if this is an msdfs proxy. */
1437 if (*msdfs_proxy
!= '\0') {
1441 /* Now enumerate all dfs links */
1442 dirp
= SMB_VFS_OPENDIR(&conn
, ".", NULL
, 0);
1447 while ((dname
= vfs_readdirname(&conn
, dirp
)) != NULL
) {
1448 if (is_msdfs_link(&conn
,
1455 SMB_VFS_CLOSEDIR(&conn
,dirp
);
1459 conn_free_internal(&conn
);
1463 /*********************************************************************
1464 *********************************************************************/
1466 static int form_junctions(TALLOC_CTX
*ctx
,
1468 struct junction_map
*jucn
,
1472 SMB_STRUCT_DIR
*dirp
= NULL
;
1474 const char *connect_path
= lp_pathname(snum
);
1475 char *service_name
= lp_servicename(snum
);
1476 const char *msdfs_proxy
= lp_msdfs_proxy(snum
);
1477 connection_struct conn
;
1478 struct referral
*ref
= NULL
;
1482 if (jn_remain
== 0) {
1486 if(*connect_path
== '\0') {
1491 * Fake up a connection struct for the VFS layer.
1494 if (!NT_STATUS_IS_OK(create_conn_struct(ctx
, &conn
, snum
, connect_path
))) {
1498 /* form a junction for the msdfs root - convention
1499 DO NOT REMOVE THIS: NT clients will not work with us
1500 if this is not present
1502 jucn
[cnt
].service_name
= talloc_strdup(ctx
,service_name
);
1503 jucn
[cnt
].volume_name
= talloc_strdup(ctx
, "");
1504 if (!jucn
[cnt
].service_name
|| !jucn
[cnt
].volume_name
) {
1507 jucn
[cnt
].comment
= "";
1508 jucn
[cnt
].referral_count
= 1;
1510 ref
= jucn
[cnt
].referral_list
= TALLOC_ZERO_P(ctx
, struct referral
);
1511 if (jucn
[cnt
].referral_list
== NULL
) {
1516 ref
->ttl
= REFERRAL_TTL
;
1517 if (*msdfs_proxy
!= '\0') {
1518 ref
->alternate_path
= talloc_strdup(ctx
,
1521 ref
->alternate_path
= talloc_asprintf(ctx
,
1523 get_local_machine_name(),
1527 if (!ref
->alternate_path
) {
1532 /* Don't enumerate if we're an msdfs proxy. */
1533 if (*msdfs_proxy
!= '\0') {
1537 /* Now enumerate all dfs links */
1538 dirp
= SMB_VFS_OPENDIR(&conn
, ".", NULL
, 0);
1543 while ((dname
= vfs_readdirname(&conn
, dirp
)) != NULL
) {
1544 char *link_target
= NULL
;
1545 if (cnt
>= jn_remain
) {
1546 DEBUG(2, ("form_junctions: ran out of MSDFS "
1550 if (is_msdfs_link_internal(ctx
,
1552 dname
, &link_target
,
1554 if (parse_msdfs_symlink(ctx
,
1556 &jucn
[cnt
].referral_list
,
1557 &jucn
[cnt
].referral_count
)) {
1559 jucn
[cnt
].service_name
= talloc_strdup(ctx
,
1561 jucn
[cnt
].volume_name
= talloc_strdup(ctx
,
1563 if (!jucn
[cnt
].service_name
||
1564 !jucn
[cnt
].volume_name
) {
1567 jucn
[cnt
].comment
= "";
1570 TALLOC_FREE(link_target
);
1577 SMB_VFS_CLOSEDIR(&conn
,dirp
);
1580 conn_free_internal(&conn
);
1584 struct junction_map
*enum_msdfs_links(TALLOC_CTX
*ctx
, size_t *p_num_jn
)
1586 struct junction_map
*jn
= NULL
;
1588 size_t jn_count
= 0;
1592 if(!lp_host_msdfs()) {
1596 /* Ensure all the usershares are loaded. */
1598 load_registry_shares();
1599 sharecount
= load_usershare_shares();
1602 for(i
=0;i
< sharecount
;i
++) {
1603 if(lp_msdfs_root(i
)) {
1604 jn_count
+= count_dfs_links(ctx
, i
);
1607 if (jn_count
== 0) {
1610 jn
= TALLOC_ARRAY(ctx
, struct junction_map
, jn_count
);
1614 for(i
=0; i
< sharecount
; i
++) {
1615 if (*p_num_jn
>= jn_count
) {
1618 if(lp_msdfs_root(i
)) {
1619 *p_num_jn
+= form_junctions(ctx
, i
,
1621 jn_count
- *p_num_jn
);
1627 /******************************************************************************
1628 Core function to resolve a dfs pathname.
1629 ******************************************************************************/
1631 NTSTATUS
resolve_dfspath(TALLOC_CTX
*ctx
,
1632 connection_struct
*conn
,
1634 const char *name_in
,
1637 NTSTATUS status
= NT_STATUS_OK
;
1639 if (dfs_pathnames
) {
1640 status
= dfs_redirect(ctx
,
1648 * Cheat and just return a copy of the in ptr.
1649 * Once srvstr_get_path() uses talloc it'll
1650 * be a talloced ptr anyway.
1652 *pp_name_out
= CONST_DISCARD(char *,name_in
);
1657 /******************************************************************************
1658 Core function to resolve a dfs pathname possibly containing a wildcard.
1659 This function is identical to the above except for the bool param to
1660 dfs_redirect but I need this to be separate so it's really clear when
1661 we're allowing wildcards and when we're not. JRA.
1662 ******************************************************************************/
1664 NTSTATUS
resolve_dfspath_wcard(TALLOC_CTX
*ctx
,
1665 connection_struct
*conn
,
1667 const char *name_in
,
1669 bool *ppath_contains_wcard
)
1671 NTSTATUS status
= NT_STATUS_OK
;
1672 if (dfs_pathnames
) {
1673 status
= dfs_redirect(ctx
,
1678 ppath_contains_wcard
);
1681 * Cheat and just return a copy of the in ptr.
1682 * Once srvstr_get_path() uses talloc it'll
1683 * be a talloced ptr anyway.
1685 *pp_name_out
= CONST_DISCARD(char *,name_in
);