docs: Document the -g option of smbclient.
[Samba/gbeck.git] / source3 / smbd / msdfs.c
blobd46be6426252343701c7ac48643533fd40bcfbe8
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 NTSTATUS create_conn_struct(TALLOC_CTX *ctx,
219 connection_struct **pconn,
220 int snum,
221 const char *path,
222 struct auth_serversupplied_info *server_info,
223 char **poldcwd)
225 connection_struct *conn;
226 char *connpath;
227 char *oldcwd;
229 conn = TALLOC_ZERO_P(ctx, connection_struct);
230 if (conn == NULL) {
231 return NT_STATUS_NO_MEMORY;
234 connpath = talloc_strdup(conn, path);
235 if (!connpath) {
236 TALLOC_FREE(conn);
237 return NT_STATUS_NO_MEMORY;
239 connpath = talloc_string_sub(conn,
240 connpath,
241 "%S",
242 lp_servicename(snum));
243 if (!connpath) {
244 TALLOC_FREE(conn);
245 return NT_STATUS_NO_MEMORY;
248 /* needed for smbd_vfs_init() */
250 if (!(conn->params = TALLOC_ZERO_P(conn, struct share_params))) {
251 DEBUG(0, ("TALLOC failed\n"));
252 TALLOC_FREE(conn);
253 return NT_STATUS_NO_MEMORY;
256 conn->params->service = snum;
258 if (server_info != NULL) {
259 conn->server_info = copy_serverinfo(conn, server_info);
260 if (conn->server_info == NULL) {
261 DEBUG(0, ("copy_serverinfo failed\n"));
262 TALLOC_FREE(conn);
263 return NT_STATUS_NO_MEMORY;
267 set_conn_connectpath(conn, connpath);
269 if (!smbd_vfs_init(conn)) {
270 NTSTATUS status = map_nt_error_from_unix(errno);
271 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
272 conn_free_internal(conn);
273 return status;
277 * Windows seems to insist on doing trans2getdfsreferral() calls on
278 * the IPC$ share as the anonymous user. If we try to chdir as that
279 * user we will fail.... WTF ? JRA.
282 oldcwd = vfs_GetWd(ctx, conn);
283 if (oldcwd == NULL) {
284 NTSTATUS status = map_nt_error_from_unix(errno);
285 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
286 conn_free_internal(conn);
287 return status;
290 if (vfs_ChDir(conn,conn->connectpath) != 0) {
291 NTSTATUS status = map_nt_error_from_unix(errno);
292 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
293 "Error was %s\n",
294 conn->connectpath, strerror(errno) ));
295 conn_free_internal(conn);
296 return status;
299 *pconn = conn;
300 *poldcwd = oldcwd;
302 return NT_STATUS_OK;
305 /**********************************************************************
306 Parse the contents of a symlink to verify if it is an msdfs referral
307 A valid referral is of the form:
309 msdfs:server1\share1,server2\share2
310 msdfs:server1\share1\pathname,server2\share2\pathname
311 msdfs:server1/share1,server2/share2
312 msdfs:server1/share1/pathname,server2/share2/pathname.
314 Note that the alternate paths returned here must be of the canonicalized
315 form:
317 \server\share or
318 \server\share\path\to\file,
320 even in posix path mode. This is because we have no knowledge if the
321 server we're referring to understands posix paths.
322 **********************************************************************/
324 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
325 const char *target,
326 struct referral **preflist,
327 int *refcount)
329 char *temp = NULL;
330 char *prot;
331 char **alt_path = NULL;
332 int count = 0, i;
333 struct referral *reflist;
334 char *saveptr;
336 temp = talloc_strdup(ctx, target);
337 if (!temp) {
338 return False;
340 prot = strtok_r(temp, ":", &saveptr);
341 if (!prot) {
342 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
343 return False;
346 alt_path = TALLOC_ARRAY(ctx, char *, MAX_REFERRAL_COUNT);
347 if (!alt_path) {
348 return False;
351 /* parse out the alternate paths */
352 while((count<MAX_REFERRAL_COUNT) &&
353 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
354 count++;
357 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
359 if (count) {
360 reflist = *preflist = TALLOC_ZERO_ARRAY(ctx,
361 struct referral, count);
362 if(reflist == NULL) {
363 TALLOC_FREE(alt_path);
364 return False;
366 } else {
367 reflist = *preflist = NULL;
370 for(i=0;i<count;i++) {
371 char *p;
373 /* Canonicalize link target.
374 * Replace all /'s in the path by a \ */
375 string_replace(alt_path[i], '/', '\\');
377 /* Remove leading '\\'s */
378 p = alt_path[i];
379 while (*p && (*p == '\\')) {
380 p++;
383 reflist[i].alternate_path = talloc_asprintf(ctx,
384 "\\%s",
386 if (!reflist[i].alternate_path) {
387 return False;
390 reflist[i].proximity = 0;
391 reflist[i].ttl = REFERRAL_TTL;
392 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
393 reflist[i].alternate_path));
396 *refcount = count;
398 TALLOC_FREE(alt_path);
399 return True;
402 /**********************************************************************
403 Returns true if the unix path is a valid msdfs symlink and also
404 returns the target string from inside the link.
405 **********************************************************************/
407 static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
408 connection_struct *conn,
409 const char *path,
410 char **pp_link_target,
411 SMB_STRUCT_STAT *sbufp)
413 SMB_STRUCT_STAT st;
414 int referral_len = 0;
415 char link_target_buf[7];
416 size_t bufsize = 0;
417 char *link_target = NULL;
419 if (pp_link_target) {
420 bufsize = 1024;
421 link_target = TALLOC_ARRAY(ctx, char, bufsize);
422 if (!link_target) {
423 return False;
425 *pp_link_target = link_target;
426 } else {
427 bufsize = sizeof(link_target_buf);
428 link_target = link_target_buf;
431 if (sbufp == NULL) {
432 sbufp = &st;
435 if (SMB_VFS_LSTAT(conn, path, sbufp) != 0) {
436 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
437 path));
438 goto err;
441 if (!S_ISLNK(sbufp->st_mode)) {
442 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
443 path));
444 goto err;
447 referral_len = SMB_VFS_READLINK(conn, path, link_target, bufsize - 1);
448 if (referral_len == -1) {
449 DEBUG(0,("is_msdfs_link_read_target: Error reading "
450 "msdfs link %s: %s\n",
451 path, strerror(errno)));
452 goto err;
454 link_target[referral_len] = '\0';
456 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path,
457 link_target));
459 if (!strnequal(link_target, "msdfs:", 6)) {
460 goto err;
462 return True;
464 err:
466 if (link_target != link_target_buf) {
467 TALLOC_FREE(link_target);
469 return False;
472 /**********************************************************************
473 Returns true if the unix path is a valid msdfs symlink.
474 **********************************************************************/
476 bool is_msdfs_link(connection_struct *conn,
477 const char *path,
478 SMB_STRUCT_STAT *sbufp)
480 return is_msdfs_link_internal(talloc_tos(),
481 conn,
482 path,
483 NULL,
484 sbufp);
487 /*****************************************************************
488 Used by other functions to decide if a dfs path is remote,
489 and to get the list of referred locations for that remote path.
491 search_flag: For findfirsts, dfs links themselves are not
492 redirected, but paths beyond the links are. For normal smb calls,
493 even dfs links need to be redirected.
495 consumedcntp: how much of the dfs path is being redirected. the client
496 should try the remaining path on the redirected server.
498 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
499 link redirect are in targetpath.
500 *****************************************************************/
502 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
503 connection_struct *conn,
504 const char *dfspath, /* Incoming complete dfs path */
505 const struct dfs_path *pdp, /* Parsed out
506 server+share+extrapath. */
507 bool search_flag, /* Called from a findfirst ? */
508 int *consumedcntp,
509 char **pp_targetpath)
511 char *p = NULL;
512 char *q = NULL;
513 SMB_STRUCT_STAT sbuf;
514 NTSTATUS status;
515 char *localpath = NULL;
516 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
517 components). */
519 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
520 conn->connectpath, pdp->reqpath));
523 * Note the unix path conversion here we're doing we can
524 * throw away. We're looking for a symlink for a dfs
525 * resolution, if we don't find it we'll do another
526 * unix_convert later in the codepath.
527 * If we needed to remember what we'd resolved in
528 * dp->reqpath (as the original code did) we'd
529 * copy (localhost, dp->reqpath) on any code
530 * path below that returns True - but I don't
531 * think this is needed. JRA.
534 status = unix_convert(ctx, conn, pdp->reqpath, search_flag, &localpath,
535 NULL, &sbuf);
536 if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status,
537 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
538 return status;
541 /* Optimization - check if we can redirect the whole path. */
543 if (is_msdfs_link_internal(ctx, conn, localpath, pp_targetpath, NULL)) {
544 if (search_flag) {
545 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
546 "for dfs link %s.\n", dfspath));
547 return NT_STATUS_OK;
550 DEBUG(6,("dfs_path_lookup: %s resolves to a "
551 "valid dfs link %s.\n", dfspath,
552 pp_targetpath ? *pp_targetpath : ""));
554 if (consumedcntp) {
555 *consumedcntp = strlen(dfspath);
557 return NT_STATUS_PATH_NOT_COVERED;
560 /* Prepare to test only for '/' components in the given path,
561 * so if a Windows path replace all '\\' characters with '/'.
562 * For a POSIX DFS path we know all separators are already '/'. */
564 canon_dfspath = talloc_strdup(ctx, dfspath);
565 if (!canon_dfspath) {
566 return NT_STATUS_NO_MEMORY;
568 if (!pdp->posix_path) {
569 string_replace(canon_dfspath, '\\', '/');
573 * localpath comes out of unix_convert, so it has
574 * no trailing backslash. Make sure that canon_dfspath hasn't either.
575 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
578 trim_char(canon_dfspath,0,'/');
581 * Redirect if any component in the path is a link.
582 * We do this by walking backwards through the
583 * local path, chopping off the last component
584 * in both the local path and the canonicalized
585 * DFS path. If we hit a DFS link then we're done.
588 p = strrchr_m(localpath, '/');
589 if (consumedcntp) {
590 q = strrchr_m(canon_dfspath, '/');
593 while (p) {
594 *p = '\0';
595 if (q) {
596 *q = '\0';
599 if (is_msdfs_link_internal(ctx, conn,
600 localpath, pp_targetpath, NULL)) {
601 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
602 "parent %s is dfs link\n", dfspath, localpath));
604 if (consumedcntp) {
605 *consumedcntp = strlen(canon_dfspath);
606 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
607 "(%d)\n",
608 canon_dfspath,
609 *consumedcntp));
612 return NT_STATUS_PATH_NOT_COVERED;
615 /* Step back on the filesystem. */
616 p = strrchr_m(localpath, '/');
618 if (consumedcntp) {
619 /* And in the canonicalized dfs path. */
620 q = strrchr_m(canon_dfspath, '/');
624 return NT_STATUS_OK;
627 /*****************************************************************
628 Decides if a dfs pathname should be redirected or not.
629 If not, the pathname is converted to a tcon-relative local unix path
631 search_wcard_flag: this flag performs 2 functions both related
632 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
633 for details.
635 This function can return NT_STATUS_OK, meaning use the returned path as-is
636 (mapped into a local path).
637 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
638 any other NT_STATUS error which is a genuine error to be
639 returned to the client.
640 *****************************************************************/
642 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
643 connection_struct *conn,
644 const char *path_in,
645 bool search_wcard_flag,
646 char **pp_path_out,
647 bool *ppath_contains_wcard)
649 NTSTATUS status;
650 struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
652 if (!pdp) {
653 return NT_STATUS_NO_MEMORY;
656 status = parse_dfs_path(conn, path_in, search_wcard_flag, pdp,
657 ppath_contains_wcard);
658 if (!NT_STATUS_IS_OK(status)) {
659 TALLOC_FREE(pdp);
660 return status;
663 if (pdp->reqpath[0] == '\0') {
664 TALLOC_FREE(pdp);
665 *pp_path_out = talloc_strdup(ctx, "");
666 if (!*pp_path_out) {
667 return NT_STATUS_NO_MEMORY;
669 DEBUG(5,("dfs_redirect: self-referral.\n"));
670 return NT_STATUS_OK;
673 /* If dfs pathname for a non-dfs share, convert to tcon-relative
674 path and return OK */
676 if (!lp_msdfs_root(SNUM(conn))) {
677 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
678 TALLOC_FREE(pdp);
679 if (!*pp_path_out) {
680 return NT_STATUS_NO_MEMORY;
682 return NT_STATUS_OK;
685 /* If it looked like a local path (zero hostname/servicename)
686 * just treat as a tcon-relative path. */
688 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
689 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
690 TALLOC_FREE(pdp);
691 if (!*pp_path_out) {
692 return NT_STATUS_NO_MEMORY;
694 return NT_STATUS_OK;
697 if (!( strequal(pdp->servicename, lp_servicename(SNUM(conn)))
698 || (strequal(pdp->servicename, HOMES_NAME)
699 && strequal(lp_servicename(SNUM(conn)),
700 conn->server_info->sanitized_username) )) ) {
702 /* The given sharename doesn't match this connection. */
703 TALLOC_FREE(pdp);
705 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
708 status = dfs_path_lookup(ctx, conn, path_in, pdp,
709 search_wcard_flag, NULL, NULL);
710 if (!NT_STATUS_IS_OK(status)) {
711 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
712 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
713 } else {
714 DEBUG(10,("dfs_redirect: dfs_path_lookup "
715 "failed for %s with %s\n",
716 path_in, nt_errstr(status) ));
718 return status;
721 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
723 /* Form non-dfs tcon-relative path */
724 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
725 TALLOC_FREE(pdp);
726 if (!*pp_path_out) {
727 return NT_STATUS_NO_MEMORY;
730 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
731 path_in,
732 *pp_path_out));
734 return NT_STATUS_OK;
737 /**********************************************************************
738 Return a self referral.
739 **********************************************************************/
741 static NTSTATUS self_ref(TALLOC_CTX *ctx,
742 const char *dfs_path,
743 struct junction_map *jucn,
744 int *consumedcntp,
745 bool *self_referralp)
747 struct referral *ref;
749 *self_referralp = True;
751 jucn->referral_count = 1;
752 if((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
753 return NT_STATUS_NO_MEMORY;
756 ref->alternate_path = talloc_strdup(ctx, dfs_path);
757 if (!ref->alternate_path) {
758 return NT_STATUS_NO_MEMORY;
760 ref->proximity = 0;
761 ref->ttl = REFERRAL_TTL;
762 jucn->referral_list = ref;
763 *consumedcntp = strlen(dfs_path);
764 return NT_STATUS_OK;
767 /**********************************************************************
768 Gets valid referrals for a dfs path and fills up the
769 junction_map structure.
770 **********************************************************************/
772 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
773 const char *dfs_path,
774 struct junction_map *jucn,
775 int *consumedcntp,
776 bool *self_referralp)
778 struct connection_struct *conn;
779 char *targetpath = NULL;
780 int snum;
781 NTSTATUS status = NT_STATUS_NOT_FOUND;
782 bool dummy;
783 struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
784 char *oldpath;
786 if (!pdp) {
787 return NT_STATUS_NO_MEMORY;
790 *self_referralp = False;
792 status = parse_dfs_path(NULL, dfs_path, False, pdp, &dummy);
793 if (!NT_STATUS_IS_OK(status)) {
794 return status;
797 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
798 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
799 if (!jucn->service_name || !jucn->volume_name) {
800 TALLOC_FREE(pdp);
801 return NT_STATUS_NO_MEMORY;
804 /* Verify the share is a dfs root */
805 snum = lp_servicenumber(jucn->service_name);
806 if(snum < 0) {
807 fstring service_name;
808 fstrcpy(service_name, jucn->service_name);
809 if ((snum = find_service(service_name)) < 0) {
810 return NT_STATUS_NOT_FOUND;
812 TALLOC_FREE(jucn->service_name);
813 jucn->service_name = talloc_strdup(ctx, service_name);
814 if (!jucn->service_name) {
815 TALLOC_FREE(pdp);
816 return NT_STATUS_NO_MEMORY;
820 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(snum) == '\0')) {
821 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
822 "a dfs root.\n",
823 pdp->servicename, dfs_path));
824 TALLOC_FREE(pdp);
825 return NT_STATUS_NOT_FOUND;
829 * Self referrals are tested with a anonymous IPC connection and
830 * a GET_DFS_REFERRAL call to \\server\share. (which means
831 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
832 * into the directory and will fail if it cannot (as the anonymous
833 * user). Cope with this.
836 if (pdp->reqpath[0] == '\0') {
837 char *tmp;
838 struct referral *ref;
840 if (*lp_msdfs_proxy(snum) == '\0') {
841 TALLOC_FREE(pdp);
842 return self_ref(ctx,
843 dfs_path,
844 jucn,
845 consumedcntp,
846 self_referralp);
850 * It's an msdfs proxy share. Redirect to
851 * the configured target share.
854 jucn->referral_count = 1;
855 if ((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
856 TALLOC_FREE(pdp);
857 return NT_STATUS_NO_MEMORY;
860 if (!(tmp = talloc_strdup(ctx, lp_msdfs_proxy(snum)))) {
861 TALLOC_FREE(pdp);
862 return NT_STATUS_NO_MEMORY;
865 trim_string(tmp, "\\", 0);
867 ref->alternate_path = talloc_asprintf(ctx, "\\%s", tmp);
868 TALLOC_FREE(tmp);
870 if (!ref->alternate_path) {
871 TALLOC_FREE(pdp);
872 return NT_STATUS_NO_MEMORY;
875 if (pdp->reqpath[0] != '\0') {
876 ref->alternate_path = talloc_asprintf_append(
877 ref->alternate_path,
878 "%s",
879 pdp->reqpath);
880 if (!ref->alternate_path) {
881 TALLOC_FREE(pdp);
882 return NT_STATUS_NO_MEMORY;
885 ref->proximity = 0;
886 ref->ttl = REFERRAL_TTL;
887 jucn->referral_list = ref;
888 *consumedcntp = strlen(dfs_path);
889 TALLOC_FREE(pdp);
890 return NT_STATUS_OK;
893 status = create_conn_struct(ctx, &conn, snum, lp_pathname(snum),
894 NULL, &oldpath);
895 if (!NT_STATUS_IS_OK(status)) {
896 TALLOC_FREE(pdp);
897 return status;
900 /* If this is a DFS path dfs_lookup should return
901 * NT_STATUS_PATH_NOT_COVERED. */
903 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
904 False, consumedcntp, &targetpath);
906 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
907 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
908 dfs_path));
909 vfs_ChDir(conn, oldpath);
910 conn_free_internal(conn);
911 TALLOC_FREE(pdp);
912 return status;
915 /* We know this is a valid dfs link. Parse the targetpath. */
916 if (!parse_msdfs_symlink(ctx, targetpath,
917 &jucn->referral_list,
918 &jucn->referral_count)) {
919 DEBUG(3,("get_referred_path: failed to parse symlink "
920 "target %s\n", targetpath ));
921 vfs_ChDir(conn, oldpath);
922 conn_free_internal(conn);
923 TALLOC_FREE(pdp);
924 return NT_STATUS_NOT_FOUND;
927 vfs_ChDir(conn, oldpath);
928 conn_free_internal(conn);
929 TALLOC_FREE(pdp);
930 return NT_STATUS_OK;
933 static int setup_ver2_dfs_referral(const char *pathname,
934 char **ppdata,
935 struct junction_map *junction,
936 bool self_referral)
938 char* pdata = *ppdata;
940 smb_ucs2_t *uni_requestedpath = NULL;
941 int uni_reqpathoffset1,uni_reqpathoffset2;
942 int uni_curroffset;
943 int requestedpathlen=0;
944 int offset;
945 int reply_size = 0;
946 int i=0;
948 DEBUG(10,("Setting up version2 referral\nRequested path:\n"));
950 requestedpathlen = rpcstr_push_talloc(talloc_tos(),
951 &uni_requestedpath, pathname);
952 if (uni_requestedpath == NULL || requestedpathlen == 0) {
953 return -1;
956 if (DEBUGLVL(10)) {
957 dump_data(0, (unsigned char *)uni_requestedpath,
958 requestedpathlen);
961 DEBUG(10,("ref count = %u\n",junction->referral_count));
963 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
964 VERSION2_REFERRAL_SIZE * junction->referral_count;
966 uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen;
968 uni_curroffset = uni_reqpathoffset2 + requestedpathlen;
970 reply_size = REFERRAL_HEADER_SIZE +
971 VERSION2_REFERRAL_SIZE*junction->referral_count +
972 2 * requestedpathlen;
973 DEBUG(10,("reply_size: %u\n",reply_size));
975 /* add up the unicode lengths of all the referral paths */
976 for(i=0;i<junction->referral_count;i++) {
977 DEBUG(10,("referral %u : %s\n",
979 junction->referral_list[i].alternate_path));
980 reply_size +=
981 (strlen(junction->referral_list[i].alternate_path)+1)*2;
984 DEBUG(10,("reply_size = %u\n",reply_size));
985 /* add the unexplained 0x16 bytes */
986 reply_size += 0x16;
988 pdata = (char *)SMB_REALLOC(pdata,reply_size);
989 if(pdata == NULL) {
990 DEBUG(0,("Realloc failed!\n"));
991 return -1;
993 *ppdata = pdata;
995 /* copy in the dfs requested paths.. required for offset calculations */
996 memcpy(pdata+uni_reqpathoffset1,uni_requestedpath,requestedpathlen);
997 memcpy(pdata+uni_reqpathoffset2,uni_requestedpath,requestedpathlen);
999 /* create the header */
1000 SSVAL(pdata,0,requestedpathlen - 2); /* UCS2 of path consumed minus
1001 2 byte null */
1002 /* number of referral in this pkt */
1003 SSVAL(pdata,2,junction->referral_count);
1004 if(self_referral) {
1005 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
1006 } else {
1007 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
1010 offset = 8;
1011 /* add the referral elements */
1012 for(i=0;i<junction->referral_count;i++) {
1013 struct referral* ref = &junction->referral_list[i];
1014 int unilen;
1016 SSVAL(pdata,offset,2); /* version 2 */
1017 SSVAL(pdata,offset+2,VERSION2_REFERRAL_SIZE);
1018 if(self_referral) {
1019 SSVAL(pdata,offset+4,1);
1020 } else {
1021 SSVAL(pdata,offset+4,0);
1024 /* ref_flags :use path_consumed bytes? */
1025 SSVAL(pdata,offset+6,0);
1026 SIVAL(pdata,offset+8,ref->proximity);
1027 SIVAL(pdata,offset+12,ref->ttl);
1029 SSVAL(pdata,offset+16,uni_reqpathoffset1-offset);
1030 SSVAL(pdata,offset+18,uni_reqpathoffset2-offset);
1031 /* copy referred path into current offset */
1032 unilen = rpcstr_push(pdata+uni_curroffset,
1033 ref->alternate_path,
1034 reply_size - uni_curroffset,
1035 STR_UNICODE);
1037 SSVAL(pdata,offset+20,uni_curroffset-offset);
1039 uni_curroffset += unilen;
1040 offset += VERSION2_REFERRAL_SIZE;
1042 /* add in the unexplained 22 (0x16) bytes at the end */
1043 memset(pdata+uni_curroffset,'\0',0x16);
1044 return reply_size;
1047 static int setup_ver3_dfs_referral(const char *pathname,
1048 char **ppdata,
1049 struct junction_map *junction,
1050 bool self_referral)
1052 char *pdata = *ppdata;
1054 smb_ucs2_t *uni_reqpath = NULL;
1055 int uni_reqpathoffset1, uni_reqpathoffset2;
1056 int uni_curroffset;
1057 int reply_size = 0;
1059 int reqpathlen = 0;
1060 int offset,i=0;
1062 DEBUG(10,("setting up version3 referral\n"));
1064 reqpathlen = rpcstr_push_talloc(talloc_tos(), &uni_reqpath, pathname);
1065 if (uni_reqpath == NULL || reqpathlen == 0) {
1066 return -1;
1069 if (DEBUGLVL(10)) {
1070 dump_data(0, (unsigned char *)uni_reqpath,
1071 reqpathlen);
1074 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
1075 VERSION3_REFERRAL_SIZE * junction->referral_count;
1076 uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen;
1077 reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen;
1079 for(i=0;i<junction->referral_count;i++) {
1080 DEBUG(10,("referral %u : %s\n",
1082 junction->referral_list[i].alternate_path));
1083 reply_size +=
1084 (strlen(junction->referral_list[i].alternate_path)+1)*2;
1087 pdata = (char *)SMB_REALLOC(pdata,reply_size);
1088 if(pdata == NULL) {
1089 DEBUG(0,("version3 referral setup:"
1090 "malloc failed for Realloc!\n"));
1091 return -1;
1093 *ppdata = pdata;
1095 /* create the header */
1096 SSVAL(pdata,0,reqpathlen - 2); /* UCS2 of path consumed minus
1097 2 byte null */
1098 SSVAL(pdata,2,junction->referral_count); /* number of referral */
1099 if(self_referral) {
1100 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
1101 } else {
1102 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
1105 /* copy in the reqpaths */
1106 memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen);
1107 memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen);
1109 offset = 8;
1110 for(i=0;i<junction->referral_count;i++) {
1111 struct referral* ref = &(junction->referral_list[i]);
1112 int unilen;
1114 SSVAL(pdata,offset,3); /* version 3 */
1115 SSVAL(pdata,offset+2,VERSION3_REFERRAL_SIZE);
1116 if(self_referral) {
1117 SSVAL(pdata,offset+4,1);
1118 } else {
1119 SSVAL(pdata,offset+4,0);
1122 /* ref_flags :use path_consumed bytes? */
1123 SSVAL(pdata,offset+6,0);
1124 SIVAL(pdata,offset+8,ref->ttl);
1126 SSVAL(pdata,offset+12,uni_reqpathoffset1-offset);
1127 SSVAL(pdata,offset+14,uni_reqpathoffset2-offset);
1128 /* copy referred path into current offset */
1129 unilen = rpcstr_push(pdata+uni_curroffset,ref->alternate_path,
1130 reply_size - uni_curroffset,
1131 STR_UNICODE | STR_TERMINATE);
1132 SSVAL(pdata,offset+16,uni_curroffset-offset);
1133 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
1134 memset(pdata+offset+18,'\0',16);
1136 uni_curroffset += unilen;
1137 offset += VERSION3_REFERRAL_SIZE;
1139 return reply_size;
1142 /******************************************************************
1143 Set up the DFS referral for the dfs pathname. This call returns
1144 the amount of the path covered by this server, and where the
1145 client should be redirected to. This is the meat of the
1146 TRANS2_GET_DFS_REFERRAL call.
1147 ******************************************************************/
1149 int setup_dfs_referral(connection_struct *orig_conn,
1150 const char *dfs_path,
1151 int max_referral_level,
1152 char **ppdata, NTSTATUS *pstatus)
1154 struct junction_map *junction = NULL;
1155 int consumedcnt = 0;
1156 bool self_referral = False;
1157 int reply_size = 0;
1158 char *pathnamep = NULL;
1159 char *local_dfs_path = NULL;
1160 TALLOC_CTX *ctx;
1162 if (!(ctx=talloc_init("setup_dfs_referral"))) {
1163 *pstatus = NT_STATUS_NO_MEMORY;
1164 return -1;
1167 /* get the junction entry */
1168 if (!dfs_path) {
1169 talloc_destroy(ctx);
1170 *pstatus = NT_STATUS_NOT_FOUND;
1171 return -1;
1175 * Trim pathname sent by client so it begins with only one backslash.
1176 * Two backslashes confuse some dfs clients
1179 local_dfs_path = talloc_strdup(ctx,dfs_path);
1180 if (!local_dfs_path) {
1181 *pstatus = NT_STATUS_NO_MEMORY;
1182 talloc_destroy(ctx);
1183 return -1;
1185 pathnamep = local_dfs_path;
1186 while (IS_DIRECTORY_SEP(pathnamep[0]) &&
1187 IS_DIRECTORY_SEP(pathnamep[1])) {
1188 pathnamep++;
1191 junction = TALLOC_ZERO_P(ctx, struct junction_map);
1192 if (!junction) {
1193 *pstatus = NT_STATUS_NO_MEMORY;
1194 talloc_destroy(ctx);
1195 return -1;
1198 /* The following call can change cwd. */
1199 *pstatus = get_referred_path(ctx, pathnamep, junction,
1200 &consumedcnt, &self_referral);
1201 if (!NT_STATUS_IS_OK(*pstatus)) {
1202 vfs_ChDir(orig_conn,orig_conn->connectpath);
1203 talloc_destroy(ctx);
1204 return -1;
1206 vfs_ChDir(orig_conn,orig_conn->connectpath);
1208 if (!self_referral) {
1209 pathnamep[consumedcnt] = '\0';
1211 if( DEBUGLVL( 3 ) ) {
1212 int i=0;
1213 dbgtext("setup_dfs_referral: Path %s to "
1214 "alternate path(s):",
1215 pathnamep);
1216 for(i=0;i<junction->referral_count;i++)
1217 dbgtext(" %s",
1218 junction->referral_list[i].alternate_path);
1219 dbgtext(".\n");
1223 /* create the referral depeding on version */
1224 DEBUG(10,("max_referral_level :%d\n",max_referral_level));
1226 if (max_referral_level < 2) {
1227 max_referral_level = 2;
1229 if (max_referral_level > 3) {
1230 max_referral_level = 3;
1233 switch(max_referral_level) {
1234 case 2:
1235 reply_size = setup_ver2_dfs_referral(pathnamep,
1236 ppdata, junction,
1237 self_referral);
1238 break;
1239 case 3:
1240 reply_size = setup_ver3_dfs_referral(pathnamep, ppdata,
1241 junction, self_referral);
1242 break;
1243 default:
1244 DEBUG(0,("setup_dfs_referral: Invalid dfs referral "
1245 "version: %d\n",
1246 max_referral_level));
1247 talloc_destroy(ctx);
1248 *pstatus = NT_STATUS_INVALID_LEVEL;
1249 return -1;
1252 if (DEBUGLVL(10)) {
1253 DEBUGADD(0,("DFS Referral pdata:\n"));
1254 dump_data(0,(uint8 *)*ppdata,reply_size);
1257 talloc_destroy(ctx);
1258 *pstatus = NT_STATUS_OK;
1259 return reply_size;
1262 /**********************************************************************
1263 The following functions are called by the NETDFS RPC pipe functions
1264 **********************************************************************/
1266 /*********************************************************************
1267 Creates a junction structure from a DFS pathname
1268 **********************************************************************/
1270 bool create_junction(TALLOC_CTX *ctx,
1271 const char *dfs_path,
1272 struct junction_map *jucn)
1274 int snum;
1275 bool dummy;
1276 struct dfs_path *pdp = TALLOC_P(ctx,struct dfs_path);
1277 NTSTATUS status;
1279 if (!pdp) {
1280 return False;
1282 status = parse_dfs_path(NULL, dfs_path, False, pdp, &dummy);
1283 if (!NT_STATUS_IS_OK(status)) {
1284 return False;
1287 /* check if path is dfs : validate first token */
1288 if (!is_myname_or_ipaddr(pdp->hostname)) {
1289 DEBUG(4,("create_junction: Invalid hostname %s "
1290 "in dfs path %s\n",
1291 pdp->hostname, dfs_path));
1292 TALLOC_FREE(pdp);
1293 return False;
1296 /* Check for a non-DFS share */
1297 snum = lp_servicenumber(pdp->servicename);
1299 if(snum < 0 || !lp_msdfs_root(snum)) {
1300 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1301 pdp->servicename));
1302 TALLOC_FREE(pdp);
1303 return False;
1306 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1307 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1308 jucn->comment = talloc_strdup(ctx, lp_comment(snum));
1310 TALLOC_FREE(pdp);
1311 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1312 return False;
1314 return True;
1317 /**********************************************************************
1318 Forms a valid Unix pathname from the junction
1319 **********************************************************************/
1321 static bool junction_to_local_path(const struct junction_map *jucn,
1322 char **pp_path_out,
1323 connection_struct **conn_out,
1324 char **oldpath)
1326 int snum;
1327 NTSTATUS status;
1329 snum = lp_servicenumber(jucn->service_name);
1330 if(snum < 0) {
1331 return False;
1333 status = create_conn_struct(talloc_tos(), conn_out, snum,
1334 lp_pathname(snum), NULL, oldpath);
1335 if (!NT_STATUS_IS_OK(status)) {
1336 return False;
1339 *pp_path_out = talloc_asprintf(*conn_out,
1340 "%s/%s",
1341 lp_pathname(snum),
1342 jucn->volume_name);
1343 if (!*pp_path_out) {
1344 vfs_ChDir(*conn_out, *oldpath);
1345 conn_free_internal(*conn_out);
1346 return False;
1348 return True;
1351 bool create_msdfs_link(const struct junction_map *jucn)
1353 char *path = NULL;
1354 char *cwd;
1355 char *msdfs_link = NULL;
1356 connection_struct *conn;
1357 int i=0;
1358 bool insert_comma = False;
1359 bool ret = False;
1361 if(!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1362 return False;
1365 /* Form the msdfs_link contents */
1366 msdfs_link = talloc_strdup(conn, "msdfs:");
1367 if (!msdfs_link) {
1368 goto out;
1370 for(i=0; i<jucn->referral_count; i++) {
1371 char *refpath = jucn->referral_list[i].alternate_path;
1373 /* Alternate paths always use Windows separators. */
1374 trim_char(refpath, '\\', '\\');
1375 if(*refpath == '\0') {
1376 if (i == 0) {
1377 insert_comma = False;
1379 continue;
1381 if (i > 0 && insert_comma) {
1382 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1383 ",%s",
1384 refpath);
1385 } else {
1386 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1387 "%s",
1388 refpath);
1391 if (!msdfs_link) {
1392 goto out;
1394 if (!insert_comma) {
1395 insert_comma = True;
1399 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1400 path, msdfs_link));
1402 if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1403 if (errno == EEXIST) {
1404 if(SMB_VFS_UNLINK(conn,path)!=0) {
1405 goto out;
1408 if (SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1409 DEBUG(1,("create_msdfs_link: symlink failed "
1410 "%s -> %s\nError: %s\n",
1411 path, msdfs_link, strerror(errno)));
1412 goto out;
1416 ret = True;
1418 out:
1419 vfs_ChDir(conn, cwd);
1420 conn_free_internal(conn);
1421 return ret;
1424 bool remove_msdfs_link(const struct junction_map *jucn)
1426 char *path = NULL;
1427 char *cwd;
1428 connection_struct *conn;
1429 bool ret = False;
1431 if (!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1432 return false;
1435 if( SMB_VFS_UNLINK(conn, path) == 0 ) {
1436 ret = True;
1439 vfs_ChDir(conn, cwd);
1440 conn_free_internal(conn);
1441 return ret;
1444 /*********************************************************************
1445 Return the number of DFS links at the root of this share.
1446 *********************************************************************/
1448 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1450 size_t cnt = 0;
1451 SMB_STRUCT_DIR *dirp = NULL;
1452 char *dname = NULL;
1453 const char *connect_path = lp_pathname(snum);
1454 const char *msdfs_proxy = lp_msdfs_proxy(snum);
1455 connection_struct *conn;
1456 NTSTATUS status;
1457 char *cwd;
1459 if(*connect_path == '\0') {
1460 return 0;
1464 * Fake up a connection struct for the VFS layer.
1467 status = create_conn_struct(talloc_tos(), &conn, snum, connect_path,
1468 NULL, &cwd);
1469 if (!NT_STATUS_IS_OK(status)) {
1470 DEBUG(3, ("create_conn_struct failed: %s\n",
1471 nt_errstr(status)));
1472 return 0;
1475 /* Count a link for the msdfs root - convention */
1476 cnt = 1;
1478 /* No more links if this is an msdfs proxy. */
1479 if (*msdfs_proxy != '\0') {
1480 goto out;
1483 /* Now enumerate all dfs links */
1484 dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1485 if(!dirp) {
1486 goto out;
1489 while ((dname = vfs_readdirname(conn, dirp)) != NULL) {
1490 if (is_msdfs_link(conn,
1491 dname,
1492 NULL)) {
1493 cnt++;
1497 SMB_VFS_CLOSEDIR(conn,dirp);
1499 out:
1500 vfs_ChDir(conn, cwd);
1501 conn_free_internal(conn);
1502 return cnt;
1505 /*********************************************************************
1506 *********************************************************************/
1508 static int form_junctions(TALLOC_CTX *ctx,
1509 int snum,
1510 struct junction_map *jucn,
1511 size_t jn_remain)
1513 size_t cnt = 0;
1514 SMB_STRUCT_DIR *dirp = NULL;
1515 char *dname = NULL;
1516 const char *connect_path = lp_pathname(snum);
1517 char *service_name = lp_servicename(snum);
1518 const char *msdfs_proxy = lp_msdfs_proxy(snum);
1519 connection_struct *conn;
1520 struct referral *ref = NULL;
1521 char *cwd;
1522 NTSTATUS status;
1524 if (jn_remain == 0) {
1525 return 0;
1528 if(*connect_path == '\0') {
1529 return 0;
1533 * Fake up a connection struct for the VFS layer.
1536 status = create_conn_struct(ctx, &conn, snum, connect_path, NULL,
1537 &cwd);
1538 if (!NT_STATUS_IS_OK(status)) {
1539 DEBUG(3, ("create_conn_struct failed: %s\n",
1540 nt_errstr(status)));
1541 return 0;
1544 /* form a junction for the msdfs root - convention
1545 DO NOT REMOVE THIS: NT clients will not work with us
1546 if this is not present
1548 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1549 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1550 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1551 goto out;
1553 jucn[cnt].comment = "";
1554 jucn[cnt].referral_count = 1;
1556 ref = jucn[cnt].referral_list = TALLOC_ZERO_P(ctx, struct referral);
1557 if (jucn[cnt].referral_list == NULL) {
1558 goto out;
1561 ref->proximity = 0;
1562 ref->ttl = REFERRAL_TTL;
1563 if (*msdfs_proxy != '\0') {
1564 ref->alternate_path = talloc_strdup(ctx,
1565 msdfs_proxy);
1566 } else {
1567 ref->alternate_path = talloc_asprintf(ctx,
1568 "\\\\%s\\%s",
1569 get_local_machine_name(),
1570 service_name);
1573 if (!ref->alternate_path) {
1574 goto out;
1576 cnt++;
1578 /* Don't enumerate if we're an msdfs proxy. */
1579 if (*msdfs_proxy != '\0') {
1580 goto out;
1583 /* Now enumerate all dfs links */
1584 dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1585 if(!dirp) {
1586 goto out;
1589 while ((dname = vfs_readdirname(conn, dirp)) != NULL) {
1590 char *link_target = NULL;
1591 if (cnt >= jn_remain) {
1592 DEBUG(2, ("form_junctions: ran out of MSDFS "
1593 "junction slots"));
1594 goto out;
1596 if (is_msdfs_link_internal(ctx,
1597 conn,
1598 dname, &link_target,
1599 NULL)) {
1600 if (parse_msdfs_symlink(ctx,
1601 link_target,
1602 &jucn[cnt].referral_list,
1603 &jucn[cnt].referral_count)) {
1605 jucn[cnt].service_name = talloc_strdup(ctx,
1606 service_name);
1607 jucn[cnt].volume_name = talloc_strdup(ctx,
1608 dname);
1609 if (!jucn[cnt].service_name ||
1610 !jucn[cnt].volume_name) {
1611 goto out;
1613 jucn[cnt].comment = "";
1614 cnt++;
1616 TALLOC_FREE(link_target);
1620 out:
1622 if (dirp) {
1623 SMB_VFS_CLOSEDIR(conn,dirp);
1626 vfs_ChDir(conn, cwd);
1627 conn_free_internal(conn);
1628 return cnt;
1631 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1633 struct junction_map *jn = NULL;
1634 int i=0;
1635 size_t jn_count = 0;
1636 int sharecount = 0;
1638 *p_num_jn = 0;
1639 if(!lp_host_msdfs()) {
1640 return NULL;
1643 /* Ensure all the usershares are loaded. */
1644 become_root();
1645 load_registry_shares();
1646 sharecount = load_usershare_shares();
1647 unbecome_root();
1649 for(i=0;i < sharecount;i++) {
1650 if(lp_msdfs_root(i)) {
1651 jn_count += count_dfs_links(ctx, i);
1654 if (jn_count == 0) {
1655 return NULL;
1657 jn = TALLOC_ARRAY(ctx, struct junction_map, jn_count);
1658 if (!jn) {
1659 return NULL;
1661 for(i=0; i < sharecount; i++) {
1662 if (*p_num_jn >= jn_count) {
1663 break;
1665 if(lp_msdfs_root(i)) {
1666 *p_num_jn += form_junctions(ctx, i,
1667 &jn[*p_num_jn],
1668 jn_count - *p_num_jn);
1671 return jn;
1674 /******************************************************************************
1675 Core function to resolve a dfs pathname.
1676 ******************************************************************************/
1678 NTSTATUS resolve_dfspath(TALLOC_CTX *ctx,
1679 connection_struct *conn,
1680 bool dfs_pathnames,
1681 const char *name_in,
1682 char **pp_name_out)
1684 NTSTATUS status = NT_STATUS_OK;
1685 bool dummy;
1686 if (dfs_pathnames) {
1687 status = dfs_redirect(ctx,
1688 conn,
1689 name_in,
1690 False,
1691 pp_name_out,
1692 &dummy);
1693 } else {
1695 * Cheat and just return a copy of the in ptr.
1696 * Once srvstr_get_path() uses talloc it'll
1697 * be a talloced ptr anyway.
1699 *pp_name_out = CONST_DISCARD(char *,name_in);
1701 return status;
1704 /******************************************************************************
1705 Core function to resolve a dfs pathname possibly containing a wildcard.
1706 This function is identical to the above except for the bool param to
1707 dfs_redirect but I need this to be separate so it's really clear when
1708 we're allowing wildcards and when we're not. JRA.
1709 ******************************************************************************/
1711 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1712 connection_struct *conn,
1713 bool dfs_pathnames,
1714 const char *name_in,
1715 char **pp_name_out,
1716 bool *ppath_contains_wcard)
1718 NTSTATUS status = NT_STATUS_OK;
1719 if (dfs_pathnames) {
1720 status = dfs_redirect(ctx,
1721 conn,
1722 name_in,
1723 True,
1724 pp_name_out,
1725 ppath_contains_wcard);
1726 } else {
1728 * Cheat and just return a copy of the in ptr.
1729 * Once srvstr_get_path() uses talloc it'll
1730 * be a talloced ptr anyway.
1732 *pp_name_out = CONST_DISCARD(char *,name_in);
1734 return status;