Fix bug 6382: Case insensitive access to DFS links broken
[Samba.git] / source / smbd / msdfs.c
blob184967c1077d4876038d3d3468bcf7d1c2dc6559
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;
263 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn);
266 * Windows seems to insist on doing trans2getdfsreferral() calls on
267 * the IPC$ share as the anonymous user. If we try to chdir as that
268 * user we will fail.... WTF ? JRA.
271 if (vfs_ChDir(conn,conn->connectpath) != 0) {
272 NTSTATUS status = map_nt_error_from_unix(errno);
273 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
274 "Error was %s\n",
275 conn->connectpath, strerror(errno) ));
276 conn_free_internal(conn);
277 return status;
280 return NT_STATUS_OK;
283 /**********************************************************************
284 Parse the contents of a symlink to verify if it is an msdfs referral
285 A valid referral is of the form:
287 msdfs:server1\share1,server2\share2
288 msdfs:server1\share1\pathname,server2\share2\pathname
289 msdfs:server1/share1,server2/share2
290 msdfs:server1/share1/pathname,server2/share2/pathname.
292 Note that the alternate paths returned here must be of the canonicalized
293 form:
295 \server\share or
296 \server\share\path\to\file,
298 even in posix path mode. This is because we have no knowledge if the
299 server we're referring to understands posix paths.
300 **********************************************************************/
302 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
303 const char *target,
304 struct referral **preflist,
305 int *refcount)
307 char *temp = NULL;
308 char *prot;
309 char **alt_path = NULL;
310 int count = 0, i;
311 struct referral *reflist;
312 char *saveptr;
314 temp = talloc_strdup(ctx, target);
315 if (!temp) {
316 return False;
318 prot = strtok_r(temp, ":", &saveptr);
319 if (!prot) {
320 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
321 return False;
324 alt_path = TALLOC_ARRAY(ctx, char *, MAX_REFERRAL_COUNT);
325 if (!alt_path) {
326 return False;
329 /* parse out the alternate paths */
330 while((count<MAX_REFERRAL_COUNT) &&
331 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
332 count++;
335 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
337 if (count) {
338 reflist = *preflist = TALLOC_ZERO_ARRAY(ctx,
339 struct referral, count);
340 if(reflist == NULL) {
341 TALLOC_FREE(alt_path);
342 return False;
344 } else {
345 reflist = *preflist = NULL;
348 for(i=0;i<count;i++) {
349 char *p;
351 /* Canonicalize link target.
352 * Replace all /'s in the path by a \ */
353 string_replace(alt_path[i], '/', '\\');
355 /* Remove leading '\\'s */
356 p = alt_path[i];
357 while (*p && (*p == '\\')) {
358 p++;
361 reflist[i].alternate_path = talloc_asprintf(ctx,
362 "\\%s",
364 if (!reflist[i].alternate_path) {
365 return False;
368 reflist[i].proximity = 0;
369 reflist[i].ttl = REFERRAL_TTL;
370 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
371 reflist[i].alternate_path));
374 *refcount = count;
376 TALLOC_FREE(alt_path);
377 return True;
380 /**********************************************************************
381 Returns true if the unix path is a valid msdfs symlink and also
382 returns the target string from inside the link.
383 **********************************************************************/
385 static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
386 connection_struct *conn,
387 const char *path,
388 char **pp_link_target,
389 SMB_STRUCT_STAT *sbufp)
391 SMB_STRUCT_STAT st;
392 int referral_len = 0;
393 char link_target_buf[7];
394 size_t bufsize = 0;
395 char *link_target = NULL;
397 if (pp_link_target) {
398 bufsize = 1024;
399 link_target = TALLOC_ARRAY(ctx, char, bufsize);
400 if (!link_target) {
401 return False;
403 *pp_link_target = link_target;
404 } else {
405 bufsize = sizeof(link_target_buf);
406 link_target = link_target_buf;
409 if (sbufp == NULL) {
410 sbufp = &st;
413 if (SMB_VFS_LSTAT(conn, path, sbufp) != 0) {
414 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
415 path));
416 goto err;
419 if (!S_ISLNK(sbufp->st_mode)) {
420 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
421 path));
422 goto err;
425 referral_len = SMB_VFS_READLINK(conn, path, link_target, bufsize - 1);
426 if (referral_len == -1) {
427 DEBUG(0,("is_msdfs_link_read_target: Error reading "
428 "msdfs link %s: %s\n",
429 path, strerror(errno)));
430 goto err;
432 link_target[referral_len] = '\0';
434 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path,
435 link_target));
437 if (!strnequal(link_target, "msdfs:", 6)) {
438 goto err;
440 return True;
442 err:
444 if (link_target != link_target_buf) {
445 TALLOC_FREE(link_target);
447 return False;
450 /**********************************************************************
451 Returns true if the unix path is a valid msdfs symlink.
452 **********************************************************************/
454 bool is_msdfs_link(connection_struct *conn,
455 const char *path,
456 SMB_STRUCT_STAT *sbufp)
458 return is_msdfs_link_internal(talloc_tos(),
459 conn,
460 path,
461 NULL,
462 sbufp);
465 /*****************************************************************
466 Used by other functions to decide if a dfs path is remote,
467 and to get the list of referred locations for that remote path.
469 search_flag: For findfirsts, dfs links themselves are not
470 redirected, but paths beyond the links are. For normal smb calls,
471 even dfs links need to be redirected.
473 consumedcntp: how much of the dfs path is being redirected. the client
474 should try the remaining path on the redirected server.
476 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
477 link redirect are in targetpath.
478 *****************************************************************/
480 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
481 connection_struct *conn,
482 const char *dfspath, /* Incoming complete dfs path */
483 const struct dfs_path *pdp, /* Parsed out
484 server+share+extrapath. */
485 bool search_flag, /* Called from a findfirst ? */
486 int *consumedcntp,
487 char **pp_targetpath)
489 char *p = NULL;
490 char *q = NULL;
491 SMB_STRUCT_STAT sbuf;
492 NTSTATUS status;
493 char *localpath = NULL;
494 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
495 components). */
497 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
498 conn->connectpath, pdp->reqpath));
501 * Note the unix path conversion here we're doing we can
502 * throw away. We're looking for a symlink for a dfs
503 * resolution, if we don't find it we'll do another
504 * unix_convert later in the codepath.
505 * If we needed to remember what we'd resolved in
506 * dp->reqpath (as the original code did) we'd
507 * copy (localhost, dp->reqpath) on any code
508 * path below that returns True - but I don't
509 * think this is needed. JRA.
512 status = unix_convert(ctx, conn, pdp->reqpath, search_flag, &localpath,
513 NULL, &sbuf);
514 if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status,
515 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
516 return status;
519 /* Optimization - check if we can redirect the whole path. */
521 if (is_msdfs_link_internal(ctx, conn, localpath, pp_targetpath, NULL)) {
522 if (search_flag) {
523 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
524 "for dfs link %s.\n", dfspath));
525 return NT_STATUS_OK;
528 DEBUG(6,("dfs_path_lookup: %s resolves to a "
529 "valid dfs link %s.\n", dfspath,
530 pp_targetpath ? *pp_targetpath : ""));
532 if (consumedcntp) {
533 *consumedcntp = strlen(dfspath);
535 return NT_STATUS_PATH_NOT_COVERED;
538 /* Prepare to test only for '/' components in the given path,
539 * so if a Windows path replace all '\\' characters with '/'.
540 * For a POSIX DFS path we know all separators are already '/'. */
542 canon_dfspath = talloc_strdup(ctx, dfspath);
543 if (!canon_dfspath) {
544 return NT_STATUS_NO_MEMORY;
546 if (!pdp->posix_path) {
547 string_replace(canon_dfspath, '\\', '/');
551 * localpath comes out of unix_convert, so it has
552 * no trailing backslash. Make sure that canon_dfspath hasn't either.
553 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
556 trim_char(canon_dfspath,0,'/');
559 * Redirect if any component in the path is a link.
560 * We do this by walking backwards through the
561 * local path, chopping off the last component
562 * in both the local path and the canonicalized
563 * DFS path. If we hit a DFS link then we're done.
566 p = strrchr_m(localpath, '/');
567 if (consumedcntp) {
568 q = strrchr_m(canon_dfspath, '/');
571 while (p) {
572 *p = '\0';
573 if (q) {
574 *q = '\0';
577 if (is_msdfs_link_internal(ctx, conn,
578 localpath, pp_targetpath, NULL)) {
579 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
580 "parent %s is dfs link\n", dfspath, localpath));
582 if (consumedcntp) {
583 *consumedcntp = strlen(canon_dfspath);
584 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
585 "(%d)\n",
586 canon_dfspath,
587 *consumedcntp));
590 return NT_STATUS_PATH_NOT_COVERED;
593 /* Step back on the filesystem. */
594 p = strrchr_m(localpath, '/');
596 if (consumedcntp) {
597 /* And in the canonicalized dfs path. */
598 q = strrchr_m(canon_dfspath, '/');
602 return NT_STATUS_OK;
605 /*****************************************************************
606 Decides if a dfs pathname should be redirected or not.
607 If not, the pathname is converted to a tcon-relative local unix path
609 search_wcard_flag: this flag performs 2 functions both related
610 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
611 for details.
613 This function can return NT_STATUS_OK, meaning use the returned path as-is
614 (mapped into a local path).
615 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
616 any other NT_STATUS error which is a genuine error to be
617 returned to the client.
618 *****************************************************************/
620 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
621 connection_struct *conn,
622 const char *path_in,
623 bool search_wcard_flag,
624 char **pp_path_out,
625 bool *ppath_contains_wcard)
627 NTSTATUS status;
628 struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
630 if (!pdp) {
631 return NT_STATUS_NO_MEMORY;
634 status = parse_dfs_path(conn, path_in, search_wcard_flag, pdp,
635 ppath_contains_wcard);
636 if (!NT_STATUS_IS_OK(status)) {
637 TALLOC_FREE(pdp);
638 return status;
641 if (pdp->reqpath[0] == '\0') {
642 TALLOC_FREE(pdp);
643 *pp_path_out = talloc_strdup(ctx, "");
644 if (!*pp_path_out) {
645 return NT_STATUS_NO_MEMORY;
647 DEBUG(5,("dfs_redirect: self-referral.\n"));
648 return NT_STATUS_OK;
651 /* If dfs pathname for a non-dfs share, convert to tcon-relative
652 path and return OK */
654 if (!lp_msdfs_root(SNUM(conn))) {
655 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
656 TALLOC_FREE(pdp);
657 if (!*pp_path_out) {
658 return NT_STATUS_NO_MEMORY;
660 return NT_STATUS_OK;
663 /* If it looked like a local path (zero hostname/servicename)
664 * just treat as a tcon-relative path. */
666 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
667 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
668 TALLOC_FREE(pdp);
669 if (!*pp_path_out) {
670 return NT_STATUS_NO_MEMORY;
672 return NT_STATUS_OK;
675 status = dfs_path_lookup(ctx, conn, path_in, pdp,
676 search_wcard_flag, NULL, NULL);
677 if (!NT_STATUS_IS_OK(status)) {
678 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
679 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
680 } else {
681 DEBUG(10,("dfs_redirect: dfs_path_lookup "
682 "failed for %s with %s\n",
683 path_in, nt_errstr(status) ));
685 return status;
688 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
690 /* Form non-dfs tcon-relative path */
691 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
692 TALLOC_FREE(pdp);
693 if (!*pp_path_out) {
694 return NT_STATUS_NO_MEMORY;
697 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
698 path_in,
699 *pp_path_out));
701 return NT_STATUS_OK;
704 /**********************************************************************
705 Return a self referral.
706 **********************************************************************/
708 static NTSTATUS self_ref(TALLOC_CTX *ctx,
709 const char *dfs_path,
710 struct junction_map *jucn,
711 int *consumedcntp,
712 bool *self_referralp)
714 struct referral *ref;
716 *self_referralp = True;
718 jucn->referral_count = 1;
719 if((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
720 return NT_STATUS_NO_MEMORY;
723 ref->alternate_path = talloc_strdup(ctx, dfs_path);
724 if (!ref->alternate_path) {
725 return NT_STATUS_NO_MEMORY;
727 ref->proximity = 0;
728 ref->ttl = REFERRAL_TTL;
729 jucn->referral_list = ref;
730 *consumedcntp = strlen(dfs_path);
731 return NT_STATUS_OK;
734 /**********************************************************************
735 Gets valid referrals for a dfs path and fills up the
736 junction_map structure.
737 **********************************************************************/
739 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
740 const char *dfs_path,
741 struct junction_map *jucn,
742 int *consumedcntp,
743 bool *self_referralp)
745 struct connection_struct conns;
746 struct connection_struct *conn = &conns;
747 char *targetpath = NULL;
748 int snum;
749 NTSTATUS status = NT_STATUS_NOT_FOUND;
750 bool dummy;
751 struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
753 if (!pdp) {
754 return NT_STATUS_NO_MEMORY;
757 ZERO_STRUCT(conns);
758 *self_referralp = False;
760 status = parse_dfs_path(NULL, dfs_path, False, pdp, &dummy);
761 if (!NT_STATUS_IS_OK(status)) {
762 return status;
765 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
766 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
767 if (!jucn->service_name || !jucn->volume_name) {
768 TALLOC_FREE(pdp);
769 return NT_STATUS_NO_MEMORY;
772 /* Verify the share is a dfs root */
773 snum = lp_servicenumber(jucn->service_name);
774 if(snum < 0) {
775 fstring service_name;
776 fstrcpy(service_name, jucn->service_name);
777 if ((snum = find_service(service_name)) < 0) {
778 return NT_STATUS_NOT_FOUND;
780 TALLOC_FREE(jucn->service_name);
781 jucn->service_name = talloc_strdup(ctx, service_name);
782 if (!jucn->service_name) {
783 TALLOC_FREE(pdp);
784 return NT_STATUS_NO_MEMORY;
788 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(snum) == '\0')) {
789 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
790 "a dfs root.\n",
791 pdp->servicename, dfs_path));
792 TALLOC_FREE(pdp);
793 return NT_STATUS_NOT_FOUND;
797 * Self referrals are tested with a anonymous IPC connection and
798 * a GET_DFS_REFERRAL call to \\server\share. (which means
799 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
800 * into the directory and will fail if it cannot (as the anonymous
801 * user). Cope with this.
804 if (pdp->reqpath[0] == '\0') {
805 char *tmp;
806 struct referral *ref;
808 if (*lp_msdfs_proxy(snum) == '\0') {
809 TALLOC_FREE(pdp);
810 return self_ref(ctx,
811 dfs_path,
812 jucn,
813 consumedcntp,
814 self_referralp);
818 * It's an msdfs proxy share. Redirect to
819 * the configured target share.
822 jucn->referral_count = 1;
823 if ((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
824 TALLOC_FREE(pdp);
825 return NT_STATUS_NO_MEMORY;
828 if (!(tmp = talloc_strdup(ctx, lp_msdfs_proxy(snum)))) {
829 TALLOC_FREE(pdp);
830 return NT_STATUS_NO_MEMORY;
833 trim_string(tmp, "\\", 0);
835 ref->alternate_path = talloc_asprintf(ctx, "\\%s", tmp);
836 TALLOC_FREE(tmp);
838 if (!ref->alternate_path) {
839 TALLOC_FREE(pdp);
840 return NT_STATUS_NO_MEMORY;
843 if (pdp->reqpath[0] != '\0') {
844 ref->alternate_path = talloc_asprintf_append(
845 ref->alternate_path,
846 "%s",
847 pdp->reqpath);
848 if (!ref->alternate_path) {
849 TALLOC_FREE(pdp);
850 return NT_STATUS_NO_MEMORY;
853 ref->proximity = 0;
854 ref->ttl = REFERRAL_TTL;
855 jucn->referral_list = ref;
856 *consumedcntp = strlen(dfs_path);
857 TALLOC_FREE(pdp);
858 return NT_STATUS_OK;
861 status = create_conn_struct(ctx, conn, snum, lp_pathname(snum));
862 if (!NT_STATUS_IS_OK(status)) {
863 TALLOC_FREE(pdp);
864 return status;
867 /* If this is a DFS path dfs_lookup should return
868 * NT_STATUS_PATH_NOT_COVERED. */
870 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
871 False, consumedcntp, &targetpath);
873 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
874 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
875 dfs_path));
876 conn_free_internal(conn);
877 TALLOC_FREE(pdp);
878 return status;
881 /* We know this is a valid dfs link. Parse the targetpath. */
882 if (!parse_msdfs_symlink(ctx, targetpath,
883 &jucn->referral_list,
884 &jucn->referral_count)) {
885 DEBUG(3,("get_referred_path: failed to parse symlink "
886 "target %s\n", targetpath ));
887 conn_free_internal(conn);
888 TALLOC_FREE(pdp);
889 return NT_STATUS_NOT_FOUND;
892 conn_free_internal(conn);
893 TALLOC_FREE(pdp);
894 return NT_STATUS_OK;
897 static int setup_ver2_dfs_referral(const char *pathname,
898 char **ppdata,
899 struct junction_map *junction,
900 bool self_referral)
902 char* pdata = *ppdata;
904 smb_ucs2_t *uni_requestedpath = NULL;
905 int uni_reqpathoffset1,uni_reqpathoffset2;
906 int uni_curroffset;
907 int requestedpathlen=0;
908 int offset;
909 int reply_size = 0;
910 int i=0;
912 DEBUG(10,("Setting up version2 referral\nRequested path:\n"));
914 requestedpathlen = rpcstr_push_talloc(talloc_tos(),
915 &uni_requestedpath, pathname);
916 if (uni_requestedpath == NULL || requestedpathlen == 0) {
917 return -1;
920 if (DEBUGLVL(10)) {
921 dump_data(0, (unsigned char *)uni_requestedpath,
922 requestedpathlen);
925 DEBUG(10,("ref count = %u\n",junction->referral_count));
927 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
928 VERSION2_REFERRAL_SIZE * junction->referral_count;
930 uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen;
932 uni_curroffset = uni_reqpathoffset2 + requestedpathlen;
934 reply_size = REFERRAL_HEADER_SIZE +
935 VERSION2_REFERRAL_SIZE*junction->referral_count +
936 2 * requestedpathlen;
937 DEBUG(10,("reply_size: %u\n",reply_size));
939 /* add up the unicode lengths of all the referral paths */
940 for(i=0;i<junction->referral_count;i++) {
941 DEBUG(10,("referral %u : %s\n",
943 junction->referral_list[i].alternate_path));
944 reply_size +=
945 (strlen(junction->referral_list[i].alternate_path)+1)*2;
948 DEBUG(10,("reply_size = %u\n",reply_size));
949 /* add the unexplained 0x16 bytes */
950 reply_size += 0x16;
952 pdata = (char *)SMB_REALLOC(pdata,reply_size);
953 if(pdata == NULL) {
954 DEBUG(0,("Realloc failed!\n"));
955 return -1;
957 *ppdata = pdata;
959 /* copy in the dfs requested paths.. required for offset calculations */
960 memcpy(pdata+uni_reqpathoffset1,uni_requestedpath,requestedpathlen);
961 memcpy(pdata+uni_reqpathoffset2,uni_requestedpath,requestedpathlen);
963 /* create the header */
964 SSVAL(pdata,0,requestedpathlen - 2); /* UCS2 of path consumed minus
965 2 byte null */
966 /* number of referral in this pkt */
967 SSVAL(pdata,2,junction->referral_count);
968 if(self_referral) {
969 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
970 } else {
971 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
974 offset = 8;
975 /* add the referral elements */
976 for(i=0;i<junction->referral_count;i++) {
977 struct referral* ref = &junction->referral_list[i];
978 int unilen;
980 SSVAL(pdata,offset,2); /* version 2 */
981 SSVAL(pdata,offset+2,VERSION2_REFERRAL_SIZE);
982 if(self_referral) {
983 SSVAL(pdata,offset+4,1);
984 } else {
985 SSVAL(pdata,offset+4,0);
988 /* ref_flags :use path_consumed bytes? */
989 SSVAL(pdata,offset+6,0);
990 SIVAL(pdata,offset+8,ref->proximity);
991 SIVAL(pdata,offset+12,ref->ttl);
993 SSVAL(pdata,offset+16,uni_reqpathoffset1-offset);
994 SSVAL(pdata,offset+18,uni_reqpathoffset2-offset);
995 /* copy referred path into current offset */
996 unilen = rpcstr_push(pdata+uni_curroffset,
997 ref->alternate_path,
998 reply_size - uni_curroffset,
999 STR_UNICODE);
1001 SSVAL(pdata,offset+20,uni_curroffset-offset);
1003 uni_curroffset += unilen;
1004 offset += VERSION2_REFERRAL_SIZE;
1006 /* add in the unexplained 22 (0x16) bytes at the end */
1007 memset(pdata+uni_curroffset,'\0',0x16);
1008 return reply_size;
1011 static int setup_ver3_dfs_referral(const char *pathname,
1012 char **ppdata,
1013 struct junction_map *junction,
1014 bool self_referral)
1016 char *pdata = *ppdata;
1018 smb_ucs2_t *uni_reqpath = NULL;
1019 int uni_reqpathoffset1, uni_reqpathoffset2;
1020 int uni_curroffset;
1021 int reply_size = 0;
1023 int reqpathlen = 0;
1024 int offset,i=0;
1026 DEBUG(10,("setting up version3 referral\n"));
1028 reqpathlen = rpcstr_push_talloc(talloc_tos(), &uni_reqpath, pathname);
1029 if (uni_reqpath == NULL || reqpathlen == 0) {
1030 return -1;
1033 if (DEBUGLVL(10)) {
1034 dump_data(0, (unsigned char *)uni_reqpath,
1035 reqpathlen);
1038 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
1039 VERSION3_REFERRAL_SIZE * junction->referral_count;
1040 uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen;
1041 reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen;
1043 for(i=0;i<junction->referral_count;i++) {
1044 DEBUG(10,("referral %u : %s\n",
1046 junction->referral_list[i].alternate_path));
1047 reply_size +=
1048 (strlen(junction->referral_list[i].alternate_path)+1)*2;
1051 pdata = (char *)SMB_REALLOC(pdata,reply_size);
1052 if(pdata == NULL) {
1053 DEBUG(0,("version3 referral setup:"
1054 "malloc failed for Realloc!\n"));
1055 return -1;
1057 *ppdata = pdata;
1059 /* create the header */
1060 SSVAL(pdata,0,reqpathlen - 2); /* UCS2 of path consumed minus
1061 2 byte null */
1062 SSVAL(pdata,2,junction->referral_count); /* number of referral */
1063 if(self_referral) {
1064 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
1065 } else {
1066 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
1069 /* copy in the reqpaths */
1070 memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen);
1071 memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen);
1073 offset = 8;
1074 for(i=0;i<junction->referral_count;i++) {
1075 struct referral* ref = &(junction->referral_list[i]);
1076 int unilen;
1078 SSVAL(pdata,offset,3); /* version 3 */
1079 SSVAL(pdata,offset+2,VERSION3_REFERRAL_SIZE);
1080 if(self_referral) {
1081 SSVAL(pdata,offset+4,1);
1082 } else {
1083 SSVAL(pdata,offset+4,0);
1086 /* ref_flags :use path_consumed bytes? */
1087 SSVAL(pdata,offset+6,0);
1088 SIVAL(pdata,offset+8,ref->ttl);
1090 SSVAL(pdata,offset+12,uni_reqpathoffset1-offset);
1091 SSVAL(pdata,offset+14,uni_reqpathoffset2-offset);
1092 /* copy referred path into current offset */
1093 unilen = rpcstr_push(pdata+uni_curroffset,ref->alternate_path,
1094 reply_size - uni_curroffset,
1095 STR_UNICODE | STR_TERMINATE);
1096 SSVAL(pdata,offset+16,uni_curroffset-offset);
1097 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
1098 memset(pdata+offset+18,'\0',16);
1100 uni_curroffset += unilen;
1101 offset += VERSION3_REFERRAL_SIZE;
1103 return reply_size;
1106 /******************************************************************
1107 Set up the DFS referral for the dfs pathname. This call returns
1108 the amount of the path covered by this server, and where the
1109 client should be redirected to. This is the meat of the
1110 TRANS2_GET_DFS_REFERRAL call.
1111 ******************************************************************/
1113 int setup_dfs_referral(connection_struct *orig_conn,
1114 const char *dfs_path,
1115 int max_referral_level,
1116 char **ppdata, NTSTATUS *pstatus)
1118 struct junction_map *junction = NULL;
1119 int consumedcnt = 0;
1120 bool self_referral = False;
1121 int reply_size = 0;
1122 char *pathnamep = NULL;
1123 char *local_dfs_path = NULL;
1124 TALLOC_CTX *ctx;
1126 if (!(ctx=talloc_init("setup_dfs_referral"))) {
1127 *pstatus = NT_STATUS_NO_MEMORY;
1128 return -1;
1131 /* get the junction entry */
1132 if (!dfs_path) {
1133 talloc_destroy(ctx);
1134 *pstatus = NT_STATUS_NOT_FOUND;
1135 return -1;
1139 * Trim pathname sent by client so it begins with only one backslash.
1140 * Two backslashes confuse some dfs clients
1143 local_dfs_path = talloc_strdup(ctx,dfs_path);
1144 if (!local_dfs_path) {
1145 *pstatus = NT_STATUS_NO_MEMORY;
1146 talloc_destroy(ctx);
1147 return -1;
1149 pathnamep = local_dfs_path;
1150 while (IS_DIRECTORY_SEP(pathnamep[0]) &&
1151 IS_DIRECTORY_SEP(pathnamep[1])) {
1152 pathnamep++;
1155 junction = TALLOC_ZERO_P(ctx, struct junction_map);
1156 if (!junction) {
1157 *pstatus = NT_STATUS_NO_MEMORY;
1158 talloc_destroy(ctx);
1159 return -1;
1162 /* The following call can change cwd. */
1163 *pstatus = get_referred_path(ctx, pathnamep, junction,
1164 &consumedcnt, &self_referral);
1165 if (!NT_STATUS_IS_OK(*pstatus)) {
1166 vfs_ChDir(orig_conn,orig_conn->connectpath);
1167 talloc_destroy(ctx);
1168 return -1;
1170 vfs_ChDir(orig_conn,orig_conn->connectpath);
1172 if (!self_referral) {
1173 pathnamep[consumedcnt] = '\0';
1175 if( DEBUGLVL( 3 ) ) {
1176 int i=0;
1177 dbgtext("setup_dfs_referral: Path %s to "
1178 "alternate path(s):",
1179 pathnamep);
1180 for(i=0;i<junction->referral_count;i++)
1181 dbgtext(" %s",
1182 junction->referral_list[i].alternate_path);
1183 dbgtext(".\n");
1187 /* create the referral depeding on version */
1188 DEBUG(10,("max_referral_level :%d\n",max_referral_level));
1190 if (max_referral_level < 2) {
1191 max_referral_level = 2;
1193 if (max_referral_level > 3) {
1194 max_referral_level = 3;
1197 switch(max_referral_level) {
1198 case 2:
1199 reply_size = setup_ver2_dfs_referral(pathnamep,
1200 ppdata, junction,
1201 self_referral);
1202 break;
1203 case 3:
1204 reply_size = setup_ver3_dfs_referral(pathnamep, ppdata,
1205 junction, self_referral);
1206 break;
1207 default:
1208 DEBUG(0,("setup_dfs_referral: Invalid dfs referral "
1209 "version: %d\n",
1210 max_referral_level));
1211 talloc_destroy(ctx);
1212 *pstatus = NT_STATUS_INVALID_LEVEL;
1213 return -1;
1216 if (DEBUGLVL(10)) {
1217 DEBUGADD(0,("DFS Referral pdata:\n"));
1218 dump_data(0,(uint8 *)*ppdata,reply_size);
1221 talloc_destroy(ctx);
1222 *pstatus = NT_STATUS_OK;
1223 return reply_size;
1226 /**********************************************************************
1227 The following functions are called by the NETDFS RPC pipe functions
1228 **********************************************************************/
1230 /*********************************************************************
1231 Creates a junction structure from a DFS pathname
1232 **********************************************************************/
1234 bool create_junction(TALLOC_CTX *ctx,
1235 const char *dfs_path,
1236 struct junction_map *jucn)
1238 int snum;
1239 bool dummy;
1240 struct dfs_path *pdp = TALLOC_P(ctx,struct dfs_path);
1241 NTSTATUS status;
1243 if (!pdp) {
1244 return False;
1246 status = parse_dfs_path(NULL, dfs_path, False, pdp, &dummy);
1247 if (!NT_STATUS_IS_OK(status)) {
1248 return False;
1251 /* check if path is dfs : validate first token */
1252 if (!is_myname_or_ipaddr(pdp->hostname)) {
1253 DEBUG(4,("create_junction: Invalid hostname %s "
1254 "in dfs path %s\n",
1255 pdp->hostname, dfs_path));
1256 TALLOC_FREE(pdp);
1257 return False;
1260 /* Check for a non-DFS share */
1261 snum = lp_servicenumber(pdp->servicename);
1263 if(snum < 0 || !lp_msdfs_root(snum)) {
1264 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1265 pdp->servicename));
1266 TALLOC_FREE(pdp);
1267 return False;
1270 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1271 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1272 jucn->comment = talloc_strdup(ctx, lp_comment(snum));
1274 TALLOC_FREE(pdp);
1275 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1276 return False;
1278 return True;
1281 /**********************************************************************
1282 Forms a valid Unix pathname from the junction
1283 **********************************************************************/
1285 static bool junction_to_local_path(const struct junction_map *jucn,
1286 char **pp_path_out,
1287 connection_struct *conn_out)
1289 int snum;
1291 snum = lp_servicenumber(jucn->service_name);
1292 if(snum < 0) {
1293 return False;
1295 if (!NT_STATUS_IS_OK(create_conn_struct(talloc_tos(),
1296 conn_out, snum,
1297 lp_pathname(snum)))) {
1298 return False;
1301 *pp_path_out = talloc_asprintf(conn_out->mem_ctx,
1302 "%s/%s",
1303 lp_pathname(snum),
1304 jucn->volume_name);
1305 if (!*pp_path_out) {
1306 return False;
1308 return True;
1311 bool create_msdfs_link(const struct junction_map *jucn)
1313 char *path = NULL;
1314 char *msdfs_link = NULL;
1315 connection_struct conns;
1316 connection_struct *conn = &conns;
1317 int i=0;
1318 bool insert_comma = False;
1319 bool ret = False;
1321 ZERO_STRUCT(conns);
1323 if(!junction_to_local_path(jucn, &path, conn)) {
1324 return False;
1327 /* Form the msdfs_link contents */
1328 msdfs_link = talloc_strdup(conn->mem_ctx, "msdfs:");
1329 if (!msdfs_link) {
1330 goto out;
1332 for(i=0; i<jucn->referral_count; i++) {
1333 char *refpath = jucn->referral_list[i].alternate_path;
1335 /* Alternate paths always use Windows separators. */
1336 trim_char(refpath, '\\', '\\');
1337 if(*refpath == '\0') {
1338 if (i == 0) {
1339 insert_comma = False;
1341 continue;
1343 if (i > 0 && insert_comma) {
1344 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1345 ",%s",
1346 refpath);
1347 } else {
1348 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1349 "%s",
1350 refpath);
1353 if (!msdfs_link) {
1354 goto out;
1356 if (!insert_comma) {
1357 insert_comma = True;
1361 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1362 path, msdfs_link));
1364 if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1365 if (errno == EEXIST) {
1366 if(SMB_VFS_UNLINK(conn,path)!=0) {
1367 goto out;
1370 if (SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1371 DEBUG(1,("create_msdfs_link: symlink failed "
1372 "%s -> %s\nError: %s\n",
1373 path, msdfs_link, strerror(errno)));
1374 goto out;
1378 ret = True;
1380 out:
1382 conn_free_internal(conn);
1383 return ret;
1386 bool remove_msdfs_link(const struct junction_map *jucn)
1388 char *path = NULL;
1389 connection_struct conns;
1390 connection_struct *conn = &conns;
1391 bool ret = False;
1393 ZERO_STRUCT(conns);
1395 if( junction_to_local_path(jucn, &path, conn) ) {
1396 if( SMB_VFS_UNLINK(conn, path) == 0 ) {
1397 ret = True;
1401 conn_free_internal(conn);
1402 return ret;
1405 /*********************************************************************
1406 Return the number of DFS links at the root of this share.
1407 *********************************************************************/
1409 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1411 size_t cnt = 0;
1412 SMB_STRUCT_DIR *dirp = NULL;
1413 char *dname = NULL;
1414 const char *connect_path = lp_pathname(snum);
1415 const char *msdfs_proxy = lp_msdfs_proxy(snum);
1416 connection_struct conn;
1418 ZERO_STRUCT(conn);
1420 if(*connect_path == '\0') {
1421 return 0;
1425 * Fake up a connection struct for the VFS layer.
1428 if (!NT_STATUS_IS_OK(create_conn_struct(talloc_tos(),
1429 &conn, snum, connect_path))) {
1430 return 0;
1433 /* Count a link for the msdfs root - convention */
1434 cnt = 1;
1436 /* No more links if this is an msdfs proxy. */
1437 if (*msdfs_proxy != '\0') {
1438 goto out;
1441 /* Now enumerate all dfs links */
1442 dirp = SMB_VFS_OPENDIR(&conn, ".", NULL, 0);
1443 if(!dirp) {
1444 goto out;
1447 while ((dname = vfs_readdirname(&conn, dirp)) != NULL) {
1448 if (is_msdfs_link(&conn,
1449 dname,
1450 NULL)) {
1451 cnt++;
1455 SMB_VFS_CLOSEDIR(&conn,dirp);
1457 out:
1459 conn_free_internal(&conn);
1460 return cnt;
1463 /*********************************************************************
1464 *********************************************************************/
1466 static int form_junctions(TALLOC_CTX *ctx,
1467 int snum,
1468 struct junction_map *jucn,
1469 size_t jn_remain)
1471 size_t cnt = 0;
1472 SMB_STRUCT_DIR *dirp = NULL;
1473 char *dname = NULL;
1474 const char *connect_path = lp_pathname(snum);
1475 char *service_name = lp_servicename(snum);
1476 const char *msdfs_proxy = lp_msdfs_proxy(snum);
1477 connection_struct conn;
1478 struct referral *ref = NULL;
1480 ZERO_STRUCT(conn);
1482 if (jn_remain == 0) {
1483 return 0;
1486 if(*connect_path == '\0') {
1487 return 0;
1491 * Fake up a connection struct for the VFS layer.
1494 if (!NT_STATUS_IS_OK(create_conn_struct(ctx, &conn, snum, connect_path))) {
1495 return 0;
1498 /* form a junction for the msdfs root - convention
1499 DO NOT REMOVE THIS: NT clients will not work with us
1500 if this is not present
1502 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1503 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1504 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1505 goto out;
1507 jucn[cnt].comment = "";
1508 jucn[cnt].referral_count = 1;
1510 ref = jucn[cnt].referral_list = TALLOC_ZERO_P(ctx, struct referral);
1511 if (jucn[cnt].referral_list == NULL) {
1512 goto out;
1515 ref->proximity = 0;
1516 ref->ttl = REFERRAL_TTL;
1517 if (*msdfs_proxy != '\0') {
1518 ref->alternate_path = talloc_strdup(ctx,
1519 msdfs_proxy);
1520 } else {
1521 ref->alternate_path = talloc_asprintf(ctx,
1522 "\\\\%s\\%s",
1523 get_local_machine_name(),
1524 service_name);
1527 if (!ref->alternate_path) {
1528 goto out;
1530 cnt++;
1532 /* Don't enumerate if we're an msdfs proxy. */
1533 if (*msdfs_proxy != '\0') {
1534 goto out;
1537 /* Now enumerate all dfs links */
1538 dirp = SMB_VFS_OPENDIR(&conn, ".", NULL, 0);
1539 if(!dirp) {
1540 goto out;
1543 while ((dname = vfs_readdirname(&conn, dirp)) != NULL) {
1544 char *link_target = NULL;
1545 if (cnt >= jn_remain) {
1546 DEBUG(2, ("form_junctions: ran out of MSDFS "
1547 "junction slots"));
1548 goto out;
1550 if (is_msdfs_link_internal(ctx,
1551 &conn,
1552 dname, &link_target,
1553 NULL)) {
1554 if (parse_msdfs_symlink(ctx,
1555 link_target,
1556 &jucn[cnt].referral_list,
1557 &jucn[cnt].referral_count)) {
1559 jucn[cnt].service_name = talloc_strdup(ctx,
1560 service_name);
1561 jucn[cnt].volume_name = talloc_strdup(ctx,
1562 dname);
1563 if (!jucn[cnt].service_name ||
1564 !jucn[cnt].volume_name) {
1565 goto out;
1567 jucn[cnt].comment = "";
1568 cnt++;
1570 TALLOC_FREE(link_target);
1574 out:
1576 if (dirp) {
1577 SMB_VFS_CLOSEDIR(&conn,dirp);
1580 conn_free_internal(&conn);
1581 return cnt;
1584 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1586 struct junction_map *jn = NULL;
1587 int i=0;
1588 size_t jn_count = 0;
1589 int sharecount = 0;
1591 *p_num_jn = 0;
1592 if(!lp_host_msdfs()) {
1593 return NULL;
1596 /* Ensure all the usershares are loaded. */
1597 become_root();
1598 load_registry_shares();
1599 sharecount = load_usershare_shares();
1600 unbecome_root();
1602 for(i=0;i < sharecount;i++) {
1603 if(lp_msdfs_root(i)) {
1604 jn_count += count_dfs_links(ctx, i);
1607 if (jn_count == 0) {
1608 return NULL;
1610 jn = TALLOC_ARRAY(ctx, struct junction_map, jn_count);
1611 if (!jn) {
1612 return NULL;
1614 for(i=0; i < sharecount; i++) {
1615 if (*p_num_jn >= jn_count) {
1616 break;
1618 if(lp_msdfs_root(i)) {
1619 *p_num_jn += form_junctions(ctx, i,
1620 &jn[*p_num_jn],
1621 jn_count - *p_num_jn);
1624 return jn;
1627 /******************************************************************************
1628 Core function to resolve a dfs pathname.
1629 ******************************************************************************/
1631 NTSTATUS resolve_dfspath(TALLOC_CTX *ctx,
1632 connection_struct *conn,
1633 bool dfs_pathnames,
1634 const char *name_in,
1635 char **pp_name_out)
1637 NTSTATUS status = NT_STATUS_OK;
1638 bool dummy;
1639 if (dfs_pathnames) {
1640 status = dfs_redirect(ctx,
1641 conn,
1642 name_in,
1643 False,
1644 pp_name_out,
1645 &dummy);
1646 } else {
1648 * Cheat and just return a copy of the in ptr.
1649 * Once srvstr_get_path() uses talloc it'll
1650 * be a talloced ptr anyway.
1652 *pp_name_out = CONST_DISCARD(char *,name_in);
1654 return status;
1657 /******************************************************************************
1658 Core function to resolve a dfs pathname possibly containing a wildcard.
1659 This function is identical to the above except for the bool param to
1660 dfs_redirect but I need this to be separate so it's really clear when
1661 we're allowing wildcards and when we're not. JRA.
1662 ******************************************************************************/
1664 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1665 connection_struct *conn,
1666 bool dfs_pathnames,
1667 const char *name_in,
1668 char **pp_name_out,
1669 bool *ppath_contains_wcard)
1671 NTSTATUS status = NT_STATUS_OK;
1672 if (dfs_pathnames) {
1673 status = dfs_redirect(ctx,
1674 conn,
1675 name_in,
1676 True,
1677 pp_name_out,
1678 ppath_contains_wcard);
1679 } else {
1681 * Cheat and just return a copy of the in ptr.
1682 * Once srvstr_get_path() uses talloc it'll
1683 * be a talloced ptr anyway.
1685 *pp_name_out = CONST_DISCARD(char *,name_in);
1687 return status;