The compatibility function also should have a const buffer pointer
[Samba/gbeck.git] / source3 / smbd / msdfs.c
blob8e83a6c17ec9bf7df58ed65026dfb81286a18d6f
1 /*
2 Unix SMB/Netbios implementation.
3 Version 3.0
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
24 #include "includes.h"
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....
45 JRA.
46 **********************************************************************/
48 static NTSTATUS parse_dfs_path(connection_struct *conn,
49 const char *pathname,
50 bool allow_wcards,
51 struct dfs_path *pdp, /* MUST BE TALLOCED */
52 bool *ppath_contains_wcard)
54 char *pathname_local;
55 char *p,*temp;
56 char *servicename;
57 char *eos_ptr;
58 NTSTATUS status = NT_STATUS_OK;
59 char sepchar;
61 ZERO_STRUCTP(pdp);
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",
83 pathname, sepchar ));
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();
94 p = temp;
95 DEBUG(10,("parse_dfs_path: trying to convert %s to a "
96 "local path\n",
97 temp));
98 goto local_path;
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",
108 temp, sepchar));
110 /* Now tokenize. */
111 /* Parse out hostname. */
112 p = strchr_m(temp,sepchar);
113 if(p == NULL) {
114 DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
115 temp));
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; /* "" */
124 p = temp;
125 DEBUG(10,("parse_dfs_path: trying to convert %s "
126 "to a local path\n",
127 temp));
128 goto local_path;
130 *p = '\0';
131 pdp->hostname = temp;
133 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
135 /* Parse out servicename. */
136 servicename = p+1;
137 p = strchr_m(servicename,sepchar);
138 if (p) {
139 *p = '\0';
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",
148 servicename));
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
159 we nulled out */
160 servicename--;
161 *servicename = sepchar;
162 if (p) {
163 *p = sepchar;
166 p = temp;
167 DEBUG(10,("parse_dfs_path: trying to convert %s "
168 "to a local path\n",
169 temp));
170 goto local_path;
173 pdp->servicename = servicename;
175 DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
177 if(p == NULL) {
178 /* Client sent self referral \server\share. */
179 pdp->reqpath = eos_ptr; /* "" */
180 return NT_STATUS_OK;
183 p++;
185 local_path:
187 *ppath_contains_wcard = False;
189 pdp->reqpath = p;
191 /* Rest is reqpath. */
192 if (pdp->posix_path) {
193 status = check_path_syntax_posix(pdp->reqpath);
194 } else {
195 if (allow_wcards) {
196 status = check_path_syntax_wcard(pdp->reqpath,
197 ppath_contains_wcard);
198 } else {
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) ));
206 return status;
209 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
210 return NT_STATUS_OK;
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 **pconn,
220 int snum,
221 const char *path,
222 char **poldcwd)
224 connection_struct *conn;
225 char *connpath;
226 char *oldcwd;
228 conn = TALLOC_ZERO_P(ctx, connection_struct);
229 if (conn == NULL) {
230 return NT_STATUS_NO_MEMORY;
233 connpath = talloc_strdup(conn, path);
234 if (!connpath) {
235 TALLOC_FREE(conn);
236 return NT_STATUS_NO_MEMORY;
238 connpath = talloc_string_sub(conn,
239 connpath,
240 "%S",
241 lp_servicename(snum));
242 if (!connpath) {
243 TALLOC_FREE(conn);
244 return NT_STATUS_NO_MEMORY;
247 /* needed for smbd_vfs_init() */
249 if (!(conn->params = TALLOC_ZERO_P(conn, struct share_params))) {
250 DEBUG(0, ("TALLOC failed\n"));
251 TALLOC_FREE(conn);
252 return NT_STATUS_NO_MEMORY;
255 conn->params->service = snum;
257 set_conn_connectpath(conn, connpath);
259 if (!smbd_vfs_init(conn)) {
260 NTSTATUS status = map_nt_error_from_unix(errno);
261 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
262 conn_free_internal(conn);
263 return status;
267 * Windows seems to insist on doing trans2getdfsreferral() calls on
268 * the IPC$ share as the anonymous user. If we try to chdir as that
269 * user we will fail.... WTF ? JRA.
272 oldcwd = vfs_GetWd(ctx, conn);
273 if (oldcwd == NULL) {
274 NTSTATUS status = map_nt_error_from_unix(errno);
275 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
276 conn_free_internal(conn);
277 return status;
280 if (vfs_ChDir(conn,conn->connectpath) != 0) {
281 NTSTATUS status = map_nt_error_from_unix(errno);
282 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
283 "Error was %s\n",
284 conn->connectpath, strerror(errno) ));
285 conn_free_internal(conn);
286 return status;
289 *pconn = conn;
290 *poldcwd = oldcwd;
292 return NT_STATUS_OK;
295 /**********************************************************************
296 Parse the contents of a symlink to verify if it is an msdfs referral
297 A valid referral is of the form:
299 msdfs:server1\share1,server2\share2
300 msdfs:server1\share1\pathname,server2\share2\pathname
301 msdfs:server1/share1,server2/share2
302 msdfs:server1/share1/pathname,server2/share2/pathname.
304 Note that the alternate paths returned here must be of the canonicalized
305 form:
307 \server\share or
308 \server\share\path\to\file,
310 even in posix path mode. This is because we have no knowledge if the
311 server we're referring to understands posix paths.
312 **********************************************************************/
314 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
315 const char *target,
316 struct referral **preflist,
317 int *refcount)
319 char *temp = NULL;
320 char *prot;
321 char **alt_path = NULL;
322 int count = 0, i;
323 struct referral *reflist;
324 char *saveptr;
326 temp = talloc_strdup(ctx, target);
327 if (!temp) {
328 return False;
330 prot = strtok_r(temp, ":", &saveptr);
331 if (!prot) {
332 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
333 return False;
336 alt_path = TALLOC_ARRAY(ctx, char *, MAX_REFERRAL_COUNT);
337 if (!alt_path) {
338 return False;
341 /* parse out the alternate paths */
342 while((count<MAX_REFERRAL_COUNT) &&
343 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
344 count++;
347 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
349 if (count) {
350 reflist = *preflist = TALLOC_ZERO_ARRAY(ctx,
351 struct referral, count);
352 if(reflist == NULL) {
353 TALLOC_FREE(alt_path);
354 return False;
356 } else {
357 reflist = *preflist = NULL;
360 for(i=0;i<count;i++) {
361 char *p;
363 /* Canonicalize link target.
364 * Replace all /'s in the path by a \ */
365 string_replace(alt_path[i], '/', '\\');
367 /* Remove leading '\\'s */
368 p = alt_path[i];
369 while (*p && (*p == '\\')) {
370 p++;
373 reflist[i].alternate_path = talloc_asprintf(ctx,
374 "\\%s",
376 if (!reflist[i].alternate_path) {
377 return False;
380 reflist[i].proximity = 0;
381 reflist[i].ttl = REFERRAL_TTL;
382 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
383 reflist[i].alternate_path));
386 *refcount = count;
388 TALLOC_FREE(alt_path);
389 return True;
392 /**********************************************************************
393 Returns true if the unix path is a valid msdfs symlink and also
394 returns the target string from inside the link.
395 **********************************************************************/
397 static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
398 connection_struct *conn,
399 const char *path,
400 char **pp_link_target,
401 SMB_STRUCT_STAT *sbufp)
403 SMB_STRUCT_STAT st;
404 int referral_len = 0;
405 char link_target_buf[7];
406 size_t bufsize = 0;
407 char *link_target = NULL;
409 if (pp_link_target) {
410 bufsize = 1024;
411 link_target = TALLOC_ARRAY(ctx, char, bufsize);
412 if (!link_target) {
413 return False;
415 *pp_link_target = link_target;
416 } else {
417 bufsize = sizeof(link_target_buf);
418 link_target = link_target_buf;
421 if (sbufp == NULL) {
422 sbufp = &st;
425 if (SMB_VFS_LSTAT(conn, path, sbufp) != 0) {
426 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
427 path));
428 goto err;
431 if (!S_ISLNK(sbufp->st_mode)) {
432 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
433 path));
434 goto err;
437 referral_len = SMB_VFS_READLINK(conn, path, link_target, bufsize - 1);
438 if (referral_len == -1) {
439 DEBUG(0,("is_msdfs_link_read_target: Error reading "
440 "msdfs link %s: %s\n",
441 path, strerror(errno)));
442 goto err;
444 link_target[referral_len] = '\0';
446 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path,
447 link_target));
449 if (!strnequal(link_target, "msdfs:", 6)) {
450 goto err;
452 return True;
454 err:
456 if (link_target != link_target_buf) {
457 TALLOC_FREE(link_target);
459 return False;
462 /**********************************************************************
463 Returns true if the unix path is a valid msdfs symlink.
464 **********************************************************************/
466 bool is_msdfs_link(connection_struct *conn,
467 const char *path,
468 SMB_STRUCT_STAT *sbufp)
470 return is_msdfs_link_internal(talloc_tos(),
471 conn,
472 path,
473 NULL,
474 sbufp);
477 /*****************************************************************
478 Used by other functions to decide if a dfs path is remote,
479 and to get the list of referred locations for that remote path.
481 search_flag: For findfirsts, dfs links themselves are not
482 redirected, but paths beyond the links are. For normal smb calls,
483 even dfs links need to be redirected.
485 consumedcntp: how much of the dfs path is being redirected. the client
486 should try the remaining path on the redirected server.
488 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
489 link redirect are in targetpath.
490 *****************************************************************/
492 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
493 connection_struct *conn,
494 const char *dfspath, /* Incoming complete dfs path */
495 const struct dfs_path *pdp, /* Parsed out
496 server+share+extrapath. */
497 bool search_flag, /* Called from a findfirst ? */
498 int *consumedcntp,
499 char **pp_targetpath)
501 char *p = NULL;
502 char *q = NULL;
503 SMB_STRUCT_STAT sbuf;
504 NTSTATUS status;
505 char *localpath = NULL;
506 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
507 components). */
509 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
510 conn->connectpath, pdp->reqpath));
513 * Note the unix path conversion here we're doing we can
514 * throw away. We're looking for a symlink for a dfs
515 * resolution, if we don't find it we'll do another
516 * unix_convert later in the codepath.
517 * If we needed to remember what we'd resolved in
518 * dp->reqpath (as the original code did) we'd
519 * copy (localhost, dp->reqpath) on any code
520 * path below that returns True - but I don't
521 * think this is needed. JRA.
524 status = unix_convert(ctx, conn, pdp->reqpath, search_flag, &localpath,
525 NULL, &sbuf);
526 if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status,
527 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
528 return status;
531 /* Optimization - check if we can redirect the whole path. */
533 if (is_msdfs_link_internal(ctx, conn, localpath, pp_targetpath, NULL)) {
534 if (search_flag) {
535 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
536 "for dfs link %s.\n", dfspath));
537 return NT_STATUS_OK;
540 DEBUG(6,("dfs_path_lookup: %s resolves to a "
541 "valid dfs link %s.\n", dfspath,
542 pp_targetpath ? *pp_targetpath : ""));
544 if (consumedcntp) {
545 *consumedcntp = strlen(dfspath);
547 return NT_STATUS_PATH_NOT_COVERED;
550 /* Prepare to test only for '/' components in the given path,
551 * so if a Windows path replace all '\\' characters with '/'.
552 * For a POSIX DFS path we know all separators are already '/'. */
554 canon_dfspath = talloc_strdup(ctx, dfspath);
555 if (!canon_dfspath) {
556 return NT_STATUS_NO_MEMORY;
558 if (!pdp->posix_path) {
559 string_replace(canon_dfspath, '\\', '/');
563 * localpath comes out of unix_convert, so it has
564 * no trailing backslash. Make sure that canon_dfspath hasn't either.
565 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
568 trim_char(canon_dfspath,0,'/');
571 * Redirect if any component in the path is a link.
572 * We do this by walking backwards through the
573 * local path, chopping off the last component
574 * in both the local path and the canonicalized
575 * DFS path. If we hit a DFS link then we're done.
578 p = strrchr_m(localpath, '/');
579 if (consumedcntp) {
580 q = strrchr_m(canon_dfspath, '/');
583 while (p) {
584 *p = '\0';
585 if (q) {
586 *q = '\0';
589 if (is_msdfs_link_internal(ctx, conn,
590 localpath, pp_targetpath, NULL)) {
591 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
592 "parent %s is dfs link\n", dfspath, localpath));
594 if (consumedcntp) {
595 *consumedcntp = strlen(canon_dfspath);
596 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
597 "(%d)\n",
598 canon_dfspath,
599 *consumedcntp));
602 return NT_STATUS_PATH_NOT_COVERED;
605 /* Step back on the filesystem. */
606 p = strrchr_m(localpath, '/');
608 if (consumedcntp) {
609 /* And in the canonicalized dfs path. */
610 q = strrchr_m(canon_dfspath, '/');
614 return NT_STATUS_OK;
617 /*****************************************************************
618 Decides if a dfs pathname should be redirected or not.
619 If not, the pathname is converted to a tcon-relative local unix path
621 search_wcard_flag: this flag performs 2 functions both related
622 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
623 for details.
625 This function can return NT_STATUS_OK, meaning use the returned path as-is
626 (mapped into a local path).
627 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
628 any other NT_STATUS error which is a genuine error to be
629 returned to the client.
630 *****************************************************************/
632 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
633 connection_struct *conn,
634 const char *path_in,
635 bool search_wcard_flag,
636 char **pp_path_out,
637 bool *ppath_contains_wcard)
639 NTSTATUS status;
640 struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
642 if (!pdp) {
643 return NT_STATUS_NO_MEMORY;
646 status = parse_dfs_path(conn, path_in, search_wcard_flag, pdp,
647 ppath_contains_wcard);
648 if (!NT_STATUS_IS_OK(status)) {
649 TALLOC_FREE(pdp);
650 return status;
653 if (pdp->reqpath[0] == '\0') {
654 TALLOC_FREE(pdp);
655 *pp_path_out = talloc_strdup(ctx, "");
656 if (!*pp_path_out) {
657 return NT_STATUS_NO_MEMORY;
659 DEBUG(5,("dfs_redirect: self-referral.\n"));
660 return NT_STATUS_OK;
663 /* If dfs pathname for a non-dfs share, convert to tcon-relative
664 path and return OK */
666 if (!lp_msdfs_root(SNUM(conn))) {
667 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
668 TALLOC_FREE(pdp);
669 if (!*pp_path_out) {
670 return NT_STATUS_NO_MEMORY;
672 return NT_STATUS_OK;
675 /* If it looked like a local path (zero hostname/servicename)
676 * just treat as a tcon-relative path. */
678 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
679 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
680 TALLOC_FREE(pdp);
681 if (!*pp_path_out) {
682 return NT_STATUS_NO_MEMORY;
684 return NT_STATUS_OK;
687 if (!( strequal(pdp->servicename, lp_servicename(SNUM(conn)))
688 || (strequal(pdp->servicename, HOMES_NAME)
689 && strequal(lp_servicename(SNUM(conn)),
690 conn->server_info->sanitized_username) )) ) {
692 /* The given sharename doesn't match this connection. */
693 TALLOC_FREE(pdp);
695 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
698 status = dfs_path_lookup(ctx, conn, path_in, pdp,
699 search_wcard_flag, NULL, NULL);
700 if (!NT_STATUS_IS_OK(status)) {
701 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
702 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
703 } else {
704 DEBUG(10,("dfs_redirect: dfs_path_lookup "
705 "failed for %s with %s\n",
706 path_in, nt_errstr(status) ));
708 return status;
711 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
713 /* Form non-dfs tcon-relative path */
714 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
715 TALLOC_FREE(pdp);
716 if (!*pp_path_out) {
717 return NT_STATUS_NO_MEMORY;
720 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
721 path_in,
722 *pp_path_out));
724 return NT_STATUS_OK;
727 /**********************************************************************
728 Return a self referral.
729 **********************************************************************/
731 static NTSTATUS self_ref(TALLOC_CTX *ctx,
732 const char *dfs_path,
733 struct junction_map *jucn,
734 int *consumedcntp,
735 bool *self_referralp)
737 struct referral *ref;
739 *self_referralp = True;
741 jucn->referral_count = 1;
742 if((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
743 return NT_STATUS_NO_MEMORY;
746 ref->alternate_path = talloc_strdup(ctx, dfs_path);
747 if (!ref->alternate_path) {
748 return NT_STATUS_NO_MEMORY;
750 ref->proximity = 0;
751 ref->ttl = REFERRAL_TTL;
752 jucn->referral_list = ref;
753 *consumedcntp = strlen(dfs_path);
754 return NT_STATUS_OK;
757 /**********************************************************************
758 Gets valid referrals for a dfs path and fills up the
759 junction_map structure.
760 **********************************************************************/
762 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
763 const char *dfs_path,
764 struct junction_map *jucn,
765 int *consumedcntp,
766 bool *self_referralp)
768 struct connection_struct *conn;
769 char *targetpath = NULL;
770 int snum;
771 NTSTATUS status = NT_STATUS_NOT_FOUND;
772 bool dummy;
773 struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
774 char *oldpath;
776 if (!pdp) {
777 return NT_STATUS_NO_MEMORY;
780 *self_referralp = False;
782 status = parse_dfs_path(NULL, dfs_path, False, pdp, &dummy);
783 if (!NT_STATUS_IS_OK(status)) {
784 return status;
787 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
788 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
789 if (!jucn->service_name || !jucn->volume_name) {
790 TALLOC_FREE(pdp);
791 return NT_STATUS_NO_MEMORY;
794 /* Verify the share is a dfs root */
795 snum = lp_servicenumber(jucn->service_name);
796 if(snum < 0) {
797 fstring service_name;
798 fstrcpy(service_name, jucn->service_name);
799 if ((snum = find_service(service_name)) < 0) {
800 return NT_STATUS_NOT_FOUND;
802 TALLOC_FREE(jucn->service_name);
803 jucn->service_name = talloc_strdup(ctx, service_name);
804 if (!jucn->service_name) {
805 TALLOC_FREE(pdp);
806 return NT_STATUS_NO_MEMORY;
810 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(snum) == '\0')) {
811 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
812 "a dfs root.\n",
813 pdp->servicename, dfs_path));
814 TALLOC_FREE(pdp);
815 return NT_STATUS_NOT_FOUND;
819 * Self referrals are tested with a anonymous IPC connection and
820 * a GET_DFS_REFERRAL call to \\server\share. (which means
821 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
822 * into the directory and will fail if it cannot (as the anonymous
823 * user). Cope with this.
826 if (pdp->reqpath[0] == '\0') {
827 char *tmp;
828 struct referral *ref;
830 if (*lp_msdfs_proxy(snum) == '\0') {
831 TALLOC_FREE(pdp);
832 return self_ref(ctx,
833 dfs_path,
834 jucn,
835 consumedcntp,
836 self_referralp);
840 * It's an msdfs proxy share. Redirect to
841 * the configured target share.
844 jucn->referral_count = 1;
845 if ((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
846 TALLOC_FREE(pdp);
847 return NT_STATUS_NO_MEMORY;
850 if (!(tmp = talloc_strdup(ctx, lp_msdfs_proxy(snum)))) {
851 TALLOC_FREE(pdp);
852 return NT_STATUS_NO_MEMORY;
855 trim_string(tmp, "\\", 0);
857 ref->alternate_path = talloc_asprintf(ctx, "\\%s", tmp);
858 TALLOC_FREE(tmp);
860 if (!ref->alternate_path) {
861 TALLOC_FREE(pdp);
862 return NT_STATUS_NO_MEMORY;
865 if (pdp->reqpath[0] != '\0') {
866 ref->alternate_path = talloc_asprintf_append(
867 ref->alternate_path,
868 "%s",
869 pdp->reqpath);
870 if (!ref->alternate_path) {
871 TALLOC_FREE(pdp);
872 return NT_STATUS_NO_MEMORY;
875 ref->proximity = 0;
876 ref->ttl = REFERRAL_TTL;
877 jucn->referral_list = ref;
878 *consumedcntp = strlen(dfs_path);
879 TALLOC_FREE(pdp);
880 return NT_STATUS_OK;
883 status = create_conn_struct(ctx, &conn, snum, lp_pathname(snum),
884 &oldpath);
885 if (!NT_STATUS_IS_OK(status)) {
886 TALLOC_FREE(pdp);
887 return status;
890 /* If this is a DFS path dfs_lookup should return
891 * NT_STATUS_PATH_NOT_COVERED. */
893 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
894 False, consumedcntp, &targetpath);
896 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
897 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
898 dfs_path));
899 vfs_ChDir(conn, oldpath);
900 conn_free_internal(conn);
901 TALLOC_FREE(pdp);
902 return status;
905 /* We know this is a valid dfs link. Parse the targetpath. */
906 if (!parse_msdfs_symlink(ctx, targetpath,
907 &jucn->referral_list,
908 &jucn->referral_count)) {
909 DEBUG(3,("get_referred_path: failed to parse symlink "
910 "target %s\n", targetpath ));
911 vfs_ChDir(conn, oldpath);
912 conn_free_internal(conn);
913 TALLOC_FREE(pdp);
914 return NT_STATUS_NOT_FOUND;
917 vfs_ChDir(conn, oldpath);
918 conn_free_internal(conn);
919 TALLOC_FREE(pdp);
920 return NT_STATUS_OK;
923 static int setup_ver2_dfs_referral(const char *pathname,
924 char **ppdata,
925 struct junction_map *junction,
926 int consumedcnt,
927 bool self_referral)
929 char* pdata = *ppdata;
931 smb_ucs2_t *uni_requestedpath = NULL;
932 int uni_reqpathoffset1,uni_reqpathoffset2;
933 int uni_curroffset;
934 int requestedpathlen=0;
935 int offset;
936 int reply_size = 0;
937 int i=0;
939 DEBUG(10,("Setting up version2 referral\nRequested path:\n"));
941 requestedpathlen = rpcstr_push_talloc(talloc_tos(),
942 &uni_requestedpath, pathname);
943 if (uni_requestedpath == NULL || requestedpathlen == 0) {
944 return -1;
947 if (DEBUGLVL(10)) {
948 dump_data(0, (unsigned char *)uni_requestedpath,
949 requestedpathlen);
952 DEBUG(10,("ref count = %u\n",junction->referral_count));
954 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
955 VERSION2_REFERRAL_SIZE * junction->referral_count;
957 uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen;
959 uni_curroffset = uni_reqpathoffset2 + requestedpathlen;
961 reply_size = REFERRAL_HEADER_SIZE +
962 VERSION2_REFERRAL_SIZE*junction->referral_count +
963 2 * requestedpathlen;
964 DEBUG(10,("reply_size: %u\n",reply_size));
966 /* add up the unicode lengths of all the referral paths */
967 for(i=0;i<junction->referral_count;i++) {
968 DEBUG(10,("referral %u : %s\n",
970 junction->referral_list[i].alternate_path));
971 reply_size +=
972 (strlen(junction->referral_list[i].alternate_path)+1)*2;
975 DEBUG(10,("reply_size = %u\n",reply_size));
976 /* add the unexplained 0x16 bytes */
977 reply_size += 0x16;
979 pdata = (char *)SMB_REALLOC(pdata,reply_size);
980 if(pdata == NULL) {
981 DEBUG(0,("Realloc failed!\n"));
982 return -1;
984 *ppdata = pdata;
986 /* copy in the dfs requested paths.. required for offset calculations */
987 memcpy(pdata+uni_reqpathoffset1,uni_requestedpath,requestedpathlen);
988 memcpy(pdata+uni_reqpathoffset2,uni_requestedpath,requestedpathlen);
990 /* create the header */
991 SSVAL(pdata,0,consumedcnt * 2); /* path consumed */
992 /* number of referral in this pkt */
993 SSVAL(pdata,2,junction->referral_count);
994 if(self_referral) {
995 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
996 } else {
997 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
1000 offset = 8;
1001 /* add the referral elements */
1002 for(i=0;i<junction->referral_count;i++) {
1003 struct referral* ref = &junction->referral_list[i];
1004 int unilen;
1006 SSVAL(pdata,offset,2); /* version 2 */
1007 SSVAL(pdata,offset+2,VERSION2_REFERRAL_SIZE);
1008 if(self_referral) {
1009 SSVAL(pdata,offset+4,1);
1010 } else {
1011 SSVAL(pdata,offset+4,0);
1014 /* ref_flags :use path_consumed bytes? */
1015 SSVAL(pdata,offset+6,0);
1016 SIVAL(pdata,offset+8,ref->proximity);
1017 SIVAL(pdata,offset+12,ref->ttl);
1019 SSVAL(pdata,offset+16,uni_reqpathoffset1-offset);
1020 SSVAL(pdata,offset+18,uni_reqpathoffset2-offset);
1021 /* copy referred path into current offset */
1022 unilen = rpcstr_push(pdata+uni_curroffset,
1023 ref->alternate_path,
1024 reply_size - uni_curroffset,
1025 STR_UNICODE);
1027 SSVAL(pdata,offset+20,uni_curroffset-offset);
1029 uni_curroffset += unilen;
1030 offset += VERSION2_REFERRAL_SIZE;
1032 /* add in the unexplained 22 (0x16) bytes at the end */
1033 memset(pdata+uni_curroffset,'\0',0x16);
1034 return reply_size;
1037 static int setup_ver3_dfs_referral(const char *pathname,
1038 char **ppdata,
1039 struct junction_map *junction,
1040 int consumedcnt,
1041 bool self_referral)
1043 char *pdata = *ppdata;
1045 smb_ucs2_t *uni_reqpath = NULL;
1046 int uni_reqpathoffset1, uni_reqpathoffset2;
1047 int uni_curroffset;
1048 int reply_size = 0;
1050 int reqpathlen = 0;
1051 int offset,i=0;
1053 DEBUG(10,("setting up version3 referral\n"));
1055 reqpathlen = rpcstr_push_talloc(talloc_tos(), &uni_reqpath, pathname);
1056 if (uni_reqpath == NULL || reqpathlen == 0) {
1057 return -1;
1060 if (DEBUGLVL(10)) {
1061 dump_data(0, (unsigned char *)uni_reqpath,
1062 reqpathlen);
1065 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
1066 VERSION3_REFERRAL_SIZE * junction->referral_count;
1067 uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen;
1068 reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen;
1070 for(i=0;i<junction->referral_count;i++) {
1071 DEBUG(10,("referral %u : %s\n",
1073 junction->referral_list[i].alternate_path));
1074 reply_size +=
1075 (strlen(junction->referral_list[i].alternate_path)+1)*2;
1078 pdata = (char *)SMB_REALLOC(pdata,reply_size);
1079 if(pdata == NULL) {
1080 DEBUG(0,("version3 referral setup:"
1081 "malloc failed for Realloc!\n"));
1082 return -1;
1084 *ppdata = pdata;
1086 /* create the header */
1087 SSVAL(pdata,0,consumedcnt * 2); /* path consumed */
1088 SSVAL(pdata,2,junction->referral_count); /* number of referral */
1089 if(self_referral) {
1090 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
1091 } else {
1092 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
1095 /* copy in the reqpaths */
1096 memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen);
1097 memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen);
1099 offset = 8;
1100 for(i=0;i<junction->referral_count;i++) {
1101 struct referral* ref = &(junction->referral_list[i]);
1102 int unilen;
1104 SSVAL(pdata,offset,3); /* version 3 */
1105 SSVAL(pdata,offset+2,VERSION3_REFERRAL_SIZE);
1106 if(self_referral) {
1107 SSVAL(pdata,offset+4,1);
1108 } else {
1109 SSVAL(pdata,offset+4,0);
1112 /* ref_flags :use path_consumed bytes? */
1113 SSVAL(pdata,offset+6,0);
1114 SIVAL(pdata,offset+8,ref->ttl);
1116 SSVAL(pdata,offset+12,uni_reqpathoffset1-offset);
1117 SSVAL(pdata,offset+14,uni_reqpathoffset2-offset);
1118 /* copy referred path into current offset */
1119 unilen = rpcstr_push(pdata+uni_curroffset,ref->alternate_path,
1120 reply_size - uni_curroffset,
1121 STR_UNICODE | STR_TERMINATE);
1122 SSVAL(pdata,offset+16,uni_curroffset-offset);
1123 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
1124 memset(pdata+offset+18,'\0',16);
1126 uni_curroffset += unilen;
1127 offset += VERSION3_REFERRAL_SIZE;
1129 return reply_size;
1132 /******************************************************************
1133 Set up the DFS referral for the dfs pathname. This call returns
1134 the amount of the path covered by this server, and where the
1135 client should be redirected to. This is the meat of the
1136 TRANS2_GET_DFS_REFERRAL call.
1137 ******************************************************************/
1139 int setup_dfs_referral(connection_struct *orig_conn,
1140 const char *dfs_path,
1141 int max_referral_level,
1142 char **ppdata, NTSTATUS *pstatus)
1144 struct junction_map *junction = NULL;
1145 int consumedcnt = 0;
1146 bool self_referral = False;
1147 int reply_size = 0;
1148 char *pathnamep = NULL;
1149 char *local_dfs_path = NULL;
1150 TALLOC_CTX *ctx;
1152 if (!(ctx=talloc_init("setup_dfs_referral"))) {
1153 *pstatus = NT_STATUS_NO_MEMORY;
1154 return -1;
1157 /* get the junction entry */
1158 if (!dfs_path) {
1159 talloc_destroy(ctx);
1160 *pstatus = NT_STATUS_NOT_FOUND;
1161 return -1;
1165 * Trim pathname sent by client so it begins with only one backslash.
1166 * Two backslashes confuse some dfs clients
1169 local_dfs_path = talloc_strdup(ctx,dfs_path);
1170 if (!local_dfs_path) {
1171 *pstatus = NT_STATUS_NO_MEMORY;
1172 talloc_destroy(ctx);
1173 return -1;
1175 pathnamep = local_dfs_path;
1176 while (IS_DIRECTORY_SEP(pathnamep[0]) &&
1177 IS_DIRECTORY_SEP(pathnamep[1])) {
1178 pathnamep++;
1181 junction = TALLOC_ZERO_P(ctx, struct junction_map);
1182 if (!junction) {
1183 *pstatus = NT_STATUS_NO_MEMORY;
1184 talloc_destroy(ctx);
1185 return -1;
1188 /* The following call can change cwd. */
1189 *pstatus = get_referred_path(ctx, pathnamep, junction,
1190 &consumedcnt, &self_referral);
1191 if (!NT_STATUS_IS_OK(*pstatus)) {
1192 vfs_ChDir(orig_conn,orig_conn->connectpath);
1193 talloc_destroy(ctx);
1194 return -1;
1196 vfs_ChDir(orig_conn,orig_conn->connectpath);
1198 if (!self_referral) {
1199 pathnamep[consumedcnt] = '\0';
1201 if( DEBUGLVL( 3 ) ) {
1202 int i=0;
1203 dbgtext("setup_dfs_referral: Path %s to "
1204 "alternate path(s):",
1205 pathnamep);
1206 for(i=0;i<junction->referral_count;i++)
1207 dbgtext(" %s",
1208 junction->referral_list[i].alternate_path);
1209 dbgtext(".\n");
1213 /* create the referral depeding on version */
1214 DEBUG(10,("max_referral_level :%d\n",max_referral_level));
1216 if (max_referral_level < 2) {
1217 max_referral_level = 2;
1219 if (max_referral_level > 3) {
1220 max_referral_level = 3;
1223 switch(max_referral_level) {
1224 case 2:
1225 reply_size = setup_ver2_dfs_referral(pathnamep,
1226 ppdata, junction,
1227 consumedcnt, self_referral);
1228 break;
1229 case 3:
1230 reply_size = setup_ver3_dfs_referral(pathnamep, ppdata,
1231 junction, consumedcnt, self_referral);
1232 break;
1233 default:
1234 DEBUG(0,("setup_dfs_referral: Invalid dfs referral "
1235 "version: %d\n",
1236 max_referral_level));
1237 talloc_destroy(ctx);
1238 *pstatus = NT_STATUS_INVALID_LEVEL;
1239 return -1;
1242 if (DEBUGLVL(10)) {
1243 DEBUGADD(0,("DFS Referral pdata:\n"));
1244 dump_data(0,(uint8 *)*ppdata,reply_size);
1247 talloc_destroy(ctx);
1248 *pstatus = NT_STATUS_OK;
1249 return reply_size;
1252 /**********************************************************************
1253 The following functions are called by the NETDFS RPC pipe functions
1254 **********************************************************************/
1256 /*********************************************************************
1257 Creates a junction structure from a DFS pathname
1258 **********************************************************************/
1260 bool create_junction(TALLOC_CTX *ctx,
1261 const char *dfs_path,
1262 struct junction_map *jucn)
1264 int snum;
1265 bool dummy;
1266 struct dfs_path *pdp = TALLOC_P(ctx,struct dfs_path);
1267 NTSTATUS status;
1269 if (!pdp) {
1270 return False;
1272 status = parse_dfs_path(NULL, dfs_path, False, pdp, &dummy);
1273 if (!NT_STATUS_IS_OK(status)) {
1274 return False;
1277 /* check if path is dfs : validate first token */
1278 if (!is_myname_or_ipaddr(pdp->hostname)) {
1279 DEBUG(4,("create_junction: Invalid hostname %s "
1280 "in dfs path %s\n",
1281 pdp->hostname, dfs_path));
1282 TALLOC_FREE(pdp);
1283 return False;
1286 /* Check for a non-DFS share */
1287 snum = lp_servicenumber(pdp->servicename);
1289 if(snum < 0 || !lp_msdfs_root(snum)) {
1290 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1291 pdp->servicename));
1292 TALLOC_FREE(pdp);
1293 return False;
1296 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1297 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1298 jucn->comment = talloc_strdup(ctx, lp_comment(snum));
1300 TALLOC_FREE(pdp);
1301 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1302 return False;
1304 return True;
1307 /**********************************************************************
1308 Forms a valid Unix pathname from the junction
1309 **********************************************************************/
1311 static bool junction_to_local_path(const struct junction_map *jucn,
1312 char **pp_path_out,
1313 connection_struct **conn_out,
1314 char **oldpath)
1316 int snum;
1317 NTSTATUS status;
1319 snum = lp_servicenumber(jucn->service_name);
1320 if(snum < 0) {
1321 return False;
1323 status = create_conn_struct(talloc_tos(), conn_out, snum,
1324 lp_pathname(snum), oldpath);
1325 if (!NT_STATUS_IS_OK(status)) {
1326 return False;
1329 *pp_path_out = talloc_asprintf(*conn_out,
1330 "%s/%s",
1331 lp_pathname(snum),
1332 jucn->volume_name);
1333 if (!*pp_path_out) {
1334 vfs_ChDir(*conn_out, *oldpath);
1335 conn_free_internal(*conn_out);
1336 return False;
1338 return True;
1341 bool create_msdfs_link(const struct junction_map *jucn)
1343 char *path = NULL;
1344 char *cwd;
1345 char *msdfs_link = NULL;
1346 connection_struct *conn;
1347 int i=0;
1348 bool insert_comma = False;
1349 bool ret = False;
1351 if(!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1352 return False;
1355 /* Form the msdfs_link contents */
1356 msdfs_link = talloc_strdup(conn, "msdfs:");
1357 if (!msdfs_link) {
1358 goto out;
1360 for(i=0; i<jucn->referral_count; i++) {
1361 char *refpath = jucn->referral_list[i].alternate_path;
1363 /* Alternate paths always use Windows separators. */
1364 trim_char(refpath, '\\', '\\');
1365 if(*refpath == '\0') {
1366 if (i == 0) {
1367 insert_comma = False;
1369 continue;
1371 if (i > 0 && insert_comma) {
1372 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1373 ",%s",
1374 refpath);
1375 } else {
1376 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1377 "%s",
1378 refpath);
1381 if (!msdfs_link) {
1382 goto out;
1384 if (!insert_comma) {
1385 insert_comma = True;
1389 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1390 path, msdfs_link));
1392 if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1393 if (errno == EEXIST) {
1394 if(SMB_VFS_UNLINK(conn,path)!=0) {
1395 goto out;
1398 if (SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1399 DEBUG(1,("create_msdfs_link: symlink failed "
1400 "%s -> %s\nError: %s\n",
1401 path, msdfs_link, strerror(errno)));
1402 goto out;
1406 ret = True;
1408 out:
1409 vfs_ChDir(conn, cwd);
1410 conn_free_internal(conn);
1411 return ret;
1414 bool remove_msdfs_link(const struct junction_map *jucn)
1416 char *path = NULL;
1417 char *cwd;
1418 connection_struct *conn;
1419 bool ret = False;
1421 if (!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1422 return false;
1425 if( SMB_VFS_UNLINK(conn, path) == 0 ) {
1426 ret = True;
1429 vfs_ChDir(conn, cwd);
1430 conn_free_internal(conn);
1431 return ret;
1434 /*********************************************************************
1435 Return the number of DFS links at the root of this share.
1436 *********************************************************************/
1438 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1440 size_t cnt = 0;
1441 SMB_STRUCT_DIR *dirp = NULL;
1442 char *dname = NULL;
1443 const char *connect_path = lp_pathname(snum);
1444 const char *msdfs_proxy = lp_msdfs_proxy(snum);
1445 connection_struct *conn;
1446 NTSTATUS status;
1447 char *cwd;
1449 if(*connect_path == '\0') {
1450 return 0;
1454 * Fake up a connection struct for the VFS layer.
1457 status = create_conn_struct(talloc_tos(), &conn, snum, connect_path,
1458 &cwd);
1459 if (!NT_STATUS_IS_OK(status)) {
1460 DEBUG(3, ("create_conn_struct failed: %s\n",
1461 nt_errstr(status)));
1462 return 0;
1465 /* Count a link for the msdfs root - convention */
1466 cnt = 1;
1468 /* No more links if this is an msdfs proxy. */
1469 if (*msdfs_proxy != '\0') {
1470 goto out;
1473 /* Now enumerate all dfs links */
1474 dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1475 if(!dirp) {
1476 goto out;
1479 while ((dname = vfs_readdirname(conn, dirp)) != NULL) {
1480 if (is_msdfs_link(conn,
1481 dname,
1482 NULL)) {
1483 cnt++;
1487 SMB_VFS_CLOSEDIR(conn,dirp);
1489 out:
1490 vfs_ChDir(conn, cwd);
1491 conn_free_internal(conn);
1492 return cnt;
1495 /*********************************************************************
1496 *********************************************************************/
1498 static int form_junctions(TALLOC_CTX *ctx,
1499 int snum,
1500 struct junction_map *jucn,
1501 size_t jn_remain)
1503 size_t cnt = 0;
1504 SMB_STRUCT_DIR *dirp = NULL;
1505 char *dname = NULL;
1506 const char *connect_path = lp_pathname(snum);
1507 char *service_name = lp_servicename(snum);
1508 const char *msdfs_proxy = lp_msdfs_proxy(snum);
1509 connection_struct *conn;
1510 struct referral *ref = NULL;
1511 char *cwd;
1512 NTSTATUS status;
1514 if (jn_remain == 0) {
1515 return 0;
1518 if(*connect_path == '\0') {
1519 return 0;
1523 * Fake up a connection struct for the VFS layer.
1526 status = create_conn_struct(ctx, &conn, snum, connect_path, &cwd);
1527 if (!NT_STATUS_IS_OK(status)) {
1528 DEBUG(3, ("create_conn_struct failed: %s\n",
1529 nt_errstr(status)));
1530 return 0;
1533 /* form a junction for the msdfs root - convention
1534 DO NOT REMOVE THIS: NT clients will not work with us
1535 if this is not present
1537 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1538 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1539 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1540 goto out;
1542 jucn[cnt].comment = "";
1543 jucn[cnt].referral_count = 1;
1545 ref = jucn[cnt].referral_list = TALLOC_ZERO_P(ctx, struct referral);
1546 if (jucn[cnt].referral_list == NULL) {
1547 goto out;
1550 ref->proximity = 0;
1551 ref->ttl = REFERRAL_TTL;
1552 if (*msdfs_proxy != '\0') {
1553 ref->alternate_path = talloc_strdup(ctx,
1554 msdfs_proxy);
1555 } else {
1556 ref->alternate_path = talloc_asprintf(ctx,
1557 "\\\\%s\\%s",
1558 get_local_machine_name(),
1559 service_name);
1562 if (!ref->alternate_path) {
1563 goto out;
1565 cnt++;
1567 /* Don't enumerate if we're an msdfs proxy. */
1568 if (*msdfs_proxy != '\0') {
1569 goto out;
1572 /* Now enumerate all dfs links */
1573 dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1574 if(!dirp) {
1575 goto out;
1578 while ((dname = vfs_readdirname(conn, dirp)) != NULL) {
1579 char *link_target = NULL;
1580 if (cnt >= jn_remain) {
1581 DEBUG(2, ("form_junctions: ran out of MSDFS "
1582 "junction slots"));
1583 goto out;
1585 if (is_msdfs_link_internal(ctx,
1586 conn,
1587 dname, &link_target,
1588 NULL)) {
1589 if (parse_msdfs_symlink(ctx,
1590 link_target,
1591 &jucn[cnt].referral_list,
1592 &jucn[cnt].referral_count)) {
1594 jucn[cnt].service_name = talloc_strdup(ctx,
1595 service_name);
1596 jucn[cnt].volume_name = talloc_strdup(ctx,
1597 dname);
1598 if (!jucn[cnt].service_name ||
1599 !jucn[cnt].volume_name) {
1600 goto out;
1602 jucn[cnt].comment = "";
1603 cnt++;
1605 TALLOC_FREE(link_target);
1609 out:
1611 if (dirp) {
1612 SMB_VFS_CLOSEDIR(conn,dirp);
1615 vfs_ChDir(conn, cwd);
1616 conn_free_internal(conn);
1617 return cnt;
1620 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1622 struct junction_map *jn = NULL;
1623 int i=0;
1624 size_t jn_count = 0;
1625 int sharecount = 0;
1627 *p_num_jn = 0;
1628 if(!lp_host_msdfs()) {
1629 return NULL;
1632 /* Ensure all the usershares are loaded. */
1633 become_root();
1634 load_registry_shares();
1635 sharecount = load_usershare_shares();
1636 unbecome_root();
1638 for(i=0;i < sharecount;i++) {
1639 if(lp_msdfs_root(i)) {
1640 jn_count += count_dfs_links(ctx, i);
1643 if (jn_count == 0) {
1644 return NULL;
1646 jn = TALLOC_ARRAY(ctx, struct junction_map, jn_count);
1647 if (!jn) {
1648 return NULL;
1650 for(i=0; i < sharecount; i++) {
1651 if (*p_num_jn >= jn_count) {
1652 break;
1654 if(lp_msdfs_root(i)) {
1655 *p_num_jn += form_junctions(ctx, i,
1656 &jn[*p_num_jn],
1657 jn_count - *p_num_jn);
1660 return jn;
1663 /******************************************************************************
1664 Core function to resolve a dfs pathname.
1665 ******************************************************************************/
1667 NTSTATUS resolve_dfspath(TALLOC_CTX *ctx,
1668 connection_struct *conn,
1669 bool dfs_pathnames,
1670 const char *name_in,
1671 char **pp_name_out)
1673 NTSTATUS status = NT_STATUS_OK;
1674 bool dummy;
1675 if (dfs_pathnames) {
1676 status = dfs_redirect(ctx,
1677 conn,
1678 name_in,
1679 False,
1680 pp_name_out,
1681 &dummy);
1682 } else {
1684 * Cheat and just return a copy of the in ptr.
1685 * Once srvstr_get_path() uses talloc it'll
1686 * be a talloced ptr anyway.
1688 *pp_name_out = CONST_DISCARD(char *,name_in);
1690 return status;
1693 /******************************************************************************
1694 Core function to resolve a dfs pathname possibly containing a wildcard.
1695 This function is identical to the above except for the bool param to
1696 dfs_redirect but I need this to be separate so it's really clear when
1697 we're allowing wildcards and when we're not. JRA.
1698 ******************************************************************************/
1700 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1701 connection_struct *conn,
1702 bool dfs_pathnames,
1703 const char *name_in,
1704 char **pp_name_out,
1705 bool *ppath_contains_wcard)
1707 NTSTATUS status = NT_STATUS_OK;
1708 if (dfs_pathnames) {
1709 status = dfs_redirect(ctx,
1710 conn,
1711 name_in,
1712 True,
1713 pp_name_out,
1714 ppath_contains_wcard);
1715 } else {
1717 * Cheat and just return a copy of the in ptr.
1718 * Once srvstr_get_path() uses talloc it'll
1719 * be a talloced ptr anyway.
1721 *pp_name_out = CONST_DISCARD(char *,name_in);
1723 return status;