r25111: Move to talloced pathnames on most code paths.
[Samba.git] / source / smbd / msdfs.c
blob5cbe8c68aca41ee2cd51d58bcb008182a3d8951a
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 This version does everything using pointers within one copy of the
40 pathname string, talloced on the struct dfs_path pointer (which
41 must be talloced). This may be too clever to live....
42 JRA.
43 **********************************************************************/
45 static NTSTATUS parse_dfs_path(const char *pathname,
46 BOOL allow_wcards,
47 struct dfs_path *pdp, /* MUST BE TALLOCED */
48 BOOL *ppath_contains_wcard)
50 char *pathname_local;
51 char *p,*temp;
52 char *eos_ptr;
53 NTSTATUS status = NT_STATUS_OK;
54 char sepchar;
56 ZERO_STRUCTP(pdp);
59 * This is the only talloc we should need to do
60 * on the struct dfs_path. All the pointers inside
61 * it should point to offsets within this string.
64 pathname_local = talloc_strdup(pdp, pathname);
65 if (!pathname_local) {
66 return NT_STATUS_NO_MEMORY;
68 /* Get a pointer to the terminating '\0' */
69 eos_ptr = &pathname_local[strlen(pathname_local)];
70 p = temp = pathname_local;
72 pdp->posix_path = (lp_posix_pathnames() && *pathname == '/');
74 sepchar = pdp->posix_path ? '/' : '\\';
76 if (*pathname != sepchar) {
77 DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
78 pathname, sepchar ));
80 * Possibly client sent a local path by mistake.
81 * Try and convert to a local path.
84 pdp->hostname = eos_ptr; /* "" */
85 pdp->servicename = eos_ptr; /* "" */
87 /* We've got no info about separators. */
88 pdp->posix_path = lp_posix_pathnames();
89 p = temp;
90 DEBUG(10,("parse_dfs_path: trying to convert %s to a "
91 "local path\n",
92 temp));
93 goto local_path;
97 * Safe to use on talloc'ed string as it only shrinks.
98 * It also doesn't affect the eos_ptr.
100 trim_char(temp,sepchar,sepchar);
102 DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
103 temp, sepchar));
105 /* Now tokenize. */
106 /* Parse out hostname. */
107 p = strchr_m(temp,sepchar);
108 if(p == NULL) {
109 DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
110 temp));
112 * Possibly client sent a local path by mistake.
113 * Try and convert to a local path.
116 pdp->hostname = eos_ptr; /* "" */
117 pdp->servicename = eos_ptr; /* "" */
119 p = temp;
120 DEBUG(10,("parse_dfs_path: trying to convert %s "
121 "to a local path\n",
122 temp));
123 goto local_path;
125 *p = '\0';
126 pdp->hostname = temp;
128 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
130 /* If we got a hostname, is it ours (or an IP address) ? */
131 if (!is_myname_or_ipaddr(pdp->hostname)) {
132 /* Repair path. */
133 *p = sepchar;
134 DEBUG(10,("parse_dfs_path: hostname %s isn't ours. "
135 "Try local path from path %s\n",
136 pdp->hostname, temp));
138 * Possibly client sent a local path by mistake.
139 * Try and convert to a local path.
142 pdp->hostname = eos_ptr; /* "" */
143 pdp->servicename = eos_ptr; /* "" */
145 p = temp;
146 DEBUG(10,("parse_dfs_path: trying to convert %s "
147 "to a local path\n",
148 temp));
149 goto local_path;
152 /* Parse out servicename. */
153 temp = p+1;
154 p = strchr_m(temp,sepchar);
155 if(p == NULL) {
156 pdp->servicename = temp;
157 pdp->reqpath = eos_ptr; /* "" */
158 return NT_STATUS_OK;
160 *p = '\0';
161 pdp->servicename = temp;
162 DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
164 p++;
166 local_path:
168 *ppath_contains_wcard = False;
170 pdp->reqpath = p;
172 /* Rest is reqpath. */
173 if (pdp->posix_path) {
174 status = check_path_syntax_posix(pdp->reqpath);
175 } else {
176 if (allow_wcards) {
177 status = check_path_syntax_wcard(pdp->reqpath,
178 ppath_contains_wcard);
179 } else {
180 status = check_path_syntax(pdp->reqpath);
184 if (!NT_STATUS_IS_OK(status)) {
185 DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
186 p, nt_errstr(status) ));
187 return status;
190 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
191 return NT_STATUS_OK;
194 /********************************************************
195 Fake up a connection struct for the VFS layer.
196 Note this CHANGES CWD !!!! JRA.
197 *********************************************************/
199 static NTSTATUS create_conn_struct(connection_struct *conn,
200 int snum,
201 const char *path)
203 pstring connpath;
205 ZERO_STRUCTP(conn);
207 pstrcpy(connpath, path);
208 pstring_sub(connpath , "%S", lp_servicename(snum));
210 /* needed for smbd_vfs_init() */
212 if ((conn->mem_ctx=talloc_init("connection_struct")) == NULL) {
213 DEBUG(0,("talloc_init(connection_struct) failed!\n"));
214 return NT_STATUS_NO_MEMORY;
217 if (!(conn->params = TALLOC_ZERO_P(conn->mem_ctx,
218 struct share_params))) {
219 DEBUG(0, ("TALLOC failed\n"));
220 return NT_STATUS_NO_MEMORY;
223 conn->params->service = snum;
225 set_conn_connectpath(conn, connpath);
227 if (!smbd_vfs_init(conn)) {
228 NTSTATUS status = map_nt_error_from_unix(errno);
229 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
230 conn_free_internal(conn);
231 return status;
235 * Windows seems to insist on doing trans2getdfsreferral() calls on
236 * the IPC$ share as the anonymous user. If we try to chdir as that
237 * user we will fail.... WTF ? JRA.
240 if (vfs_ChDir(conn,conn->connectpath) != 0) {
241 NTSTATUS status = map_nt_error_from_unix(errno);
242 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
243 "Error was %s\n",
244 conn->connectpath, strerror(errno) ));
245 conn_free_internal(conn);
246 return status;
249 return NT_STATUS_OK;
252 /**********************************************************************
253 Parse the contents of a symlink to verify if it is an msdfs referral
254 A valid referral is of the form:
256 msdfs:server1\share1,server2\share2
257 msdfs:server1\share1\pathname,server2\share2\pathname
258 msdfs:server1/share1,server2/share2
259 msdfs:server1/share1/pathname,server2/share2/pathname.
261 Note that the alternate paths returned here must be of the canonicalized
262 form:
264 \server\share or
265 \server\share\path\to\file,
267 even in posix path mode. This is because we have no knowledge if the
268 server we're referring to understands posix paths.
269 **********************************************************************/
271 static BOOL parse_msdfs_symlink(TALLOC_CTX *ctx,
272 const char *target,
273 struct referral **preflist,
274 int *refcount)
276 char *temp = NULL;
277 char *prot;
278 char **alt_path = NULL;
279 int count = 0, i;
280 struct referral *reflist;
282 temp = talloc_strdup(ctx, target);
283 if (!temp) {
284 return False;
286 prot = strtok(temp,":");
287 if (!prot) {
288 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
289 return False;
292 alt_path = TALLOC_ARRAY(ctx, char *, MAX_REFERRAL_COUNT);
293 if (!alt_path) {
294 return False;
297 /* parse out the alternate paths */
298 while((count<MAX_REFERRAL_COUNT) &&
299 ((alt_path[count] = strtok(NULL,",")) != NULL)) {
300 count++;
303 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
305 if (count) {
306 reflist = *preflist = TALLOC_ZERO_ARRAY(ctx,
307 struct referral, count);
308 if(reflist == NULL) {
309 TALLOC_FREE(alt_path);
310 return False;
312 } else {
313 reflist = *preflist = NULL;
316 for(i=0;i<count;i++) {
317 char *p;
319 /* Canonicalize link target.
320 * Replace all /'s in the path by a \ */
321 string_replace(alt_path[i], '/', '\\');
323 /* Remove leading '\\'s */
324 p = alt_path[i];
325 while (*p && (*p == '\\')) {
326 p++;
329 reflist[i].alternate_path = talloc_asprintf(ctx,
330 "\\%s",
332 if (!reflist[i].alternate_path) {
333 return False;
336 reflist[i].proximity = 0;
337 reflist[i].ttl = REFERRAL_TTL;
338 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
339 reflist[i].alternate_path));
340 *refcount += 1;
343 TALLOC_FREE(alt_path);
344 return True;
347 /**********************************************************************
348 Returns true if the unix path is a valid msdfs symlink and also
349 returns the target string from inside the link.
350 **********************************************************************/
352 static BOOL is_msdfs_link_internal(TALLOC_CTX *ctx,
353 connection_struct *conn,
354 const char *path,
355 char **pp_link_target,
356 SMB_STRUCT_STAT *sbufp)
358 SMB_STRUCT_STAT st;
359 int referral_len = 0;
360 char link_target_buf[7];
361 size_t bufsize = 0;
362 char *link_target = NULL;
364 if (pp_link_target) {
365 bufsize = 1024;
366 link_target = TALLOC_ARRAY(ctx, char, bufsize);
367 if (!link_target) {
368 return False;
370 *pp_link_target = link_target;
371 } else {
372 bufsize = sizeof(link_target_buf);
373 link_target = link_target_buf;
376 if (sbufp == NULL) {
377 sbufp = &st;
380 if (SMB_VFS_LSTAT(conn, path, sbufp) != 0) {
381 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
382 path));
383 goto err;
386 if (!S_ISLNK(sbufp->st_mode)) {
387 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
388 path));
389 goto err;
392 referral_len = SMB_VFS_READLINK(conn, path, link_target, bufsize - 1);
393 if (referral_len == -1) {
394 DEBUG(0,("is_msdfs_link_read_target: Error reading "
395 "msdfs link %s: %s\n",
396 path, strerror(errno)));
397 goto err;
399 link_target[referral_len] = '\0';
401 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path,
402 link_target));
404 if (!strnequal(link_target, "msdfs:", 6)) {
405 goto err;
407 return True;
409 err:
411 if (link_target != link_target_buf) {
412 TALLOC_FREE(link_target);
414 return False;
417 /**********************************************************************
418 Returns true if the unix path is a valid msdfs symlink.
419 **********************************************************************/
421 BOOL is_msdfs_link(connection_struct *conn,
422 const char *path,
423 SMB_STRUCT_STAT *sbufp)
425 return is_msdfs_link_internal(talloc_tos(),
426 conn,
427 path,
428 NULL,
429 sbufp);
432 /*****************************************************************
433 Used by other functions to decide if a dfs path is remote,
434 and to get the list of referred locations for that remote path.
436 search_flag: For findfirsts, dfs links themselves are not
437 redirected, but paths beyond the links are. For normal smb calls,
438 even dfs links need to be redirected.
440 consumedcntp: how much of the dfs path is being redirected. the client
441 should try the remaining path on the redirected server.
443 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
444 link redirect are in targetpath.
445 *****************************************************************/
447 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
448 connection_struct *conn,
449 const char *dfspath, /* Incoming complete dfs path */
450 const struct dfs_path *pdp, /* Parsed out
451 server+share+extrapath. */
452 BOOL search_flag, /* Called from a findfirst ? */
453 int *consumedcntp,
454 char **pp_targetpath)
456 char *p = NULL;
457 char *q = NULL;
458 SMB_STRUCT_STAT sbuf;
459 NTSTATUS status;
460 char *localpath = NULL;
461 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
462 components). */
464 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
465 conn->connectpath, pdp->reqpath));
468 * Note the unix path conversion here we're doing we can
469 * throw away. We're looking for a symlink for a dfs
470 * resolution, if we don't find it we'll do another
471 * unix_convert later in the codepath.
472 * If we needed to remember what we'd resolved in
473 * dp->reqpath (as the original code did) we'd
474 * pstrcpy(localhost, dp->reqpath) on any code
475 * path below that returns True - but I don't
476 * think this is needed. JRA.
479 status = unix_convert(conn, pdp->reqpath, search_flag, &localpath,
480 NULL, &sbuf);
481 if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status,
482 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
483 return status;
486 /* Optimization - check if we can redirect the whole path. */
488 if (is_msdfs_link_internal(ctx, conn, localpath, pp_targetpath, NULL)) {
489 if (search_flag) {
490 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
491 "for dfs link %s.\n", dfspath));
492 return NT_STATUS_OK;
495 DEBUG(6,("dfs_path_lookup: %s resolves to a "
496 "valid dfs link %s.\n", dfspath,
497 pp_targetpath ? *pp_targetpath : ""));
499 if (consumedcntp) {
500 *consumedcntp = strlen(dfspath);
502 return NT_STATUS_PATH_NOT_COVERED;
505 /* Prepare to test only for '/' components in the given path,
506 * so if a Windows path replace all '\\' characters with '/'.
507 * For a POSIX DFS path we know all separators are already '/'. */
509 canon_dfspath = talloc_strdup(ctx, dfspath);
510 if (!canon_dfspath) {
511 return NT_STATUS_NO_MEMORY;
513 if (!pdp->posix_path) {
514 string_replace(canon_dfspath, '\\', '/');
518 * localpath comes out of unix_convert, so it has
519 * no trailing backslash. Make sure that canon_dfspath hasn't either.
520 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
523 trim_char(canon_dfspath,0,'/');
526 * Redirect if any component in the path is a link.
527 * We do this by walking backwards through the
528 * local path, chopping off the last component
529 * in both the local path and the canonicalized
530 * DFS path. If we hit a DFS link then we're done.
533 p = strrchr_m(localpath, '/');
534 if (consumedcntp) {
535 q = strrchr_m(canon_dfspath, '/');
538 while (p) {
539 *p = '\0';
540 if (q) {
541 *q = '\0';
544 if (is_msdfs_link_internal(ctx, conn,
545 localpath, pp_targetpath, NULL)) {
546 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
547 "parent %s is dfs link\n", dfspath, localpath));
549 if (consumedcntp) {
550 *consumedcntp = strlen(canon_dfspath);
551 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
552 "(%d)\n",
553 canon_dfspath,
554 *consumedcntp));
557 return NT_STATUS_PATH_NOT_COVERED;
560 /* Step back on the filesystem. */
561 p = strrchr_m(localpath, '/');
563 if (consumedcntp) {
564 /* And in the canonicalized dfs path. */
565 q = strrchr_m(canon_dfspath, '/');
569 return NT_STATUS_OK;
572 /*****************************************************************
573 Decides if a dfs pathname should be redirected or not.
574 If not, the pathname is converted to a tcon-relative local unix path
576 search_wcard_flag: this flag performs 2 functions both related
577 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
578 for details.
580 This function can return NT_STATUS_OK, meaning use the returned path as-is
581 (mapped into a local path).
582 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
583 any other NT_STATUS error which is a genuine error to be
584 returned to the client.
585 *****************************************************************/
587 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
588 connection_struct *conn,
589 const char *path_in,
590 BOOL search_wcard_flag,
591 char **pp_path_out,
592 BOOL *ppath_contains_wcard)
594 NTSTATUS status;
595 struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
597 if (!pdp) {
598 return NT_STATUS_NO_MEMORY;
601 status = parse_dfs_path(path_in, search_wcard_flag, pdp,
602 ppath_contains_wcard);
603 if (!NT_STATUS_IS_OK(status)) {
604 TALLOC_FREE(pdp);
605 return status;
608 if (pdp->reqpath[0] == '\0') {
609 TALLOC_FREE(pdp);
610 *pp_path_out = talloc_strdup(ctx, "");
611 if (!*pp_path_out) {
612 return NT_STATUS_NO_MEMORY;
614 DEBUG(5,("dfs_redirect: self-referral.\n"));
615 return NT_STATUS_OK;
618 /* If dfs pathname for a non-dfs share, convert to tcon-relative
619 path and return OK */
621 if (!lp_msdfs_root(SNUM(conn))) {
622 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
623 TALLOC_FREE(pdp);
624 if (!*pp_path_out) {
625 return NT_STATUS_NO_MEMORY;
627 return NT_STATUS_OK;
630 /* If it looked like a local path (zero hostname/servicename)
631 * just treat as a tcon-relative path. */
633 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
634 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
635 TALLOC_FREE(pdp);
636 if (!*pp_path_out) {
637 return NT_STATUS_NO_MEMORY;
639 return NT_STATUS_OK;
642 if (!( strequal(pdp->servicename, lp_servicename(SNUM(conn)))
643 || (strequal(pdp->servicename, HOMES_NAME)
644 && strequal(lp_servicename(SNUM(conn)),
645 get_current_username()) )) ) {
647 /* The given sharename doesn't match this connection. */
648 TALLOC_FREE(pdp);
650 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
653 status = dfs_path_lookup(ctx, conn, path_in, pdp,
654 search_wcard_flag, NULL, NULL);
655 if (!NT_STATUS_IS_OK(status)) {
656 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
657 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
658 } else {
659 DEBUG(10,("dfs_redirect: dfs_path_lookup "
660 "failed for %s with %s\n",
661 path_in, nt_errstr(status) ));
663 return status;
666 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
668 /* Form non-dfs tcon-relative path */
669 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
670 TALLOC_FREE(pdp);
671 if (!*pp_path_out) {
672 return NT_STATUS_NO_MEMORY;
675 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
676 path_in,
677 *pp_path_out));
679 return NT_STATUS_OK;
682 /**********************************************************************
683 Return a self referral.
684 **********************************************************************/
686 static NTSTATUS self_ref(TALLOC_CTX *ctx,
687 const char *dfs_path,
688 struct junction_map *jucn,
689 int *consumedcntp,
690 BOOL *self_referralp)
692 struct referral *ref;
694 *self_referralp = True;
696 jucn->referral_count = 1;
697 if((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
698 return NT_STATUS_NO_MEMORY;
701 ref->alternate_path = talloc_strdup(ctx, dfs_path);
702 if (!ref->alternate_path) {
703 return NT_STATUS_NO_MEMORY;
705 ref->proximity = 0;
706 ref->ttl = REFERRAL_TTL;
707 jucn->referral_list = ref;
708 *consumedcntp = strlen(dfs_path);
709 return NT_STATUS_OK;
712 /**********************************************************************
713 Gets valid referrals for a dfs path and fills up the
714 junction_map structure.
715 **********************************************************************/
717 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
718 const char *dfs_path,
719 struct junction_map *jucn,
720 int *consumedcntp,
721 BOOL *self_referralp)
723 struct connection_struct conns;
724 struct connection_struct *conn = &conns;
725 char *targetpath = NULL;
726 int snum;
727 NTSTATUS status = NT_STATUS_NOT_FOUND;
728 BOOL dummy;
729 struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
731 if (!pdp) {
732 return NT_STATUS_NO_MEMORY;
735 ZERO_STRUCT(conns);
736 *self_referralp = False;
738 status = parse_dfs_path(dfs_path, False, pdp, &dummy);
739 if (!NT_STATUS_IS_OK(status)) {
740 return status;
743 /* Verify hostname in path */
744 if (!is_myname_or_ipaddr(pdp->hostname)) {
745 DEBUG(3, ("get_referred_path: Invalid hostname %s in path %s\n",
746 pdp->hostname, dfs_path));
747 TALLOC_FREE(pdp);
748 return NT_STATUS_NOT_FOUND;
751 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
752 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
753 if (!jucn->service_name || !jucn->volume_name) {
754 TALLOC_FREE(pdp);
755 return NT_STATUS_NO_MEMORY;
758 /* Verify the share is a dfs root */
759 snum = lp_servicenumber(jucn->service_name);
760 if(snum < 0) {
761 fstring service_name;
762 fstrcpy(service_name, jucn->service_name);
763 if ((snum = find_service(service_name)) < 0) {
764 return NT_STATUS_NOT_FOUND;
766 TALLOC_FREE(jucn->service_name);
767 jucn->service_name = talloc_strdup(ctx, service_name);
768 if (!jucn->service_name) {
769 TALLOC_FREE(pdp);
770 return NT_STATUS_NO_MEMORY;
774 if (!lp_msdfs_root(snum)) {
775 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
776 "a dfs root.\n",
777 pdp->servicename, dfs_path));
778 TALLOC_FREE(pdp);
779 return NT_STATUS_NOT_FOUND;
783 * Self referrals are tested with a anonymous IPC connection and
784 * a GET_DFS_REFERRAL call to \\server\share. (which means
785 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
786 * into the directory and will fail if it cannot (as the anonymous
787 * user). Cope with this.
790 if (pdp->reqpath[0] == '\0') {
791 struct referral *ref;
793 if (*lp_msdfs_proxy(snum) == '\0') {
794 TALLOC_FREE(pdp);
795 return self_ref(ctx,
796 dfs_path,
797 jucn,
798 consumedcntp,
799 self_referralp);
803 * It's an msdfs proxy share. Redirect to
804 * the configured target share.
807 jucn->referral_count = 1;
808 if ((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
809 TALLOC_FREE(pdp);
810 return NT_STATUS_NO_MEMORY;
813 ref->alternate_path = talloc_strdup(ctx, lp_msdfs_proxy(snum));
814 if (!ref->alternate_path) {
815 TALLOC_FREE(pdp);
816 return NT_STATUS_NO_MEMORY;
819 if (pdp->reqpath[0] != '\0') {
820 ref->alternate_path = talloc_asprintf_append(
821 ref->alternate_path,
822 "%s",
823 pdp->reqpath);
824 if (!ref->alternate_path) {
825 TALLOC_FREE(pdp);
826 return NT_STATUS_NO_MEMORY;
829 ref->proximity = 0;
830 ref->ttl = REFERRAL_TTL;
831 jucn->referral_list = ref;
832 *consumedcntp = strlen(dfs_path);
833 TALLOC_FREE(pdp);
834 return NT_STATUS_OK;
837 status = create_conn_struct(conn, snum, lp_pathname(snum));
838 if (!NT_STATUS_IS_OK(status)) {
839 TALLOC_FREE(pdp);
840 return status;
843 /* If this is a DFS path dfs_lookup should return
844 * NT_STATUS_PATH_NOT_COVERED. */
846 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
847 False, consumedcntp, &targetpath);
849 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
850 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
851 dfs_path));
852 conn_free_internal(conn);
853 TALLOC_FREE(pdp);
854 return status;
857 /* We know this is a valid dfs link. Parse the targetpath. */
858 if (!parse_msdfs_symlink(ctx, targetpath,
859 &jucn->referral_list,
860 &jucn->referral_count)) {
861 DEBUG(3,("get_referred_path: failed to parse symlink "
862 "target %s\n", targetpath ));
863 conn_free_internal(conn);
864 TALLOC_FREE(pdp);
865 return NT_STATUS_NOT_FOUND;
868 conn_free_internal(conn);
869 TALLOC_FREE(pdp);
870 return NT_STATUS_OK;
873 static int setup_ver2_dfs_referral(const char *pathname,
874 char **ppdata,
875 struct junction_map *junction,
876 int consumedcnt,
877 BOOL self_referral)
879 char* pdata = *ppdata;
881 unsigned char uni_requestedpath[sizeof(pstring)];
882 int uni_reqpathoffset1,uni_reqpathoffset2;
883 int uni_curroffset;
884 int requestedpathlen=0;
885 int offset;
886 int reply_size = 0;
887 int i=0;
889 DEBUG(10,("Setting up version2 referral\nRequested path:\n"));
891 requestedpathlen = rpcstr_push(uni_requestedpath,
892 pathname, sizeof(pstring),
893 STR_TERMINATE);
895 if (DEBUGLVL(10)) {
896 dump_data(0, uni_requestedpath,requestedpathlen);
899 DEBUG(10,("ref count = %u\n",junction->referral_count));
901 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
902 VERSION2_REFERRAL_SIZE * junction->referral_count;
904 uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen;
906 uni_curroffset = uni_reqpathoffset2 + requestedpathlen;
908 reply_size = REFERRAL_HEADER_SIZE +
909 VERSION2_REFERRAL_SIZE*junction->referral_count +
910 2 * requestedpathlen;
911 DEBUG(10,("reply_size: %u\n",reply_size));
913 /* add up the unicode lengths of all the referral paths */
914 for(i=0;i<junction->referral_count;i++) {
915 DEBUG(10,("referral %u : %s\n",
917 junction->referral_list[i].alternate_path));
918 reply_size +=
919 (strlen(junction->referral_list[i].alternate_path)+1)*2;
922 DEBUG(10,("reply_size = %u\n",reply_size));
923 /* add the unexplained 0x16 bytes */
924 reply_size += 0x16;
926 pdata = (char *)SMB_REALLOC(pdata,reply_size);
927 if(pdata == NULL) {
928 DEBUG(0,("Realloc failed!\n"));
929 return -1;
931 *ppdata = pdata;
933 /* copy in the dfs requested paths.. required for offset calculations */
934 memcpy(pdata+uni_reqpathoffset1,uni_requestedpath,requestedpathlen);
935 memcpy(pdata+uni_reqpathoffset2,uni_requestedpath,requestedpathlen);
937 /* create the header */
938 SSVAL(pdata,0,consumedcnt * 2); /* path consumed */
939 /* number of referral in this pkt */
940 SSVAL(pdata,2,junction->referral_count);
941 if(self_referral) {
942 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
943 } else {
944 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
947 offset = 8;
948 /* add the referral elements */
949 for(i=0;i<junction->referral_count;i++) {
950 struct referral* ref = &junction->referral_list[i];
951 int unilen;
953 SSVAL(pdata,offset,2); /* version 2 */
954 SSVAL(pdata,offset+2,VERSION2_REFERRAL_SIZE);
955 if(self_referral) {
956 SSVAL(pdata,offset+4,1);
957 } else {
958 SSVAL(pdata,offset+4,0);
961 /* ref_flags :use path_consumed bytes? */
962 SSVAL(pdata,offset+6,0);
963 SIVAL(pdata,offset+8,ref->proximity);
964 SIVAL(pdata,offset+12,ref->ttl);
966 SSVAL(pdata,offset+16,uni_reqpathoffset1-offset);
967 SSVAL(pdata,offset+18,uni_reqpathoffset2-offset);
968 /* copy referred path into current offset */
969 unilen = rpcstr_push(pdata+uni_curroffset, ref->alternate_path,
970 sizeof(pstring), STR_UNICODE);
972 SSVAL(pdata,offset+20,uni_curroffset-offset);
974 uni_curroffset += unilen;
975 offset += VERSION2_REFERRAL_SIZE;
977 /* add in the unexplained 22 (0x16) bytes at the end */
978 memset(pdata+uni_curroffset,'\0',0x16);
979 return reply_size;
982 static int setup_ver3_dfs_referral(const char *pathname,
983 char **ppdata,
984 struct junction_map *junction,
985 int consumedcnt,
986 BOOL self_referral)
988 char *pdata = *ppdata;
990 unsigned char uni_reqpath[sizeof(pstring)];
991 int uni_reqpathoffset1, uni_reqpathoffset2;
992 int uni_curroffset;
993 int reply_size = 0;
995 int reqpathlen = 0;
996 int offset,i=0;
998 DEBUG(10,("setting up version3 referral\n"));
1000 reqpathlen = rpcstr_push(uni_reqpath, pathname,
1001 sizeof(pstring), STR_TERMINATE);
1003 if (DEBUGLVL(10)) {
1004 dump_data(0, uni_reqpath,reqpathlen);
1007 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
1008 VERSION3_REFERRAL_SIZE * junction->referral_count;
1009 uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen;
1010 reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen;
1012 for(i=0;i<junction->referral_count;i++) {
1013 DEBUG(10,("referral %u : %s\n",
1015 junction->referral_list[i].alternate_path));
1016 reply_size +=
1017 (strlen(junction->referral_list[i].alternate_path)+1)*2;
1020 pdata = (char *)SMB_REALLOC(pdata,reply_size);
1021 if(pdata == NULL) {
1022 DEBUG(0,("version3 referral setup:"
1023 "malloc failed for Realloc!\n"));
1024 return -1;
1026 *ppdata = pdata;
1028 /* create the header */
1029 SSVAL(pdata,0,consumedcnt * 2); /* path consumed */
1030 SSVAL(pdata,2,junction->referral_count); /* number of referral */
1031 if(self_referral) {
1032 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
1033 } else {
1034 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
1037 /* copy in the reqpaths */
1038 memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen);
1039 memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen);
1041 offset = 8;
1042 for(i=0;i<junction->referral_count;i++) {
1043 struct referral* ref = &(junction->referral_list[i]);
1044 int unilen;
1046 SSVAL(pdata,offset,3); /* version 3 */
1047 SSVAL(pdata,offset+2,VERSION3_REFERRAL_SIZE);
1048 if(self_referral) {
1049 SSVAL(pdata,offset+4,1);
1050 } else {
1051 SSVAL(pdata,offset+4,0);
1054 /* ref_flags :use path_consumed bytes? */
1055 SSVAL(pdata,offset+6,0);
1056 SIVAL(pdata,offset+8,ref->ttl);
1058 SSVAL(pdata,offset+12,uni_reqpathoffset1-offset);
1059 SSVAL(pdata,offset+14,uni_reqpathoffset2-offset);
1060 /* copy referred path into current offset */
1061 unilen = rpcstr_push(pdata+uni_curroffset,ref->alternate_path,
1062 sizeof(pstring),
1063 STR_UNICODE | STR_TERMINATE);
1064 SSVAL(pdata,offset+16,uni_curroffset-offset);
1065 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
1066 memset(pdata+offset+18,'\0',16);
1068 uni_curroffset += unilen;
1069 offset += VERSION3_REFERRAL_SIZE;
1071 return reply_size;
1074 /******************************************************************
1075 Set up the DFS referral for the dfs pathname. This call returns
1076 the amount of the path covered by this server, and where the
1077 client should be redirected to. This is the meat of the
1078 TRANS2_GET_DFS_REFERRAL call.
1079 ******************************************************************/
1081 int setup_dfs_referral(connection_struct *orig_conn,
1082 const char *dfs_path,
1083 int max_referral_level,
1084 char **ppdata, NTSTATUS *pstatus)
1086 struct junction_map *junction = NULL;
1087 int consumedcnt = 0;
1088 BOOL self_referral = False;
1089 int reply_size = 0;
1090 char *pathnamep = NULL;
1091 char *local_dfs_path = NULL;
1092 TALLOC_CTX *ctx;
1094 if (!(ctx=talloc_init("setup_dfs_referral"))) {
1095 *pstatus = NT_STATUS_NO_MEMORY;
1096 return -1;
1099 /* get the junction entry */
1100 if (!dfs_path) {
1101 talloc_destroy(ctx);
1102 *pstatus = NT_STATUS_NOT_FOUND;
1103 return -1;
1107 * Trim pathname sent by client so it begins with only one backslash.
1108 * Two backslashes confuse some dfs clients
1111 local_dfs_path = talloc_strdup(ctx,dfs_path);
1112 if (!local_dfs_path) {
1113 *pstatus = NT_STATUS_NO_MEMORY;
1114 talloc_destroy(ctx);
1115 return -1;
1117 pathnamep = local_dfs_path;
1118 while (IS_DIRECTORY_SEP(pathnamep[0]) &&
1119 IS_DIRECTORY_SEP(pathnamep[1])) {
1120 pathnamep++;
1123 junction = TALLOC_ZERO_P(ctx, struct junction_map);
1124 if (!junction) {
1125 *pstatus = NT_STATUS_NO_MEMORY;
1126 talloc_destroy(ctx);
1127 return -1;
1130 /* The following call can change cwd. */
1131 *pstatus = get_referred_path(ctx, pathnamep, junction,
1132 &consumedcnt, &self_referral);
1133 if (!NT_STATUS_IS_OK(*pstatus)) {
1134 vfs_ChDir(orig_conn,orig_conn->connectpath);
1135 talloc_destroy(ctx);
1136 return -1;
1138 vfs_ChDir(orig_conn,orig_conn->connectpath);
1140 if (!self_referral) {
1141 pathnamep[consumedcnt] = '\0';
1143 if( DEBUGLVL( 3 ) ) {
1144 int i=0;
1145 dbgtext("setup_dfs_referral: Path %s to "
1146 "alternate path(s):",
1147 pathnamep);
1148 for(i=0;i<junction->referral_count;i++)
1149 dbgtext(" %s",
1150 junction->referral_list[i].alternate_path);
1151 dbgtext(".\n");
1155 /* create the referral depeding on version */
1156 DEBUG(10,("max_referral_level :%d\n",max_referral_level));
1158 if (max_referral_level < 2) {
1159 max_referral_level = 2;
1161 if (max_referral_level > 3) {
1162 max_referral_level = 3;
1165 switch(max_referral_level) {
1166 case 2:
1167 reply_size = setup_ver2_dfs_referral(pathnamep,
1168 ppdata, junction,
1169 consumedcnt, self_referral);
1170 break;
1171 case 3:
1172 reply_size = setup_ver3_dfs_referral(pathnamep, ppdata,
1173 junction, consumedcnt, self_referral);
1174 break;
1175 default:
1176 DEBUG(0,("setup_dfs_referral: Invalid dfs referral "
1177 "version: %d\n",
1178 max_referral_level));
1179 talloc_destroy(ctx);
1180 *pstatus = NT_STATUS_INVALID_LEVEL;
1181 return -1;
1184 if (DEBUGLVL(10)) {
1185 DEBUGADD(0,("DFS Referral pdata:\n"));
1186 dump_data(0,(uint8 *)*ppdata,reply_size);
1189 talloc_destroy(ctx);
1190 *pstatus = NT_STATUS_OK;
1191 return reply_size;
1194 /**********************************************************************
1195 The following functions are called by the NETDFS RPC pipe functions
1196 **********************************************************************/
1198 /*********************************************************************
1199 Creates a junction structure from a DFS pathname
1200 **********************************************************************/
1202 BOOL create_junction(TALLOC_CTX *ctx,
1203 const char *dfs_path,
1204 struct junction_map *jucn)
1206 int snum;
1207 BOOL dummy;
1208 struct dfs_path *pdp = TALLOC_P(ctx,struct dfs_path);
1209 NTSTATUS status;
1211 if (!pdp) {
1212 return False;
1214 status = parse_dfs_path(dfs_path, False, pdp, &dummy);
1215 if (!NT_STATUS_IS_OK(status)) {
1216 return False;
1219 /* check if path is dfs : validate first token */
1220 if (!is_myname_or_ipaddr(pdp->hostname)) {
1221 DEBUG(4,("create_junction: Invalid hostname %s "
1222 "in dfs path %s\n",
1223 pdp->hostname, dfs_path));
1224 TALLOC_FREE(pdp);
1225 return False;
1228 /* Check for a non-DFS share */
1229 snum = lp_servicenumber(pdp->servicename);
1231 if(snum < 0 || !lp_msdfs_root(snum)) {
1232 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1233 pdp->servicename));
1234 TALLOC_FREE(pdp);
1235 return False;
1238 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1239 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1240 jucn->comment = talloc_strdup(ctx, lp_comment(snum));
1242 TALLOC_FREE(pdp);
1243 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1244 return False;
1246 return True;
1249 /**********************************************************************
1250 Forms a valid Unix pathname from the junction
1251 **********************************************************************/
1253 static BOOL junction_to_local_path(const struct junction_map *jucn,
1254 char **pp_path_out,
1255 connection_struct *conn_out)
1257 int snum;
1259 snum = lp_servicenumber(jucn->service_name);
1260 if(snum < 0) {
1261 return False;
1263 if (!NT_STATUS_IS_OK(create_conn_struct(conn_out, snum,
1264 lp_pathname(snum)))) {
1265 return False;
1268 *pp_path_out = talloc_asprintf(conn_out->mem_ctx,
1269 "%s/%s",
1270 lp_pathname(snum),
1271 jucn->volume_name);
1272 if (!*pp_path_out) {
1273 return False;
1275 return True;
1278 BOOL create_msdfs_link(const struct junction_map *jucn,
1279 BOOL exists)
1281 char *path = NULL;
1282 char *msdfs_link = NULL;
1283 connection_struct conns;
1284 connection_struct *conn = &conns;
1285 int i=0;
1286 BOOL insert_comma = False;
1287 BOOL ret = False;
1289 ZERO_STRUCT(conns);
1291 if(!junction_to_local_path(jucn, &path, conn)) {
1292 return False;
1295 /* Form the msdfs_link contents */
1296 msdfs_link = talloc_strdup(conn->mem_ctx, "msdfs:");
1297 if (!msdfs_link) {
1298 goto out;
1300 for(i=0; i<jucn->referral_count; i++) {
1301 char *refpath = jucn->referral_list[i].alternate_path;
1303 /* Alternate paths always use Windows separators. */
1304 trim_char(refpath, '\\', '\\');
1305 if(*refpath == '\0') {
1306 if (i == 0) {
1307 insert_comma = False;
1309 continue;
1311 if (i > 0 && insert_comma) {
1312 msdfs_link = talloc_asprintf_append(msdfs_link,
1313 ",%s",
1314 refpath);
1315 } else {
1316 msdfs_link = talloc_asprintf_append(msdfs_link,
1317 "%s",
1318 refpath);
1321 if (!msdfs_link) {
1322 goto out;
1324 if (!insert_comma) {
1325 insert_comma = True;
1329 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1330 path, msdfs_link));
1332 if(exists) {
1333 if(SMB_VFS_UNLINK(conn,path)!=0) {
1334 goto out;
1338 if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1339 DEBUG(1,("create_msdfs_link: symlink failed "
1340 "%s -> %s\nError: %s\n",
1341 path, msdfs_link, strerror(errno)));
1342 goto out;
1345 ret = True;
1347 out:
1349 conn_free_internal(conn);
1350 return ret;
1353 BOOL remove_msdfs_link(const struct junction_map *jucn)
1355 char *path = NULL;
1356 connection_struct conns;
1357 connection_struct *conn = &conns;
1358 BOOL ret = False;
1360 ZERO_STRUCT(conns);
1362 if( junction_to_local_path(jucn, &path, conn) ) {
1363 if( SMB_VFS_UNLINK(conn, path) == 0 ) {
1364 ret = True;
1368 conn_free_internal(conn);
1369 return ret;
1372 /*********************************************************************
1373 Return the number of DFS links at the root of this share.
1374 *********************************************************************/
1376 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1378 size_t cnt = 0;
1379 SMB_STRUCT_DIR *dirp = NULL;
1380 char *dname = NULL;
1381 const char *connect_path = lp_pathname(snum);
1382 const char *msdfs_proxy = lp_msdfs_proxy(snum);
1383 connection_struct conn;
1385 ZERO_STRUCT(conn);
1387 if(*connect_path == '\0') {
1388 return 0;
1392 * Fake up a connection struct for the VFS layer.
1395 if (!NT_STATUS_IS_OK(create_conn_struct(&conn, snum, connect_path))) {
1396 return 0;
1399 /* Count a link for the msdfs root - convention */
1400 cnt = 1;
1402 /* No more links if this is an msdfs proxy. */
1403 if (*msdfs_proxy != '\0') {
1404 goto out;
1407 /* Now enumerate all dfs links */
1408 dirp = SMB_VFS_OPENDIR(&conn, ".", NULL, 0);
1409 if(!dirp) {
1410 goto out;
1413 while ((dname = vfs_readdirname(&conn, dirp)) != NULL) {
1414 if (is_msdfs_link(&conn,
1415 dname,
1416 NULL)) {
1417 cnt++;
1421 SMB_VFS_CLOSEDIR(&conn,dirp);
1423 out:
1425 conn_free_internal(&conn);
1426 return cnt;
1429 /*********************************************************************
1430 *********************************************************************/
1432 static int form_junctions(TALLOC_CTX *ctx,
1433 int snum,
1434 struct junction_map *jucn,
1435 size_t jn_remain)
1437 size_t cnt = 0;
1438 SMB_STRUCT_DIR *dirp = NULL;
1439 char *dname = NULL;
1440 const char *connect_path = lp_pathname(snum);
1441 char *service_name = lp_servicename(snum);
1442 const char *msdfs_proxy = lp_msdfs_proxy(snum);
1443 connection_struct conn;
1444 struct referral *ref = NULL;
1446 ZERO_STRUCT(conn);
1448 if (jn_remain == 0) {
1449 return 0;
1452 if(*connect_path == '\0') {
1453 return 0;
1457 * Fake up a connection struct for the VFS layer.
1460 if (!NT_STATUS_IS_OK(create_conn_struct(&conn, snum, connect_path))) {
1461 return 0;
1464 /* form a junction for the msdfs root - convention
1465 DO NOT REMOVE THIS: NT clients will not work with us
1466 if this is not present
1468 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1469 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1470 if (!jucn[cnt].service_name || jucn[cnt].volume_name) {
1471 goto out;
1473 jucn[cnt].referral_count = 1;
1475 ref = jucn[cnt].referral_list = TALLOC_ZERO_P(ctx, struct referral);
1476 if (jucn[cnt].referral_list == NULL) {
1477 goto out;
1480 ref->proximity = 0;
1481 ref->ttl = REFERRAL_TTL;
1482 if (*msdfs_proxy != '\0') {
1483 ref->alternate_path = talloc_strdup(ctx,
1484 msdfs_proxy);
1485 } else {
1486 ref->alternate_path = talloc_asprintf(ctx,
1487 "\\\\%s\\%s",
1488 get_local_machine_name(),
1489 service_name);
1492 if (!ref->alternate_path) {
1493 goto out;
1495 cnt++;
1497 /* Don't enumerate if we're an msdfs proxy. */
1498 if (*msdfs_proxy != '\0') {
1499 goto out;
1502 /* Now enumerate all dfs links */
1503 dirp = SMB_VFS_OPENDIR(&conn, ".", NULL, 0);
1504 if(!dirp) {
1505 goto out;
1508 while ((dname = vfs_readdirname(&conn, dirp)) != NULL) {
1509 char *link_target = NULL;
1510 if (cnt >= jn_remain) {
1511 SMB_VFS_CLOSEDIR(&conn,dirp);
1512 DEBUG(2, ("form_junctions: ran out of MSDFS "
1513 "junction slots"));
1514 goto out;
1516 if (is_msdfs_link_internal(ctx,
1517 &conn,
1518 dname, &link_target,
1519 NULL)) {
1520 if (parse_msdfs_symlink(ctx,
1521 link_target,
1522 &jucn[cnt].referral_list,
1523 &jucn[cnt].referral_count)) {
1525 jucn[cnt].service_name = talloc_strdup(ctx,
1526 service_name);
1527 jucn[cnt].volume_name = talloc_strdup(ctx,
1528 dname);
1529 if (!jucn[cnt].service_name ||
1530 !jucn[cnt].volume_name) {
1531 goto out;
1533 cnt++;
1538 out:
1540 if (dirp) {
1541 SMB_VFS_CLOSEDIR(&conn,dirp);
1544 conn_free_internal(&conn);
1545 return cnt;
1548 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1550 struct junction_map *jn = NULL;
1551 int i=0;
1552 size_t jn_count;
1553 int sharecount = 0;
1555 *p_num_jn = 0;
1556 if(!lp_host_msdfs()) {
1557 return NULL;
1560 /* Ensure all the usershares are loaded. */
1561 become_root();
1562 load_registry_shares();
1563 sharecount = load_usershare_shares();
1564 unbecome_root();
1566 for(i=0;i < sharecount;i++) {
1567 if(lp_msdfs_root(i)) {
1568 jn_count += count_dfs_links(ctx, i);
1571 if (jn_count == 0) {
1572 return NULL;
1574 jn = TALLOC_ARRAY(ctx, struct junction_map, jn_count);
1575 if (!jn) {
1576 return NULL;
1578 for(i=0; i < sharecount; i++) {
1579 if (*p_num_jn >= jn_count) {
1580 break;
1582 if(lp_msdfs_root(i)) {
1583 *p_num_jn += form_junctions(ctx, i,
1584 &jn[*p_num_jn],
1585 jn_count - *p_num_jn);
1588 return jn;
1591 /******************************************************************************
1592 Core function to resolve a dfs pathname.
1593 ******************************************************************************/
1595 NTSTATUS resolve_dfspath(TALLOC_CTX *ctx,
1596 connection_struct *conn,
1597 BOOL dfs_pathnames,
1598 const char *name_in,
1599 char **pp_name_out)
1601 NTSTATUS status = NT_STATUS_OK;
1602 BOOL dummy;
1603 if (dfs_pathnames) {
1604 status = dfs_redirect(ctx,
1605 conn,
1606 name_in,
1607 False,
1608 pp_name_out,
1609 &dummy);
1610 } else {
1612 * Cheat and just return a copy of the in ptr.
1613 * Once srvstr_get_path() uses talloc it'll
1614 * be a talloced ptr anyway.
1616 *pp_name_out = CONST_DISCARD(char *,name_in);
1618 return status;
1621 /******************************************************************************
1622 Core function to resolve a dfs pathname possibly containing a wildcard.
1623 This function is identical to the above except for the BOOL param to
1624 dfs_redirect but I need this to be separate so it's really clear when
1625 we're allowing wildcards and when we're not. JRA.
1626 ******************************************************************************/
1628 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1629 connection_struct *conn,
1630 BOOL dfs_pathnames,
1631 const char *name_in,
1632 char **pp_name_out,
1633 BOOL *ppath_contains_wcard)
1635 NTSTATUS status = NT_STATUS_OK;
1636 if (dfs_pathnames) {
1637 status = dfs_redirect(ctx,
1638 conn,
1639 name_in,
1640 True,
1641 pp_name_out,
1642 ppath_contains_wcard);
1643 } else {
1645 * Cheat and just return a copy of the in ptr.
1646 * Once srvstr_get_path() uses talloc it'll
1647 * be a talloced ptr anyway.
1649 *pp_name_out = CONST_DISCARD(char *,name_in);
1651 return status;