Use rpccli_samr_LookupNames() in net.
[Samba/gebeck_regimport.git] / source3 / smbd / msdfs.c
blob8ffa0f7751cb4ce1cd0d1d0c9cb0a2143ab71da4
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(TALLOC_CTX *ctx,
200 connection_struct *conn,
201 int snum,
202 const char *path)
204 char *connpath;
206 ZERO_STRUCTP(conn);
208 connpath = talloc_strdup(ctx, path);
209 if (!connpath) {
210 return NT_STATUS_NO_MEMORY;
212 connpath = talloc_string_sub(ctx,
213 connpath,
214 "%S",
215 lp_servicename(snum));
216 if (!connpath) {
217 return NT_STATUS_NO_MEMORY;
220 /* needed for smbd_vfs_init() */
222 if ((conn->mem_ctx=talloc_init("connection_struct")) == NULL) {
223 DEBUG(0,("talloc_init(connection_struct) failed!\n"));
224 return NT_STATUS_NO_MEMORY;
227 if (!(conn->params = TALLOC_ZERO_P(conn->mem_ctx,
228 struct share_params))) {
229 DEBUG(0, ("TALLOC failed\n"));
230 return NT_STATUS_NO_MEMORY;
233 conn->params->service = snum;
235 set_conn_connectpath(conn, connpath);
237 if (!smbd_vfs_init(conn)) {
238 NTSTATUS status = map_nt_error_from_unix(errno);
239 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
240 conn_free_internal(conn);
241 return status;
245 * Windows seems to insist on doing trans2getdfsreferral() calls on
246 * the IPC$ share as the anonymous user. If we try to chdir as that
247 * user we will fail.... WTF ? JRA.
250 if (vfs_ChDir(conn,conn->connectpath) != 0) {
251 NTSTATUS status = map_nt_error_from_unix(errno);
252 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
253 "Error was %s\n",
254 conn->connectpath, strerror(errno) ));
255 conn_free_internal(conn);
256 return status;
259 return NT_STATUS_OK;
262 /**********************************************************************
263 Parse the contents of a symlink to verify if it is an msdfs referral
264 A valid referral is of the form:
266 msdfs:server1\share1,server2\share2
267 msdfs:server1\share1\pathname,server2\share2\pathname
268 msdfs:server1/share1,server2/share2
269 msdfs:server1/share1/pathname,server2/share2/pathname.
271 Note that the alternate paths returned here must be of the canonicalized
272 form:
274 \server\share or
275 \server\share\path\to\file,
277 even in posix path mode. This is because we have no knowledge if the
278 server we're referring to understands posix paths.
279 **********************************************************************/
281 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
282 const char *target,
283 struct referral **preflist,
284 int *refcount)
286 char *temp = NULL;
287 char *prot;
288 char **alt_path = NULL;
289 int count = 0, i;
290 struct referral *reflist;
291 char *saveptr;
293 temp = talloc_strdup(ctx, target);
294 if (!temp) {
295 return False;
297 prot = strtok_r(temp, ":", &saveptr);
298 if (!prot) {
299 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
300 return False;
303 alt_path = TALLOC_ARRAY(ctx, char *, MAX_REFERRAL_COUNT);
304 if (!alt_path) {
305 return False;
308 /* parse out the alternate paths */
309 while((count<MAX_REFERRAL_COUNT) &&
310 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
311 count++;
314 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
316 if (count) {
317 reflist = *preflist = TALLOC_ZERO_ARRAY(ctx,
318 struct referral, count);
319 if(reflist == NULL) {
320 TALLOC_FREE(alt_path);
321 return False;
323 } else {
324 reflist = *preflist = NULL;
327 for(i=0;i<count;i++) {
328 char *p;
330 /* Canonicalize link target.
331 * Replace all /'s in the path by a \ */
332 string_replace(alt_path[i], '/', '\\');
334 /* Remove leading '\\'s */
335 p = alt_path[i];
336 while (*p && (*p == '\\')) {
337 p++;
340 reflist[i].alternate_path = talloc_asprintf(ctx,
341 "\\%s",
343 if (!reflist[i].alternate_path) {
344 return False;
347 reflist[i].proximity = 0;
348 reflist[i].ttl = REFERRAL_TTL;
349 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
350 reflist[i].alternate_path));
351 *refcount += 1;
354 TALLOC_FREE(alt_path);
355 return True;
358 /**********************************************************************
359 Returns true if the unix path is a valid msdfs symlink and also
360 returns the target string from inside the link.
361 **********************************************************************/
363 static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
364 connection_struct *conn,
365 const char *path,
366 char **pp_link_target,
367 SMB_STRUCT_STAT *sbufp)
369 SMB_STRUCT_STAT st;
370 int referral_len = 0;
371 char link_target_buf[7];
372 size_t bufsize = 0;
373 char *link_target = NULL;
375 if (pp_link_target) {
376 bufsize = 1024;
377 link_target = TALLOC_ARRAY(ctx, char, bufsize);
378 if (!link_target) {
379 return False;
381 *pp_link_target = link_target;
382 } else {
383 bufsize = sizeof(link_target_buf);
384 link_target = link_target_buf;
387 if (sbufp == NULL) {
388 sbufp = &st;
391 if (SMB_VFS_LSTAT(conn, path, sbufp) != 0) {
392 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
393 path));
394 goto err;
397 if (!S_ISLNK(sbufp->st_mode)) {
398 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
399 path));
400 goto err;
403 referral_len = SMB_VFS_READLINK(conn, path, link_target, bufsize - 1);
404 if (referral_len == -1) {
405 DEBUG(0,("is_msdfs_link_read_target: Error reading "
406 "msdfs link %s: %s\n",
407 path, strerror(errno)));
408 goto err;
410 link_target[referral_len] = '\0';
412 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path,
413 link_target));
415 if (!strnequal(link_target, "msdfs:", 6)) {
416 goto err;
418 return True;
420 err:
422 if (link_target != link_target_buf) {
423 TALLOC_FREE(link_target);
425 return False;
428 /**********************************************************************
429 Returns true if the unix path is a valid msdfs symlink.
430 **********************************************************************/
432 bool is_msdfs_link(connection_struct *conn,
433 const char *path,
434 SMB_STRUCT_STAT *sbufp)
436 return is_msdfs_link_internal(talloc_tos(),
437 conn,
438 path,
439 NULL,
440 sbufp);
443 /*****************************************************************
444 Used by other functions to decide if a dfs path is remote,
445 and to get the list of referred locations for that remote path.
447 search_flag: For findfirsts, dfs links themselves are not
448 redirected, but paths beyond the links are. For normal smb calls,
449 even dfs links need to be redirected.
451 consumedcntp: how much of the dfs path is being redirected. the client
452 should try the remaining path on the redirected server.
454 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
455 link redirect are in targetpath.
456 *****************************************************************/
458 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
459 connection_struct *conn,
460 const char *dfspath, /* Incoming complete dfs path */
461 const struct dfs_path *pdp, /* Parsed out
462 server+share+extrapath. */
463 bool search_flag, /* Called from a findfirst ? */
464 int *consumedcntp,
465 char **pp_targetpath)
467 char *p = NULL;
468 char *q = NULL;
469 SMB_STRUCT_STAT sbuf;
470 NTSTATUS status;
471 char *localpath = NULL;
472 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
473 components). */
475 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
476 conn->connectpath, pdp->reqpath));
479 * Note the unix path conversion here we're doing we can
480 * throw away. We're looking for a symlink for a dfs
481 * resolution, if we don't find it we'll do another
482 * unix_convert later in the codepath.
483 * If we needed to remember what we'd resolved in
484 * dp->reqpath (as the original code did) we'd
485 * copy (localhost, dp->reqpath) on any code
486 * path below that returns True - but I don't
487 * think this is needed. JRA.
490 status = unix_convert(ctx, conn, pdp->reqpath, search_flag, &localpath,
491 NULL, &sbuf);
492 if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status,
493 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
494 return status;
497 /* Optimization - check if we can redirect the whole path. */
499 if (is_msdfs_link_internal(ctx, conn, localpath, pp_targetpath, NULL)) {
500 if (search_flag) {
501 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
502 "for dfs link %s.\n", dfspath));
503 return NT_STATUS_OK;
506 DEBUG(6,("dfs_path_lookup: %s resolves to a "
507 "valid dfs link %s.\n", dfspath,
508 pp_targetpath ? *pp_targetpath : ""));
510 if (consumedcntp) {
511 *consumedcntp = strlen(dfspath);
513 return NT_STATUS_PATH_NOT_COVERED;
516 /* Prepare to test only for '/' components in the given path,
517 * so if a Windows path replace all '\\' characters with '/'.
518 * For a POSIX DFS path we know all separators are already '/'. */
520 canon_dfspath = talloc_strdup(ctx, dfspath);
521 if (!canon_dfspath) {
522 return NT_STATUS_NO_MEMORY;
524 if (!pdp->posix_path) {
525 string_replace(canon_dfspath, '\\', '/');
529 * localpath comes out of unix_convert, so it has
530 * no trailing backslash. Make sure that canon_dfspath hasn't either.
531 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
534 trim_char(canon_dfspath,0,'/');
537 * Redirect if any component in the path is a link.
538 * We do this by walking backwards through the
539 * local path, chopping off the last component
540 * in both the local path and the canonicalized
541 * DFS path. If we hit a DFS link then we're done.
544 p = strrchr_m(localpath, '/');
545 if (consumedcntp) {
546 q = strrchr_m(canon_dfspath, '/');
549 while (p) {
550 *p = '\0';
551 if (q) {
552 *q = '\0';
555 if (is_msdfs_link_internal(ctx, conn,
556 localpath, pp_targetpath, NULL)) {
557 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
558 "parent %s is dfs link\n", dfspath, localpath));
560 if (consumedcntp) {
561 *consumedcntp = strlen(canon_dfspath);
562 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
563 "(%d)\n",
564 canon_dfspath,
565 *consumedcntp));
568 return NT_STATUS_PATH_NOT_COVERED;
571 /* Step back on the filesystem. */
572 p = strrchr_m(localpath, '/');
574 if (consumedcntp) {
575 /* And in the canonicalized dfs path. */
576 q = strrchr_m(canon_dfspath, '/');
580 return NT_STATUS_OK;
583 /*****************************************************************
584 Decides if a dfs pathname should be redirected or not.
585 If not, the pathname is converted to a tcon-relative local unix path
587 search_wcard_flag: this flag performs 2 functions both related
588 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
589 for details.
591 This function can return NT_STATUS_OK, meaning use the returned path as-is
592 (mapped into a local path).
593 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
594 any other NT_STATUS error which is a genuine error to be
595 returned to the client.
596 *****************************************************************/
598 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
599 connection_struct *conn,
600 const char *path_in,
601 bool search_wcard_flag,
602 char **pp_path_out,
603 bool *ppath_contains_wcard)
605 NTSTATUS status;
606 struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
608 if (!pdp) {
609 return NT_STATUS_NO_MEMORY;
612 status = parse_dfs_path(path_in, search_wcard_flag, pdp,
613 ppath_contains_wcard);
614 if (!NT_STATUS_IS_OK(status)) {
615 TALLOC_FREE(pdp);
616 return status;
619 if (pdp->reqpath[0] == '\0') {
620 TALLOC_FREE(pdp);
621 *pp_path_out = talloc_strdup(ctx, "");
622 if (!*pp_path_out) {
623 return NT_STATUS_NO_MEMORY;
625 DEBUG(5,("dfs_redirect: self-referral.\n"));
626 return NT_STATUS_OK;
629 /* If dfs pathname for a non-dfs share, convert to tcon-relative
630 path and return OK */
632 if (!lp_msdfs_root(SNUM(conn))) {
633 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
634 TALLOC_FREE(pdp);
635 if (!*pp_path_out) {
636 return NT_STATUS_NO_MEMORY;
638 return NT_STATUS_OK;
641 /* If it looked like a local path (zero hostname/servicename)
642 * just treat as a tcon-relative path. */
644 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
645 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
646 TALLOC_FREE(pdp);
647 if (!*pp_path_out) {
648 return NT_STATUS_NO_MEMORY;
650 return NT_STATUS_OK;
653 if (!( strequal(pdp->servicename, lp_servicename(SNUM(conn)))
654 || (strequal(pdp->servicename, HOMES_NAME)
655 && strequal(lp_servicename(SNUM(conn)),
656 get_current_username()) )) ) {
658 /* The given sharename doesn't match this connection. */
659 TALLOC_FREE(pdp);
661 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
664 status = dfs_path_lookup(ctx, conn, path_in, pdp,
665 search_wcard_flag, NULL, NULL);
666 if (!NT_STATUS_IS_OK(status)) {
667 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
668 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
669 } else {
670 DEBUG(10,("dfs_redirect: dfs_path_lookup "
671 "failed for %s with %s\n",
672 path_in, nt_errstr(status) ));
674 return status;
677 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
679 /* Form non-dfs tcon-relative path */
680 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
681 TALLOC_FREE(pdp);
682 if (!*pp_path_out) {
683 return NT_STATUS_NO_MEMORY;
686 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
687 path_in,
688 *pp_path_out));
690 return NT_STATUS_OK;
693 /**********************************************************************
694 Return a self referral.
695 **********************************************************************/
697 static NTSTATUS self_ref(TALLOC_CTX *ctx,
698 const char *dfs_path,
699 struct junction_map *jucn,
700 int *consumedcntp,
701 bool *self_referralp)
703 struct referral *ref;
705 *self_referralp = True;
707 jucn->referral_count = 1;
708 if((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
709 return NT_STATUS_NO_MEMORY;
712 ref->alternate_path = talloc_strdup(ctx, dfs_path);
713 if (!ref->alternate_path) {
714 return NT_STATUS_NO_MEMORY;
716 ref->proximity = 0;
717 ref->ttl = REFERRAL_TTL;
718 jucn->referral_list = ref;
719 *consumedcntp = strlen(dfs_path);
720 return NT_STATUS_OK;
723 /**********************************************************************
724 Gets valid referrals for a dfs path and fills up the
725 junction_map structure.
726 **********************************************************************/
728 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
729 const char *dfs_path,
730 struct junction_map *jucn,
731 int *consumedcntp,
732 bool *self_referralp)
734 struct connection_struct conns;
735 struct connection_struct *conn = &conns;
736 char *targetpath = NULL;
737 int snum;
738 NTSTATUS status = NT_STATUS_NOT_FOUND;
739 bool dummy;
740 struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
742 if (!pdp) {
743 return NT_STATUS_NO_MEMORY;
746 ZERO_STRUCT(conns);
747 *self_referralp = False;
749 status = parse_dfs_path(dfs_path, False, pdp, &dummy);
750 if (!NT_STATUS_IS_OK(status)) {
751 return status;
754 /* Verify hostname in path */
755 if (!is_myname_or_ipaddr(pdp->hostname)) {
756 DEBUG(3, ("get_referred_path: Invalid hostname %s in path %s\n",
757 pdp->hostname, dfs_path));
758 TALLOC_FREE(pdp);
759 return NT_STATUS_NOT_FOUND;
762 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
763 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
764 if (!jucn->service_name || !jucn->volume_name) {
765 TALLOC_FREE(pdp);
766 return NT_STATUS_NO_MEMORY;
769 /* Verify the share is a dfs root */
770 snum = lp_servicenumber(jucn->service_name);
771 if(snum < 0) {
772 fstring service_name;
773 fstrcpy(service_name, jucn->service_name);
774 if ((snum = find_service(service_name)) < 0) {
775 return NT_STATUS_NOT_FOUND;
777 TALLOC_FREE(jucn->service_name);
778 jucn->service_name = talloc_strdup(ctx, service_name);
779 if (!jucn->service_name) {
780 TALLOC_FREE(pdp);
781 return NT_STATUS_NO_MEMORY;
785 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(snum) == '\0')) {
786 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
787 "a dfs root.\n",
788 pdp->servicename, dfs_path));
789 TALLOC_FREE(pdp);
790 return NT_STATUS_NOT_FOUND;
794 * Self referrals are tested with a anonymous IPC connection and
795 * a GET_DFS_REFERRAL call to \\server\share. (which means
796 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
797 * into the directory and will fail if it cannot (as the anonymous
798 * user). Cope with this.
801 if (pdp->reqpath[0] == '\0') {
802 char *tmp;
803 struct referral *ref;
805 if (*lp_msdfs_proxy(snum) == '\0') {
806 TALLOC_FREE(pdp);
807 return self_ref(ctx,
808 dfs_path,
809 jucn,
810 consumedcntp,
811 self_referralp);
815 * It's an msdfs proxy share. Redirect to
816 * the configured target share.
819 jucn->referral_count = 1;
820 if ((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
821 TALLOC_FREE(pdp);
822 return NT_STATUS_NO_MEMORY;
825 if (!(tmp = talloc_strdup(ctx, lp_msdfs_proxy(snum)))) {
826 TALLOC_FREE(pdp);
827 return NT_STATUS_NO_MEMORY;
830 trim_string(tmp, "\\", 0);
832 ref->alternate_path = talloc_asprintf(ctx, "\\%s", tmp);
833 TALLOC_FREE(tmp);
835 if (!ref->alternate_path) {
836 TALLOC_FREE(pdp);
837 return NT_STATUS_NO_MEMORY;
840 if (pdp->reqpath[0] != '\0') {
841 ref->alternate_path = talloc_asprintf_append(
842 ref->alternate_path,
843 "%s",
844 pdp->reqpath);
845 if (!ref->alternate_path) {
846 TALLOC_FREE(pdp);
847 return NT_STATUS_NO_MEMORY;
850 ref->proximity = 0;
851 ref->ttl = REFERRAL_TTL;
852 jucn->referral_list = ref;
853 *consumedcntp = strlen(dfs_path);
854 TALLOC_FREE(pdp);
855 return NT_STATUS_OK;
858 status = create_conn_struct(ctx, conn, snum, lp_pathname(snum));
859 if (!NT_STATUS_IS_OK(status)) {
860 TALLOC_FREE(pdp);
861 return status;
864 /* If this is a DFS path dfs_lookup should return
865 * NT_STATUS_PATH_NOT_COVERED. */
867 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
868 False, consumedcntp, &targetpath);
870 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
871 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
872 dfs_path));
873 conn_free_internal(conn);
874 TALLOC_FREE(pdp);
875 return status;
878 /* We know this is a valid dfs link. Parse the targetpath. */
879 if (!parse_msdfs_symlink(ctx, targetpath,
880 &jucn->referral_list,
881 &jucn->referral_count)) {
882 DEBUG(3,("get_referred_path: failed to parse symlink "
883 "target %s\n", targetpath ));
884 conn_free_internal(conn);
885 TALLOC_FREE(pdp);
886 return NT_STATUS_NOT_FOUND;
889 conn_free_internal(conn);
890 TALLOC_FREE(pdp);
891 return NT_STATUS_OK;
894 static int setup_ver2_dfs_referral(const char *pathname,
895 char **ppdata,
896 struct junction_map *junction,
897 int consumedcnt,
898 bool self_referral)
900 char* pdata = *ppdata;
902 smb_ucs2_t *uni_requestedpath = NULL;
903 int uni_reqpathoffset1,uni_reqpathoffset2;
904 int uni_curroffset;
905 int requestedpathlen=0;
906 int offset;
907 int reply_size = 0;
908 int i=0;
910 DEBUG(10,("Setting up version2 referral\nRequested path:\n"));
912 requestedpathlen = rpcstr_push_talloc(talloc_tos(),
913 &uni_requestedpath, pathname);
914 if (uni_requestedpath == NULL || requestedpathlen == 0) {
915 return -1;
918 if (DEBUGLVL(10)) {
919 dump_data(0, (unsigned char *)uni_requestedpath,
920 requestedpathlen);
923 DEBUG(10,("ref count = %u\n",junction->referral_count));
925 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
926 VERSION2_REFERRAL_SIZE * junction->referral_count;
928 uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen;
930 uni_curroffset = uni_reqpathoffset2 + requestedpathlen;
932 reply_size = REFERRAL_HEADER_SIZE +
933 VERSION2_REFERRAL_SIZE*junction->referral_count +
934 2 * requestedpathlen;
935 DEBUG(10,("reply_size: %u\n",reply_size));
937 /* add up the unicode lengths of all the referral paths */
938 for(i=0;i<junction->referral_count;i++) {
939 DEBUG(10,("referral %u : %s\n",
941 junction->referral_list[i].alternate_path));
942 reply_size +=
943 (strlen(junction->referral_list[i].alternate_path)+1)*2;
946 DEBUG(10,("reply_size = %u\n",reply_size));
947 /* add the unexplained 0x16 bytes */
948 reply_size += 0x16;
950 pdata = (char *)SMB_REALLOC(pdata,reply_size);
951 if(pdata == NULL) {
952 DEBUG(0,("Realloc failed!\n"));
953 return -1;
955 *ppdata = pdata;
957 /* copy in the dfs requested paths.. required for offset calculations */
958 memcpy(pdata+uni_reqpathoffset1,uni_requestedpath,requestedpathlen);
959 memcpy(pdata+uni_reqpathoffset2,uni_requestedpath,requestedpathlen);
961 /* create the header */
962 SSVAL(pdata,0,consumedcnt * 2); /* path consumed */
963 /* number of referral in this pkt */
964 SSVAL(pdata,2,junction->referral_count);
965 if(self_referral) {
966 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
967 } else {
968 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
971 offset = 8;
972 /* add the referral elements */
973 for(i=0;i<junction->referral_count;i++) {
974 struct referral* ref = &junction->referral_list[i];
975 int unilen;
977 SSVAL(pdata,offset,2); /* version 2 */
978 SSVAL(pdata,offset+2,VERSION2_REFERRAL_SIZE);
979 if(self_referral) {
980 SSVAL(pdata,offset+4,1);
981 } else {
982 SSVAL(pdata,offset+4,0);
985 /* ref_flags :use path_consumed bytes? */
986 SSVAL(pdata,offset+6,0);
987 SIVAL(pdata,offset+8,ref->proximity);
988 SIVAL(pdata,offset+12,ref->ttl);
990 SSVAL(pdata,offset+16,uni_reqpathoffset1-offset);
991 SSVAL(pdata,offset+18,uni_reqpathoffset2-offset);
992 /* copy referred path into current offset */
993 unilen = rpcstr_push(pdata+uni_curroffset,
994 ref->alternate_path,
995 reply_size - uni_curroffset,
996 STR_UNICODE);
998 SSVAL(pdata,offset+20,uni_curroffset-offset);
1000 uni_curroffset += unilen;
1001 offset += VERSION2_REFERRAL_SIZE;
1003 /* add in the unexplained 22 (0x16) bytes at the end */
1004 memset(pdata+uni_curroffset,'\0',0x16);
1005 return reply_size;
1008 static int setup_ver3_dfs_referral(const char *pathname,
1009 char **ppdata,
1010 struct junction_map *junction,
1011 int consumedcnt,
1012 bool self_referral)
1014 char *pdata = *ppdata;
1016 smb_ucs2_t *uni_reqpath = NULL;
1017 int uni_reqpathoffset1, uni_reqpathoffset2;
1018 int uni_curroffset;
1019 int reply_size = 0;
1021 int reqpathlen = 0;
1022 int offset,i=0;
1024 DEBUG(10,("setting up version3 referral\n"));
1026 reqpathlen = rpcstr_push_talloc(talloc_tos(), &uni_reqpath, pathname);
1027 if (uni_reqpath == NULL || reqpathlen == 0) {
1028 return -1;
1031 if (DEBUGLVL(10)) {
1032 dump_data(0, (unsigned char *)uni_reqpath,
1033 reqpathlen);
1036 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
1037 VERSION3_REFERRAL_SIZE * junction->referral_count;
1038 uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen;
1039 reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen;
1041 for(i=0;i<junction->referral_count;i++) {
1042 DEBUG(10,("referral %u : %s\n",
1044 junction->referral_list[i].alternate_path));
1045 reply_size +=
1046 (strlen(junction->referral_list[i].alternate_path)+1)*2;
1049 pdata = (char *)SMB_REALLOC(pdata,reply_size);
1050 if(pdata == NULL) {
1051 DEBUG(0,("version3 referral setup:"
1052 "malloc failed for Realloc!\n"));
1053 return -1;
1055 *ppdata = pdata;
1057 /* create the header */
1058 SSVAL(pdata,0,consumedcnt * 2); /* path consumed */
1059 SSVAL(pdata,2,junction->referral_count); /* number of referral */
1060 if(self_referral) {
1061 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
1062 } else {
1063 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
1066 /* copy in the reqpaths */
1067 memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen);
1068 memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen);
1070 offset = 8;
1071 for(i=0;i<junction->referral_count;i++) {
1072 struct referral* ref = &(junction->referral_list[i]);
1073 int unilen;
1075 SSVAL(pdata,offset,3); /* version 3 */
1076 SSVAL(pdata,offset+2,VERSION3_REFERRAL_SIZE);
1077 if(self_referral) {
1078 SSVAL(pdata,offset+4,1);
1079 } else {
1080 SSVAL(pdata,offset+4,0);
1083 /* ref_flags :use path_consumed bytes? */
1084 SSVAL(pdata,offset+6,0);
1085 SIVAL(pdata,offset+8,ref->ttl);
1087 SSVAL(pdata,offset+12,uni_reqpathoffset1-offset);
1088 SSVAL(pdata,offset+14,uni_reqpathoffset2-offset);
1089 /* copy referred path into current offset */
1090 unilen = rpcstr_push(pdata+uni_curroffset,ref->alternate_path,
1091 reply_size - uni_curroffset,
1092 STR_UNICODE | STR_TERMINATE);
1093 SSVAL(pdata,offset+16,uni_curroffset-offset);
1094 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
1095 memset(pdata+offset+18,'\0',16);
1097 uni_curroffset += unilen;
1098 offset += VERSION3_REFERRAL_SIZE;
1100 return reply_size;
1103 /******************************************************************
1104 Set up the DFS referral for the dfs pathname. This call returns
1105 the amount of the path covered by this server, and where the
1106 client should be redirected to. This is the meat of the
1107 TRANS2_GET_DFS_REFERRAL call.
1108 ******************************************************************/
1110 int setup_dfs_referral(connection_struct *orig_conn,
1111 const char *dfs_path,
1112 int max_referral_level,
1113 char **ppdata, NTSTATUS *pstatus)
1115 struct junction_map *junction = NULL;
1116 int consumedcnt = 0;
1117 bool self_referral = False;
1118 int reply_size = 0;
1119 char *pathnamep = NULL;
1120 char *local_dfs_path = NULL;
1121 TALLOC_CTX *ctx;
1123 if (!(ctx=talloc_init("setup_dfs_referral"))) {
1124 *pstatus = NT_STATUS_NO_MEMORY;
1125 return -1;
1128 /* get the junction entry */
1129 if (!dfs_path) {
1130 talloc_destroy(ctx);
1131 *pstatus = NT_STATUS_NOT_FOUND;
1132 return -1;
1136 * Trim pathname sent by client so it begins with only one backslash.
1137 * Two backslashes confuse some dfs clients
1140 local_dfs_path = talloc_strdup(ctx,dfs_path);
1141 if (!local_dfs_path) {
1142 *pstatus = NT_STATUS_NO_MEMORY;
1143 talloc_destroy(ctx);
1144 return -1;
1146 pathnamep = local_dfs_path;
1147 while (IS_DIRECTORY_SEP(pathnamep[0]) &&
1148 IS_DIRECTORY_SEP(pathnamep[1])) {
1149 pathnamep++;
1152 junction = TALLOC_ZERO_P(ctx, struct junction_map);
1153 if (!junction) {
1154 *pstatus = NT_STATUS_NO_MEMORY;
1155 talloc_destroy(ctx);
1156 return -1;
1159 /* The following call can change cwd. */
1160 *pstatus = get_referred_path(ctx, pathnamep, junction,
1161 &consumedcnt, &self_referral);
1162 if (!NT_STATUS_IS_OK(*pstatus)) {
1163 vfs_ChDir(orig_conn,orig_conn->connectpath);
1164 talloc_destroy(ctx);
1165 return -1;
1167 vfs_ChDir(orig_conn,orig_conn->connectpath);
1169 if (!self_referral) {
1170 pathnamep[consumedcnt] = '\0';
1172 if( DEBUGLVL( 3 ) ) {
1173 int i=0;
1174 dbgtext("setup_dfs_referral: Path %s to "
1175 "alternate path(s):",
1176 pathnamep);
1177 for(i=0;i<junction->referral_count;i++)
1178 dbgtext(" %s",
1179 junction->referral_list[i].alternate_path);
1180 dbgtext(".\n");
1184 /* create the referral depeding on version */
1185 DEBUG(10,("max_referral_level :%d\n",max_referral_level));
1187 if (max_referral_level < 2) {
1188 max_referral_level = 2;
1190 if (max_referral_level > 3) {
1191 max_referral_level = 3;
1194 switch(max_referral_level) {
1195 case 2:
1196 reply_size = setup_ver2_dfs_referral(pathnamep,
1197 ppdata, junction,
1198 consumedcnt, self_referral);
1199 break;
1200 case 3:
1201 reply_size = setup_ver3_dfs_referral(pathnamep, ppdata,
1202 junction, consumedcnt, self_referral);
1203 break;
1204 default:
1205 DEBUG(0,("setup_dfs_referral: Invalid dfs referral "
1206 "version: %d\n",
1207 max_referral_level));
1208 talloc_destroy(ctx);
1209 *pstatus = NT_STATUS_INVALID_LEVEL;
1210 return -1;
1213 if (DEBUGLVL(10)) {
1214 DEBUGADD(0,("DFS Referral pdata:\n"));
1215 dump_data(0,(uint8 *)*ppdata,reply_size);
1218 talloc_destroy(ctx);
1219 *pstatus = NT_STATUS_OK;
1220 return reply_size;
1223 /**********************************************************************
1224 The following functions are called by the NETDFS RPC pipe functions
1225 **********************************************************************/
1227 /*********************************************************************
1228 Creates a junction structure from a DFS pathname
1229 **********************************************************************/
1231 bool create_junction(TALLOC_CTX *ctx,
1232 const char *dfs_path,
1233 struct junction_map *jucn)
1235 int snum;
1236 bool dummy;
1237 struct dfs_path *pdp = TALLOC_P(ctx,struct dfs_path);
1238 NTSTATUS status;
1240 if (!pdp) {
1241 return False;
1243 status = parse_dfs_path(dfs_path, False, pdp, &dummy);
1244 if (!NT_STATUS_IS_OK(status)) {
1245 return False;
1248 /* check if path is dfs : validate first token */
1249 if (!is_myname_or_ipaddr(pdp->hostname)) {
1250 DEBUG(4,("create_junction: Invalid hostname %s "
1251 "in dfs path %s\n",
1252 pdp->hostname, dfs_path));
1253 TALLOC_FREE(pdp);
1254 return False;
1257 /* Check for a non-DFS share */
1258 snum = lp_servicenumber(pdp->servicename);
1260 if(snum < 0 || !lp_msdfs_root(snum)) {
1261 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1262 pdp->servicename));
1263 TALLOC_FREE(pdp);
1264 return False;
1267 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1268 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1269 jucn->comment = talloc_strdup(ctx, lp_comment(snum));
1271 TALLOC_FREE(pdp);
1272 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1273 return False;
1275 return True;
1278 /**********************************************************************
1279 Forms a valid Unix pathname from the junction
1280 **********************************************************************/
1282 static bool junction_to_local_path(const struct junction_map *jucn,
1283 char **pp_path_out,
1284 connection_struct *conn_out)
1286 int snum;
1288 snum = lp_servicenumber(jucn->service_name);
1289 if(snum < 0) {
1290 return False;
1292 if (!NT_STATUS_IS_OK(create_conn_struct(talloc_tos(),
1293 conn_out, snum,
1294 lp_pathname(snum)))) {
1295 return False;
1298 *pp_path_out = talloc_asprintf(conn_out->mem_ctx,
1299 "%s/%s",
1300 lp_pathname(snum),
1301 jucn->volume_name);
1302 if (!*pp_path_out) {
1303 return False;
1305 return True;
1308 bool create_msdfs_link(const struct junction_map *jucn,
1309 bool exists)
1311 char *path = NULL;
1312 char *msdfs_link = NULL;
1313 connection_struct conns;
1314 connection_struct *conn = &conns;
1315 int i=0;
1316 bool insert_comma = False;
1317 bool ret = False;
1319 ZERO_STRUCT(conns);
1321 if(!junction_to_local_path(jucn, &path, conn)) {
1322 return False;
1325 /* Form the msdfs_link contents */
1326 msdfs_link = talloc_strdup(conn->mem_ctx, "msdfs:");
1327 if (!msdfs_link) {
1328 goto out;
1330 for(i=0; i<jucn->referral_count; i++) {
1331 char *refpath = jucn->referral_list[i].alternate_path;
1333 /* Alternate paths always use Windows separators. */
1334 trim_char(refpath, '\\', '\\');
1335 if(*refpath == '\0') {
1336 if (i == 0) {
1337 insert_comma = False;
1339 continue;
1341 if (i > 0 && insert_comma) {
1342 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1343 ",%s",
1344 refpath);
1345 } else {
1346 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1347 "%s",
1348 refpath);
1351 if (!msdfs_link) {
1352 goto out;
1354 if (!insert_comma) {
1355 insert_comma = True;
1359 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1360 path, msdfs_link));
1362 if(exists) {
1363 if(SMB_VFS_UNLINK(conn,path)!=0) {
1364 goto out;
1368 if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1369 DEBUG(1,("create_msdfs_link: symlink failed "
1370 "%s -> %s\nError: %s\n",
1371 path, msdfs_link, strerror(errno)));
1372 goto out;
1375 ret = True;
1377 out:
1379 conn_free_internal(conn);
1380 return ret;
1383 bool remove_msdfs_link(const struct junction_map *jucn)
1385 char *path = NULL;
1386 connection_struct conns;
1387 connection_struct *conn = &conns;
1388 bool ret = False;
1390 ZERO_STRUCT(conns);
1392 if( junction_to_local_path(jucn, &path, conn) ) {
1393 if( SMB_VFS_UNLINK(conn, path) == 0 ) {
1394 ret = True;
1398 conn_free_internal(conn);
1399 return ret;
1402 /*********************************************************************
1403 Return the number of DFS links at the root of this share.
1404 *********************************************************************/
1406 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1408 size_t cnt = 0;
1409 SMB_STRUCT_DIR *dirp = NULL;
1410 char *dname = NULL;
1411 const char *connect_path = lp_pathname(snum);
1412 const char *msdfs_proxy = lp_msdfs_proxy(snum);
1413 connection_struct conn;
1415 ZERO_STRUCT(conn);
1417 if(*connect_path == '\0') {
1418 return 0;
1422 * Fake up a connection struct for the VFS layer.
1425 if (!NT_STATUS_IS_OK(create_conn_struct(talloc_tos(),
1426 &conn, snum, connect_path))) {
1427 return 0;
1430 /* Count a link for the msdfs root - convention */
1431 cnt = 1;
1433 /* No more links if this is an msdfs proxy. */
1434 if (*msdfs_proxy != '\0') {
1435 goto out;
1438 /* Now enumerate all dfs links */
1439 dirp = SMB_VFS_OPENDIR(&conn, ".", NULL, 0);
1440 if(!dirp) {
1441 goto out;
1444 while ((dname = vfs_readdirname(&conn, dirp)) != NULL) {
1445 if (is_msdfs_link(&conn,
1446 dname,
1447 NULL)) {
1448 cnt++;
1452 SMB_VFS_CLOSEDIR(&conn,dirp);
1454 out:
1456 conn_free_internal(&conn);
1457 return cnt;
1460 /*********************************************************************
1461 *********************************************************************/
1463 static int form_junctions(TALLOC_CTX *ctx,
1464 int snum,
1465 struct junction_map *jucn,
1466 size_t jn_remain)
1468 size_t cnt = 0;
1469 SMB_STRUCT_DIR *dirp = NULL;
1470 char *dname = NULL;
1471 const char *connect_path = lp_pathname(snum);
1472 char *service_name = lp_servicename(snum);
1473 const char *msdfs_proxy = lp_msdfs_proxy(snum);
1474 connection_struct conn;
1475 struct referral *ref = NULL;
1477 ZERO_STRUCT(conn);
1479 if (jn_remain == 0) {
1480 return 0;
1483 if(*connect_path == '\0') {
1484 return 0;
1488 * Fake up a connection struct for the VFS layer.
1491 if (!NT_STATUS_IS_OK(create_conn_struct(ctx, &conn, snum, connect_path))) {
1492 return 0;
1495 /* form a junction for the msdfs root - convention
1496 DO NOT REMOVE THIS: NT clients will not work with us
1497 if this is not present
1499 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1500 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1501 if (!jucn[cnt].service_name || jucn[cnt].volume_name) {
1502 goto out;
1504 jucn[cnt].referral_count = 1;
1506 ref = jucn[cnt].referral_list = TALLOC_ZERO_P(ctx, struct referral);
1507 if (jucn[cnt].referral_list == NULL) {
1508 goto out;
1511 ref->proximity = 0;
1512 ref->ttl = REFERRAL_TTL;
1513 if (*msdfs_proxy != '\0') {
1514 ref->alternate_path = talloc_strdup(ctx,
1515 msdfs_proxy);
1516 } else {
1517 ref->alternate_path = talloc_asprintf(ctx,
1518 "\\\\%s\\%s",
1519 get_local_machine_name(),
1520 service_name);
1523 if (!ref->alternate_path) {
1524 goto out;
1526 cnt++;
1528 /* Don't enumerate if we're an msdfs proxy. */
1529 if (*msdfs_proxy != '\0') {
1530 goto out;
1533 /* Now enumerate all dfs links */
1534 dirp = SMB_VFS_OPENDIR(&conn, ".", NULL, 0);
1535 if(!dirp) {
1536 goto out;
1539 while ((dname = vfs_readdirname(&conn, dirp)) != NULL) {
1540 char *link_target = NULL;
1541 if (cnt >= jn_remain) {
1542 SMB_VFS_CLOSEDIR(&conn,dirp);
1543 DEBUG(2, ("form_junctions: ran out of MSDFS "
1544 "junction slots"));
1545 goto out;
1547 if (is_msdfs_link_internal(ctx,
1548 &conn,
1549 dname, &link_target,
1550 NULL)) {
1551 if (parse_msdfs_symlink(ctx,
1552 link_target,
1553 &jucn[cnt].referral_list,
1554 &jucn[cnt].referral_count)) {
1556 jucn[cnt].service_name = talloc_strdup(ctx,
1557 service_name);
1558 jucn[cnt].volume_name = talloc_strdup(ctx,
1559 dname);
1560 if (!jucn[cnt].service_name ||
1561 !jucn[cnt].volume_name) {
1562 goto out;
1564 cnt++;
1569 out:
1571 if (dirp) {
1572 SMB_VFS_CLOSEDIR(&conn,dirp);
1575 conn_free_internal(&conn);
1576 return cnt;
1579 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1581 struct junction_map *jn = NULL;
1582 int i=0;
1583 size_t jn_count = 0;
1584 int sharecount = 0;
1586 *p_num_jn = 0;
1587 if(!lp_host_msdfs()) {
1588 return NULL;
1591 /* Ensure all the usershares are loaded. */
1592 become_root();
1593 load_registry_shares();
1594 sharecount = load_usershare_shares();
1595 unbecome_root();
1597 for(i=0;i < sharecount;i++) {
1598 if(lp_msdfs_root(i)) {
1599 jn_count += count_dfs_links(ctx, i);
1602 if (jn_count == 0) {
1603 return NULL;
1605 jn = TALLOC_ARRAY(ctx, struct junction_map, jn_count);
1606 if (!jn) {
1607 return NULL;
1609 for(i=0; i < sharecount; i++) {
1610 if (*p_num_jn >= jn_count) {
1611 break;
1613 if(lp_msdfs_root(i)) {
1614 *p_num_jn += form_junctions(ctx, i,
1615 &jn[*p_num_jn],
1616 jn_count - *p_num_jn);
1619 return jn;
1622 /******************************************************************************
1623 Core function to resolve a dfs pathname.
1624 ******************************************************************************/
1626 NTSTATUS resolve_dfspath(TALLOC_CTX *ctx,
1627 connection_struct *conn,
1628 bool dfs_pathnames,
1629 const char *name_in,
1630 char **pp_name_out)
1632 NTSTATUS status = NT_STATUS_OK;
1633 bool dummy;
1634 if (dfs_pathnames) {
1635 status = dfs_redirect(ctx,
1636 conn,
1637 name_in,
1638 False,
1639 pp_name_out,
1640 &dummy);
1641 } else {
1643 * Cheat and just return a copy of the in ptr.
1644 * Once srvstr_get_path() uses talloc it'll
1645 * be a talloced ptr anyway.
1647 *pp_name_out = CONST_DISCARD(char *,name_in);
1649 return status;
1652 /******************************************************************************
1653 Core function to resolve a dfs pathname possibly containing a wildcard.
1654 This function is identical to the above except for the bool param to
1655 dfs_redirect but I need this to be separate so it's really clear when
1656 we're allowing wildcards and when we're not. JRA.
1657 ******************************************************************************/
1659 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1660 connection_struct *conn,
1661 bool dfs_pathnames,
1662 const char *name_in,
1663 char **pp_name_out,
1664 bool *ppath_contains_wcard)
1666 NTSTATUS status = NT_STATUS_OK;
1667 if (dfs_pathnames) {
1668 status = dfs_redirect(ctx,
1669 conn,
1670 name_in,
1671 True,
1672 pp_name_out,
1673 ppath_contains_wcard);
1674 } else {
1676 * Cheat and just return a copy of the in ptr.
1677 * Once srvstr_get_path() uses talloc it'll
1678 * be a talloced ptr anyway.
1680 *pp_name_out = CONST_DISCARD(char *,name_in);
1682 return status;