build: autogenerate exports/libnetapi.syms
[Samba.git] / source / smbd / msdfs.c
blobf0dd900be8dddc54323225b959e4d2fab50c4387
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 *conn,
220 int snum,
221 const char *path)
223 char *connpath;
225 ZERO_STRUCTP(conn);
227 connpath = talloc_strdup(ctx, path);
228 if (!connpath) {
229 return NT_STATUS_NO_MEMORY;
231 connpath = talloc_string_sub(ctx,
232 connpath,
233 "%S",
234 lp_servicename(snum));
235 if (!connpath) {
236 return NT_STATUS_NO_MEMORY;
239 /* needed for smbd_vfs_init() */
241 if ((conn->mem_ctx=talloc_init("connection_struct")) == NULL) {
242 DEBUG(0,("talloc_init(connection_struct) failed!\n"));
243 return NT_STATUS_NO_MEMORY;
246 if (!(conn->params = TALLOC_ZERO_P(conn->mem_ctx,
247 struct share_params))) {
248 DEBUG(0, ("TALLOC failed\n"));
249 return NT_STATUS_NO_MEMORY;
252 conn->params->service = snum;
254 set_conn_connectpath(conn, connpath);
256 if (!smbd_vfs_init(conn)) {
257 NTSTATUS status = map_nt_error_from_unix(errno);
258 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
259 conn_free_internal(conn);
260 return status;
264 * Windows seems to insist on doing trans2getdfsreferral() calls on
265 * the IPC$ share as the anonymous user. If we try to chdir as that
266 * user we will fail.... WTF ? JRA.
269 if (vfs_ChDir(conn,conn->connectpath) != 0) {
270 NTSTATUS status = map_nt_error_from_unix(errno);
271 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
272 "Error was %s\n",
273 conn->connectpath, strerror(errno) ));
274 conn_free_internal(conn);
275 return status;
278 return NT_STATUS_OK;
281 /**********************************************************************
282 Parse the contents of a symlink to verify if it is an msdfs referral
283 A valid referral is of the form:
285 msdfs:server1\share1,server2\share2
286 msdfs:server1\share1\pathname,server2\share2\pathname
287 msdfs:server1/share1,server2/share2
288 msdfs:server1/share1/pathname,server2/share2/pathname.
290 Note that the alternate paths returned here must be of the canonicalized
291 form:
293 \server\share or
294 \server\share\path\to\file,
296 even in posix path mode. This is because we have no knowledge if the
297 server we're referring to understands posix paths.
298 **********************************************************************/
300 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
301 const char *target,
302 struct referral **preflist,
303 int *refcount)
305 char *temp = NULL;
306 char *prot;
307 char **alt_path = NULL;
308 int count = 0, i;
309 struct referral *reflist;
310 char *saveptr;
312 temp = talloc_strdup(ctx, target);
313 if (!temp) {
314 return False;
316 prot = strtok_r(temp, ":", &saveptr);
317 if (!prot) {
318 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
319 return False;
322 alt_path = TALLOC_ARRAY(ctx, char *, MAX_REFERRAL_COUNT);
323 if (!alt_path) {
324 return False;
327 /* parse out the alternate paths */
328 while((count<MAX_REFERRAL_COUNT) &&
329 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
330 count++;
333 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
335 if (count) {
336 reflist = *preflist = TALLOC_ZERO_ARRAY(ctx,
337 struct referral, count);
338 if(reflist == NULL) {
339 TALLOC_FREE(alt_path);
340 return False;
342 } else {
343 reflist = *preflist = NULL;
346 for(i=0;i<count;i++) {
347 char *p;
349 /* Canonicalize link target.
350 * Replace all /'s in the path by a \ */
351 string_replace(alt_path[i], '/', '\\');
353 /* Remove leading '\\'s */
354 p = alt_path[i];
355 while (*p && (*p == '\\')) {
356 p++;
359 reflist[i].alternate_path = talloc_asprintf(ctx,
360 "\\%s",
362 if (!reflist[i].alternate_path) {
363 return False;
366 reflist[i].proximity = 0;
367 reflist[i].ttl = REFERRAL_TTL;
368 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
369 reflist[i].alternate_path));
370 *refcount += 1;
373 TALLOC_FREE(alt_path);
374 return True;
377 /**********************************************************************
378 Returns true if the unix path is a valid msdfs symlink and also
379 returns the target string from inside the link.
380 **********************************************************************/
382 static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
383 connection_struct *conn,
384 const char *path,
385 char **pp_link_target,
386 SMB_STRUCT_STAT *sbufp)
388 SMB_STRUCT_STAT st;
389 int referral_len = 0;
390 char link_target_buf[7];
391 size_t bufsize = 0;
392 char *link_target = NULL;
394 if (pp_link_target) {
395 bufsize = 1024;
396 link_target = TALLOC_ARRAY(ctx, char, bufsize);
397 if (!link_target) {
398 return False;
400 *pp_link_target = link_target;
401 } else {
402 bufsize = sizeof(link_target_buf);
403 link_target = link_target_buf;
406 if (sbufp == NULL) {
407 sbufp = &st;
410 if (SMB_VFS_LSTAT(conn, path, sbufp) != 0) {
411 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
412 path));
413 goto err;
416 if (!S_ISLNK(sbufp->st_mode)) {
417 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
418 path));
419 goto err;
422 referral_len = SMB_VFS_READLINK(conn, path, link_target, bufsize - 1);
423 if (referral_len == -1) {
424 DEBUG(0,("is_msdfs_link_read_target: Error reading "
425 "msdfs link %s: %s\n",
426 path, strerror(errno)));
427 goto err;
429 link_target[referral_len] = '\0';
431 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path,
432 link_target));
434 if (!strnequal(link_target, "msdfs:", 6)) {
435 goto err;
437 return True;
439 err:
441 if (link_target != link_target_buf) {
442 TALLOC_FREE(link_target);
444 return False;
447 /**********************************************************************
448 Returns true if the unix path is a valid msdfs symlink.
449 **********************************************************************/
451 bool is_msdfs_link(connection_struct *conn,
452 const char *path,
453 SMB_STRUCT_STAT *sbufp)
455 return is_msdfs_link_internal(talloc_tos(),
456 conn,
457 path,
458 NULL,
459 sbufp);
462 /*****************************************************************
463 Used by other functions to decide if a dfs path is remote,
464 and to get the list of referred locations for that remote path.
466 search_flag: For findfirsts, dfs links themselves are not
467 redirected, but paths beyond the links are. For normal smb calls,
468 even dfs links need to be redirected.
470 consumedcntp: how much of the dfs path is being redirected. the client
471 should try the remaining path on the redirected server.
473 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
474 link redirect are in targetpath.
475 *****************************************************************/
477 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
478 connection_struct *conn,
479 const char *dfspath, /* Incoming complete dfs path */
480 const struct dfs_path *pdp, /* Parsed out
481 server+share+extrapath. */
482 bool search_flag, /* Called from a findfirst ? */
483 int *consumedcntp,
484 char **pp_targetpath)
486 char *p = NULL;
487 char *q = NULL;
488 SMB_STRUCT_STAT sbuf;
489 NTSTATUS status;
490 char *localpath = NULL;
491 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
492 components). */
494 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
495 conn->connectpath, pdp->reqpath));
498 * Note the unix path conversion here we're doing we can
499 * throw away. We're looking for a symlink for a dfs
500 * resolution, if we don't find it we'll do another
501 * unix_convert later in the codepath.
502 * If we needed to remember what we'd resolved in
503 * dp->reqpath (as the original code did) we'd
504 * copy (localhost, dp->reqpath) on any code
505 * path below that returns True - but I don't
506 * think this is needed. JRA.
509 status = unix_convert(ctx, conn, pdp->reqpath, search_flag, &localpath,
510 NULL, &sbuf);
511 if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status,
512 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
513 return status;
516 /* Optimization - check if we can redirect the whole path. */
518 if (is_msdfs_link_internal(ctx, conn, localpath, pp_targetpath, NULL)) {
519 if (search_flag) {
520 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
521 "for dfs link %s.\n", dfspath));
522 return NT_STATUS_OK;
525 DEBUG(6,("dfs_path_lookup: %s resolves to a "
526 "valid dfs link %s.\n", dfspath,
527 pp_targetpath ? *pp_targetpath : ""));
529 if (consumedcntp) {
530 *consumedcntp = strlen(dfspath);
532 return NT_STATUS_PATH_NOT_COVERED;
535 /* Prepare to test only for '/' components in the given path,
536 * so if a Windows path replace all '\\' characters with '/'.
537 * For a POSIX DFS path we know all separators are already '/'. */
539 canon_dfspath = talloc_strdup(ctx, dfspath);
540 if (!canon_dfspath) {
541 return NT_STATUS_NO_MEMORY;
543 if (!pdp->posix_path) {
544 string_replace(canon_dfspath, '\\', '/');
548 * localpath comes out of unix_convert, so it has
549 * no trailing backslash. Make sure that canon_dfspath hasn't either.
550 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
553 trim_char(canon_dfspath,0,'/');
556 * Redirect if any component in the path is a link.
557 * We do this by walking backwards through the
558 * local path, chopping off the last component
559 * in both the local path and the canonicalized
560 * DFS path. If we hit a DFS link then we're done.
563 p = strrchr_m(localpath, '/');
564 if (consumedcntp) {
565 q = strrchr_m(canon_dfspath, '/');
568 while (p) {
569 *p = '\0';
570 if (q) {
571 *q = '\0';
574 if (is_msdfs_link_internal(ctx, conn,
575 localpath, pp_targetpath, NULL)) {
576 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
577 "parent %s is dfs link\n", dfspath, localpath));
579 if (consumedcntp) {
580 *consumedcntp = strlen(canon_dfspath);
581 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
582 "(%d)\n",
583 canon_dfspath,
584 *consumedcntp));
587 return NT_STATUS_PATH_NOT_COVERED;
590 /* Step back on the filesystem. */
591 p = strrchr_m(localpath, '/');
593 if (consumedcntp) {
594 /* And in the canonicalized dfs path. */
595 q = strrchr_m(canon_dfspath, '/');
599 return NT_STATUS_OK;
602 /*****************************************************************
603 Decides if a dfs pathname should be redirected or not.
604 If not, the pathname is converted to a tcon-relative local unix path
606 search_wcard_flag: this flag performs 2 functions both related
607 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
608 for details.
610 This function can return NT_STATUS_OK, meaning use the returned path as-is
611 (mapped into a local path).
612 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
613 any other NT_STATUS error which is a genuine error to be
614 returned to the client.
615 *****************************************************************/
617 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
618 connection_struct *conn,
619 const char *path_in,
620 bool search_wcard_flag,
621 char **pp_path_out,
622 bool *ppath_contains_wcard)
624 NTSTATUS status;
625 struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
627 if (!pdp) {
628 return NT_STATUS_NO_MEMORY;
631 status = parse_dfs_path(conn, path_in, search_wcard_flag, pdp,
632 ppath_contains_wcard);
633 if (!NT_STATUS_IS_OK(status)) {
634 TALLOC_FREE(pdp);
635 return status;
638 if (pdp->reqpath[0] == '\0') {
639 TALLOC_FREE(pdp);
640 *pp_path_out = talloc_strdup(ctx, "");
641 if (!*pp_path_out) {
642 return NT_STATUS_NO_MEMORY;
644 DEBUG(5,("dfs_redirect: self-referral.\n"));
645 return NT_STATUS_OK;
648 /* If dfs pathname for a non-dfs share, convert to tcon-relative
649 path and return OK */
651 if (!lp_msdfs_root(SNUM(conn))) {
652 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
653 TALLOC_FREE(pdp);
654 if (!*pp_path_out) {
655 return NT_STATUS_NO_MEMORY;
657 return NT_STATUS_OK;
660 /* If it looked like a local path (zero hostname/servicename)
661 * just treat as a tcon-relative path. */
663 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
664 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
665 TALLOC_FREE(pdp);
666 if (!*pp_path_out) {
667 return NT_STATUS_NO_MEMORY;
669 return NT_STATUS_OK;
672 status = dfs_path_lookup(ctx, conn, path_in, pdp,
673 search_wcard_flag, NULL, NULL);
674 if (!NT_STATUS_IS_OK(status)) {
675 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
676 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
677 } else {
678 DEBUG(10,("dfs_redirect: dfs_path_lookup "
679 "failed for %s with %s\n",
680 path_in, nt_errstr(status) ));
682 return status;
685 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
687 /* Form non-dfs tcon-relative path */
688 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
689 TALLOC_FREE(pdp);
690 if (!*pp_path_out) {
691 return NT_STATUS_NO_MEMORY;
694 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
695 path_in,
696 *pp_path_out));
698 return NT_STATUS_OK;
701 /**********************************************************************
702 Return a self referral.
703 **********************************************************************/
705 static NTSTATUS self_ref(TALLOC_CTX *ctx,
706 const char *dfs_path,
707 struct junction_map *jucn,
708 int *consumedcntp,
709 bool *self_referralp)
711 struct referral *ref;
713 *self_referralp = True;
715 jucn->referral_count = 1;
716 if((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
717 return NT_STATUS_NO_MEMORY;
720 ref->alternate_path = talloc_strdup(ctx, dfs_path);
721 if (!ref->alternate_path) {
722 return NT_STATUS_NO_MEMORY;
724 ref->proximity = 0;
725 ref->ttl = REFERRAL_TTL;
726 jucn->referral_list = ref;
727 *consumedcntp = strlen(dfs_path);
728 return NT_STATUS_OK;
731 /**********************************************************************
732 Gets valid referrals for a dfs path and fills up the
733 junction_map structure.
734 **********************************************************************/
736 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
737 const char *dfs_path,
738 struct junction_map *jucn,
739 int *consumedcntp,
740 bool *self_referralp)
742 struct connection_struct conns;
743 struct connection_struct *conn = &conns;
744 char *targetpath = NULL;
745 int snum;
746 NTSTATUS status = NT_STATUS_NOT_FOUND;
747 bool dummy;
748 struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
750 if (!pdp) {
751 return NT_STATUS_NO_MEMORY;
754 ZERO_STRUCT(conns);
755 *self_referralp = False;
757 status = parse_dfs_path(NULL, dfs_path, False, pdp, &dummy);
758 if (!NT_STATUS_IS_OK(status)) {
759 return status;
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(NULL, 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;