Revert "Move user/domain from rpc_pipe_client to cli_pipe_auth_data"
[Samba.git] / source / smbd / msdfs.c
blobfb757a5f7469f76e9385c0ca64de2c0be3f71fa1
1 /*
2 Unix SMB/Netbios implementation.
3 Version 3.0
4 MSDFS services for Samba
5 Copyright (C) Shirish Kalele 2000
6 Copyright (C) Jeremy Allison 2007
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #define DBGC_CLASS DBGC_MSDFS
24 #include "includes.h"
26 extern uint32 global_client_caps;
28 /**********************************************************************
29 Parse a DFS pathname of the form \hostname\service\reqpath
30 into the dfs_path structure.
31 If POSIX pathnames is true, the pathname may also be of the
32 form /hostname/service/reqpath.
33 We cope with either here.
35 Unfortunately, due to broken clients who might set the
36 SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
37 send a local path, we have to cope with that too....
39 This version does everything using pointers within one copy of the
40 pathname string, talloced on the struct dfs_path pointer (which
41 must be talloced). This may be too clever to live....
42 JRA.
43 **********************************************************************/
45 static NTSTATUS parse_dfs_path(const char *pathname,
46 bool allow_wcards,
47 struct dfs_path *pdp, /* MUST BE TALLOCED */
48 bool *ppath_contains_wcard)
50 char *pathname_local;
51 char *p,*temp;
52 char *eos_ptr;
53 NTSTATUS status = NT_STATUS_OK;
54 char sepchar;
56 ZERO_STRUCTP(pdp);
59 * This is the only talloc we should need to do
60 * on the struct dfs_path. All the pointers inside
61 * it should point to offsets within this string.
64 pathname_local = talloc_strdup(pdp, pathname);
65 if (!pathname_local) {
66 return NT_STATUS_NO_MEMORY;
68 /* Get a pointer to the terminating '\0' */
69 eos_ptr = &pathname_local[strlen(pathname_local)];
70 p = temp = pathname_local;
72 pdp->posix_path = (lp_posix_pathnames() && *pathname == '/');
74 sepchar = pdp->posix_path ? '/' : '\\';
76 if (*pathname != sepchar) {
77 DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
78 pathname, sepchar ));
80 * Possibly client sent a local path by mistake.
81 * Try and convert to a local path.
84 pdp->hostname = eos_ptr; /* "" */
85 pdp->servicename = eos_ptr; /* "" */
87 /* We've got no info about separators. */
88 pdp->posix_path = lp_posix_pathnames();
89 p = temp;
90 DEBUG(10,("parse_dfs_path: trying to convert %s to a "
91 "local path\n",
92 temp));
93 goto local_path;
97 * Safe to use on talloc'ed string as it only shrinks.
98 * It also doesn't affect the eos_ptr.
100 trim_char(temp,sepchar,sepchar);
102 DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
103 temp, sepchar));
105 /* Now tokenize. */
106 /* Parse out hostname. */
107 p = strchr_m(temp,sepchar);
108 if(p == NULL) {
109 DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
110 temp));
112 * Possibly client sent a local path by mistake.
113 * Try and convert to a local path.
116 pdp->hostname = eos_ptr; /* "" */
117 pdp->servicename = eos_ptr; /* "" */
119 p = temp;
120 DEBUG(10,("parse_dfs_path: trying to convert %s "
121 "to a local path\n",
122 temp));
123 goto local_path;
125 *p = '\0';
126 pdp->hostname = temp;
128 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
130 /* Parse out servicename. */
131 temp = p+1;
132 p = strchr_m(temp,sepchar);
133 if(p == NULL) {
134 pdp->servicename = temp;
135 pdp->reqpath = eos_ptr; /* "" */
136 return NT_STATUS_OK;
138 *p = '\0';
139 pdp->servicename = temp;
140 DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
142 p++;
144 local_path:
146 *ppath_contains_wcard = False;
148 pdp->reqpath = p;
150 /* Rest is reqpath. */
151 if (pdp->posix_path) {
152 status = check_path_syntax_posix(pdp->reqpath);
153 } else {
154 if (allow_wcards) {
155 status = check_path_syntax_wcard(pdp->reqpath,
156 ppath_contains_wcard);
157 } else {
158 status = check_path_syntax(pdp->reqpath);
162 if (!NT_STATUS_IS_OK(status)) {
163 DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
164 p, nt_errstr(status) ));
165 return status;
168 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
169 return NT_STATUS_OK;
172 /********************************************************
173 Fake up a connection struct for the VFS layer.
174 Note this CHANGES CWD !!!! JRA.
175 *********************************************************/
177 static NTSTATUS create_conn_struct(TALLOC_CTX *ctx,
178 connection_struct *conn,
179 int snum,
180 const char *path)
182 char *connpath;
184 ZERO_STRUCTP(conn);
186 connpath = talloc_strdup(ctx, path);
187 if (!connpath) {
188 return NT_STATUS_NO_MEMORY;
190 connpath = talloc_string_sub(ctx,
191 connpath,
192 "%S",
193 lp_servicename(snum));
194 if (!connpath) {
195 return NT_STATUS_NO_MEMORY;
198 /* needed for smbd_vfs_init() */
200 if ((conn->mem_ctx=talloc_init("connection_struct")) == NULL) {
201 DEBUG(0,("talloc_init(connection_struct) failed!\n"));
202 return NT_STATUS_NO_MEMORY;
205 if (!(conn->params = TALLOC_ZERO_P(conn->mem_ctx,
206 struct share_params))) {
207 DEBUG(0, ("TALLOC failed\n"));
208 return NT_STATUS_NO_MEMORY;
211 conn->params->service = snum;
213 set_conn_connectpath(conn, connpath);
215 if (!smbd_vfs_init(conn)) {
216 NTSTATUS status = map_nt_error_from_unix(errno);
217 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
218 conn_free_internal(conn);
219 return status;
223 * Windows seems to insist on doing trans2getdfsreferral() calls on
224 * the IPC$ share as the anonymous user. If we try to chdir as that
225 * user we will fail.... WTF ? JRA.
228 if (vfs_ChDir(conn,conn->connectpath) != 0) {
229 NTSTATUS status = map_nt_error_from_unix(errno);
230 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
231 "Error was %s\n",
232 conn->connectpath, strerror(errno) ));
233 conn_free_internal(conn);
234 return status;
237 return NT_STATUS_OK;
240 /**********************************************************************
241 Parse the contents of a symlink to verify if it is an msdfs referral
242 A valid referral is of the form:
244 msdfs:server1\share1,server2\share2
245 msdfs:server1\share1\pathname,server2\share2\pathname
246 msdfs:server1/share1,server2/share2
247 msdfs:server1/share1/pathname,server2/share2/pathname.
249 Note that the alternate paths returned here must be of the canonicalized
250 form:
252 \server\share or
253 \server\share\path\to\file,
255 even in posix path mode. This is because we have no knowledge if the
256 server we're referring to understands posix paths.
257 **********************************************************************/
259 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
260 const char *target,
261 struct referral **preflist,
262 int *refcount)
264 char *temp = NULL;
265 char *prot;
266 char **alt_path = NULL;
267 int count = 0, i;
268 struct referral *reflist;
269 char *saveptr;
271 temp = talloc_strdup(ctx, target);
272 if (!temp) {
273 return False;
275 prot = strtok_r(temp, ":", &saveptr);
276 if (!prot) {
277 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
278 return False;
281 alt_path = TALLOC_ARRAY(ctx, char *, MAX_REFERRAL_COUNT);
282 if (!alt_path) {
283 return False;
286 /* parse out the alternate paths */
287 while((count<MAX_REFERRAL_COUNT) &&
288 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
289 count++;
292 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
294 if (count) {
295 reflist = *preflist = TALLOC_ZERO_ARRAY(ctx,
296 struct referral, count);
297 if(reflist == NULL) {
298 TALLOC_FREE(alt_path);
299 return False;
301 } else {
302 reflist = *preflist = NULL;
305 for(i=0;i<count;i++) {
306 char *p;
308 /* Canonicalize link target.
309 * Replace all /'s in the path by a \ */
310 string_replace(alt_path[i], '/', '\\');
312 /* Remove leading '\\'s */
313 p = alt_path[i];
314 while (*p && (*p == '\\')) {
315 p++;
318 reflist[i].alternate_path = talloc_asprintf(ctx,
319 "\\%s",
321 if (!reflist[i].alternate_path) {
322 return False;
325 reflist[i].proximity = 0;
326 reflist[i].ttl = REFERRAL_TTL;
327 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
328 reflist[i].alternate_path));
329 *refcount += 1;
332 TALLOC_FREE(alt_path);
333 return True;
336 /**********************************************************************
337 Returns true if the unix path is a valid msdfs symlink and also
338 returns the target string from inside the link.
339 **********************************************************************/
341 static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
342 connection_struct *conn,
343 const char *path,
344 char **pp_link_target,
345 SMB_STRUCT_STAT *sbufp)
347 SMB_STRUCT_STAT st;
348 int referral_len = 0;
349 char link_target_buf[7];
350 size_t bufsize = 0;
351 char *link_target = NULL;
353 if (pp_link_target) {
354 bufsize = 1024;
355 link_target = TALLOC_ARRAY(ctx, char, bufsize);
356 if (!link_target) {
357 return False;
359 *pp_link_target = link_target;
360 } else {
361 bufsize = sizeof(link_target_buf);
362 link_target = link_target_buf;
365 if (sbufp == NULL) {
366 sbufp = &st;
369 if (SMB_VFS_LSTAT(conn, path, sbufp) != 0) {
370 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
371 path));
372 goto err;
375 if (!S_ISLNK(sbufp->st_mode)) {
376 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
377 path));
378 goto err;
381 referral_len = SMB_VFS_READLINK(conn, path, link_target, bufsize - 1);
382 if (referral_len == -1) {
383 DEBUG(0,("is_msdfs_link_read_target: Error reading "
384 "msdfs link %s: %s\n",
385 path, strerror(errno)));
386 goto err;
388 link_target[referral_len] = '\0';
390 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path,
391 link_target));
393 if (!strnequal(link_target, "msdfs:", 6)) {
394 goto err;
396 return True;
398 err:
400 if (link_target != link_target_buf) {
401 TALLOC_FREE(link_target);
403 return False;
406 /**********************************************************************
407 Returns true if the unix path is a valid msdfs symlink.
408 **********************************************************************/
410 bool is_msdfs_link(connection_struct *conn,
411 const char *path,
412 SMB_STRUCT_STAT *sbufp)
414 return is_msdfs_link_internal(talloc_tos(),
415 conn,
416 path,
417 NULL,
418 sbufp);
421 /*****************************************************************
422 Used by other functions to decide if a dfs path is remote,
423 and to get the list of referred locations for that remote path.
425 search_flag: For findfirsts, dfs links themselves are not
426 redirected, but paths beyond the links are. For normal smb calls,
427 even dfs links need to be redirected.
429 consumedcntp: how much of the dfs path is being redirected. the client
430 should try the remaining path on the redirected server.
432 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
433 link redirect are in targetpath.
434 *****************************************************************/
436 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
437 connection_struct *conn,
438 const char *dfspath, /* Incoming complete dfs path */
439 const struct dfs_path *pdp, /* Parsed out
440 server+share+extrapath. */
441 bool search_flag, /* Called from a findfirst ? */
442 int *consumedcntp,
443 char **pp_targetpath)
445 char *p = NULL;
446 char *q = NULL;
447 SMB_STRUCT_STAT sbuf;
448 NTSTATUS status;
449 char *localpath = NULL;
450 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
451 components). */
453 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
454 conn->connectpath, pdp->reqpath));
457 * Note the unix path conversion here we're doing we can
458 * throw away. We're looking for a symlink for a dfs
459 * resolution, if we don't find it we'll do another
460 * unix_convert later in the codepath.
461 * If we needed to remember what we'd resolved in
462 * dp->reqpath (as the original code did) we'd
463 * copy (localhost, dp->reqpath) on any code
464 * path below that returns True - but I don't
465 * think this is needed. JRA.
468 status = unix_convert(ctx, conn, pdp->reqpath, search_flag, &localpath,
469 NULL, &sbuf);
470 if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status,
471 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
472 return status;
475 /* Optimization - check if we can redirect the whole path. */
477 if (is_msdfs_link_internal(ctx, conn, localpath, pp_targetpath, NULL)) {
478 if (search_flag) {
479 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
480 "for dfs link %s.\n", dfspath));
481 return NT_STATUS_OK;
484 DEBUG(6,("dfs_path_lookup: %s resolves to a "
485 "valid dfs link %s.\n", dfspath,
486 pp_targetpath ? *pp_targetpath : ""));
488 if (consumedcntp) {
489 *consumedcntp = strlen(dfspath);
491 return NT_STATUS_PATH_NOT_COVERED;
494 /* Prepare to test only for '/' components in the given path,
495 * so if a Windows path replace all '\\' characters with '/'.
496 * For a POSIX DFS path we know all separators are already '/'. */
498 canon_dfspath = talloc_strdup(ctx, dfspath);
499 if (!canon_dfspath) {
500 return NT_STATUS_NO_MEMORY;
502 if (!pdp->posix_path) {
503 string_replace(canon_dfspath, '\\', '/');
507 * localpath comes out of unix_convert, so it has
508 * no trailing backslash. Make sure that canon_dfspath hasn't either.
509 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
512 trim_char(canon_dfspath,0,'/');
515 * Redirect if any component in the path is a link.
516 * We do this by walking backwards through the
517 * local path, chopping off the last component
518 * in both the local path and the canonicalized
519 * DFS path. If we hit a DFS link then we're done.
522 p = strrchr_m(localpath, '/');
523 if (consumedcntp) {
524 q = strrchr_m(canon_dfspath, '/');
527 while (p) {
528 *p = '\0';
529 if (q) {
530 *q = '\0';
533 if (is_msdfs_link_internal(ctx, conn,
534 localpath, pp_targetpath, NULL)) {
535 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
536 "parent %s is dfs link\n", dfspath, localpath));
538 if (consumedcntp) {
539 *consumedcntp = strlen(canon_dfspath);
540 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
541 "(%d)\n",
542 canon_dfspath,
543 *consumedcntp));
546 return NT_STATUS_PATH_NOT_COVERED;
549 /* Step back on the filesystem. */
550 p = strrchr_m(localpath, '/');
552 if (consumedcntp) {
553 /* And in the canonicalized dfs path. */
554 q = strrchr_m(canon_dfspath, '/');
558 return NT_STATUS_OK;
561 /*****************************************************************
562 Decides if a dfs pathname should be redirected or not.
563 If not, the pathname is converted to a tcon-relative local unix path
565 search_wcard_flag: this flag performs 2 functions both related
566 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
567 for details.
569 This function can return NT_STATUS_OK, meaning use the returned path as-is
570 (mapped into a local path).
571 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
572 any other NT_STATUS error which is a genuine error to be
573 returned to the client.
574 *****************************************************************/
576 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
577 connection_struct *conn,
578 const char *path_in,
579 bool search_wcard_flag,
580 char **pp_path_out,
581 bool *ppath_contains_wcard)
583 NTSTATUS status;
584 struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
586 if (!pdp) {
587 return NT_STATUS_NO_MEMORY;
590 status = parse_dfs_path(path_in, search_wcard_flag, pdp,
591 ppath_contains_wcard);
592 if (!NT_STATUS_IS_OK(status)) {
593 TALLOC_FREE(pdp);
594 return status;
597 if (pdp->reqpath[0] == '\0') {
598 TALLOC_FREE(pdp);
599 *pp_path_out = talloc_strdup(ctx, "");
600 if (!*pp_path_out) {
601 return NT_STATUS_NO_MEMORY;
603 DEBUG(5,("dfs_redirect: self-referral.\n"));
604 return NT_STATUS_OK;
607 /* If dfs pathname for a non-dfs share, convert to tcon-relative
608 path and return OK */
610 if (!lp_msdfs_root(SNUM(conn))) {
611 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
612 TALLOC_FREE(pdp);
613 if (!*pp_path_out) {
614 return NT_STATUS_NO_MEMORY;
616 return NT_STATUS_OK;
619 /* If it looked like a local path (zero hostname/servicename)
620 * just treat as a tcon-relative path. */
622 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
623 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
624 TALLOC_FREE(pdp);
625 if (!*pp_path_out) {
626 return NT_STATUS_NO_MEMORY;
628 return NT_STATUS_OK;
631 if (!( strequal(pdp->servicename, lp_servicename(SNUM(conn)))
632 || (strequal(pdp->servicename, HOMES_NAME)
633 && strequal(lp_servicename(SNUM(conn)),
634 get_current_username()) )) ) {
636 /* The given sharename doesn't match this connection. */
637 TALLOC_FREE(pdp);
639 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
642 status = dfs_path_lookup(ctx, conn, path_in, pdp,
643 search_wcard_flag, NULL, NULL);
644 if (!NT_STATUS_IS_OK(status)) {
645 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
646 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
647 } else {
648 DEBUG(10,("dfs_redirect: dfs_path_lookup "
649 "failed for %s with %s\n",
650 path_in, nt_errstr(status) ));
652 return status;
655 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
657 /* Form non-dfs tcon-relative path */
658 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
659 TALLOC_FREE(pdp);
660 if (!*pp_path_out) {
661 return NT_STATUS_NO_MEMORY;
664 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
665 path_in,
666 *pp_path_out));
668 return NT_STATUS_OK;
671 /**********************************************************************
672 Return a self referral.
673 **********************************************************************/
675 static NTSTATUS self_ref(TALLOC_CTX *ctx,
676 const char *dfs_path,
677 struct junction_map *jucn,
678 int *consumedcntp,
679 bool *self_referralp)
681 struct referral *ref;
683 *self_referralp = True;
685 jucn->referral_count = 1;
686 if((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
687 return NT_STATUS_NO_MEMORY;
690 ref->alternate_path = talloc_strdup(ctx, dfs_path);
691 if (!ref->alternate_path) {
692 return NT_STATUS_NO_MEMORY;
694 ref->proximity = 0;
695 ref->ttl = REFERRAL_TTL;
696 jucn->referral_list = ref;
697 *consumedcntp = strlen(dfs_path);
698 return NT_STATUS_OK;
701 /**********************************************************************
702 Gets valid referrals for a dfs path and fills up the
703 junction_map structure.
704 **********************************************************************/
706 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
707 const char *dfs_path,
708 struct junction_map *jucn,
709 int *consumedcntp,
710 bool *self_referralp)
712 struct connection_struct conns;
713 struct connection_struct *conn = &conns;
714 char *targetpath = NULL;
715 int snum;
716 NTSTATUS status = NT_STATUS_NOT_FOUND;
717 bool dummy;
718 struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
720 if (!pdp) {
721 return NT_STATUS_NO_MEMORY;
724 ZERO_STRUCT(conns);
725 *self_referralp = False;
727 status = parse_dfs_path(dfs_path, False, pdp, &dummy);
728 if (!NT_STATUS_IS_OK(status)) {
729 return status;
732 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
733 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
734 if (!jucn->service_name || !jucn->volume_name) {
735 TALLOC_FREE(pdp);
736 return NT_STATUS_NO_MEMORY;
739 /* Verify the share is a dfs root */
740 snum = lp_servicenumber(jucn->service_name);
741 if(snum < 0) {
742 fstring service_name;
743 fstrcpy(service_name, jucn->service_name);
744 if ((snum = find_service(service_name)) < 0) {
745 return NT_STATUS_NOT_FOUND;
747 TALLOC_FREE(jucn->service_name);
748 jucn->service_name = talloc_strdup(ctx, service_name);
749 if (!jucn->service_name) {
750 TALLOC_FREE(pdp);
751 return NT_STATUS_NO_MEMORY;
755 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(snum) == '\0')) {
756 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
757 "a dfs root.\n",
758 pdp->servicename, dfs_path));
759 TALLOC_FREE(pdp);
760 return NT_STATUS_NOT_FOUND;
764 * Self referrals are tested with a anonymous IPC connection and
765 * a GET_DFS_REFERRAL call to \\server\share. (which means
766 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
767 * into the directory and will fail if it cannot (as the anonymous
768 * user). Cope with this.
771 if (pdp->reqpath[0] == '\0') {
772 char *tmp;
773 struct referral *ref;
775 if (*lp_msdfs_proxy(snum) == '\0') {
776 TALLOC_FREE(pdp);
777 return self_ref(ctx,
778 dfs_path,
779 jucn,
780 consumedcntp,
781 self_referralp);
785 * It's an msdfs proxy share. Redirect to
786 * the configured target share.
789 jucn->referral_count = 1;
790 if ((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
791 TALLOC_FREE(pdp);
792 return NT_STATUS_NO_MEMORY;
795 if (!(tmp = talloc_strdup(ctx, lp_msdfs_proxy(snum)))) {
796 TALLOC_FREE(pdp);
797 return NT_STATUS_NO_MEMORY;
800 trim_string(tmp, "\\", 0);
802 ref->alternate_path = talloc_asprintf(ctx, "\\%s", tmp);
803 TALLOC_FREE(tmp);
805 if (!ref->alternate_path) {
806 TALLOC_FREE(pdp);
807 return NT_STATUS_NO_MEMORY;
810 if (pdp->reqpath[0] != '\0') {
811 ref->alternate_path = talloc_asprintf_append(
812 ref->alternate_path,
813 "%s",
814 pdp->reqpath);
815 if (!ref->alternate_path) {
816 TALLOC_FREE(pdp);
817 return NT_STATUS_NO_MEMORY;
820 ref->proximity = 0;
821 ref->ttl = REFERRAL_TTL;
822 jucn->referral_list = ref;
823 *consumedcntp = strlen(dfs_path);
824 TALLOC_FREE(pdp);
825 return NT_STATUS_OK;
828 status = create_conn_struct(ctx, conn, snum, lp_pathname(snum));
829 if (!NT_STATUS_IS_OK(status)) {
830 TALLOC_FREE(pdp);
831 return status;
834 /* If this is a DFS path dfs_lookup should return
835 * NT_STATUS_PATH_NOT_COVERED. */
837 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
838 False, consumedcntp, &targetpath);
840 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
841 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
842 dfs_path));
843 conn_free_internal(conn);
844 TALLOC_FREE(pdp);
845 return status;
848 /* We know this is a valid dfs link. Parse the targetpath. */
849 if (!parse_msdfs_symlink(ctx, targetpath,
850 &jucn->referral_list,
851 &jucn->referral_count)) {
852 DEBUG(3,("get_referred_path: failed to parse symlink "
853 "target %s\n", targetpath ));
854 conn_free_internal(conn);
855 TALLOC_FREE(pdp);
856 return NT_STATUS_NOT_FOUND;
859 conn_free_internal(conn);
860 TALLOC_FREE(pdp);
861 return NT_STATUS_OK;
864 static int setup_ver2_dfs_referral(const char *pathname,
865 char **ppdata,
866 struct junction_map *junction,
867 int consumedcnt,
868 bool self_referral)
870 char* pdata = *ppdata;
872 smb_ucs2_t *uni_requestedpath = NULL;
873 int uni_reqpathoffset1,uni_reqpathoffset2;
874 int uni_curroffset;
875 int requestedpathlen=0;
876 int offset;
877 int reply_size = 0;
878 int i=0;
880 DEBUG(10,("Setting up version2 referral\nRequested path:\n"));
882 requestedpathlen = rpcstr_push_talloc(talloc_tos(),
883 &uni_requestedpath, pathname);
884 if (uni_requestedpath == NULL || requestedpathlen == 0) {
885 return -1;
888 if (DEBUGLVL(10)) {
889 dump_data(0, (unsigned char *)uni_requestedpath,
890 requestedpathlen);
893 DEBUG(10,("ref count = %u\n",junction->referral_count));
895 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
896 VERSION2_REFERRAL_SIZE * junction->referral_count;
898 uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen;
900 uni_curroffset = uni_reqpathoffset2 + requestedpathlen;
902 reply_size = REFERRAL_HEADER_SIZE +
903 VERSION2_REFERRAL_SIZE*junction->referral_count +
904 2 * requestedpathlen;
905 DEBUG(10,("reply_size: %u\n",reply_size));
907 /* add up the unicode lengths of all the referral paths */
908 for(i=0;i<junction->referral_count;i++) {
909 DEBUG(10,("referral %u : %s\n",
911 junction->referral_list[i].alternate_path));
912 reply_size +=
913 (strlen(junction->referral_list[i].alternate_path)+1)*2;
916 DEBUG(10,("reply_size = %u\n",reply_size));
917 /* add the unexplained 0x16 bytes */
918 reply_size += 0x16;
920 pdata = (char *)SMB_REALLOC(pdata,reply_size);
921 if(pdata == NULL) {
922 DEBUG(0,("Realloc failed!\n"));
923 return -1;
925 *ppdata = pdata;
927 /* copy in the dfs requested paths.. required for offset calculations */
928 memcpy(pdata+uni_reqpathoffset1,uni_requestedpath,requestedpathlen);
929 memcpy(pdata+uni_reqpathoffset2,uni_requestedpath,requestedpathlen);
931 /* create the header */
932 SSVAL(pdata,0,consumedcnt * 2); /* path consumed */
933 /* number of referral in this pkt */
934 SSVAL(pdata,2,junction->referral_count);
935 if(self_referral) {
936 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
937 } else {
938 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
941 offset = 8;
942 /* add the referral elements */
943 for(i=0;i<junction->referral_count;i++) {
944 struct referral* ref = &junction->referral_list[i];
945 int unilen;
947 SSVAL(pdata,offset,2); /* version 2 */
948 SSVAL(pdata,offset+2,VERSION2_REFERRAL_SIZE);
949 if(self_referral) {
950 SSVAL(pdata,offset+4,1);
951 } else {
952 SSVAL(pdata,offset+4,0);
955 /* ref_flags :use path_consumed bytes? */
956 SSVAL(pdata,offset+6,0);
957 SIVAL(pdata,offset+8,ref->proximity);
958 SIVAL(pdata,offset+12,ref->ttl);
960 SSVAL(pdata,offset+16,uni_reqpathoffset1-offset);
961 SSVAL(pdata,offset+18,uni_reqpathoffset2-offset);
962 /* copy referred path into current offset */
963 unilen = rpcstr_push(pdata+uni_curroffset,
964 ref->alternate_path,
965 reply_size - uni_curroffset,
966 STR_UNICODE);
968 SSVAL(pdata,offset+20,uni_curroffset-offset);
970 uni_curroffset += unilen;
971 offset += VERSION2_REFERRAL_SIZE;
973 /* add in the unexplained 22 (0x16) bytes at the end */
974 memset(pdata+uni_curroffset,'\0',0x16);
975 return reply_size;
978 static int setup_ver3_dfs_referral(const char *pathname,
979 char **ppdata,
980 struct junction_map *junction,
981 int consumedcnt,
982 bool self_referral)
984 char *pdata = *ppdata;
986 smb_ucs2_t *uni_reqpath = NULL;
987 int uni_reqpathoffset1, uni_reqpathoffset2;
988 int uni_curroffset;
989 int reply_size = 0;
991 int reqpathlen = 0;
992 int offset,i=0;
994 DEBUG(10,("setting up version3 referral\n"));
996 reqpathlen = rpcstr_push_talloc(talloc_tos(), &uni_reqpath, pathname);
997 if (uni_reqpath == NULL || reqpathlen == 0) {
998 return -1;
1001 if (DEBUGLVL(10)) {
1002 dump_data(0, (unsigned char *)uni_reqpath,
1003 reqpathlen);
1006 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
1007 VERSION3_REFERRAL_SIZE * junction->referral_count;
1008 uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen;
1009 reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen;
1011 for(i=0;i<junction->referral_count;i++) {
1012 DEBUG(10,("referral %u : %s\n",
1014 junction->referral_list[i].alternate_path));
1015 reply_size +=
1016 (strlen(junction->referral_list[i].alternate_path)+1)*2;
1019 pdata = (char *)SMB_REALLOC(pdata,reply_size);
1020 if(pdata == NULL) {
1021 DEBUG(0,("version3 referral setup:"
1022 "malloc failed for Realloc!\n"));
1023 return -1;
1025 *ppdata = pdata;
1027 /* create the header */
1028 SSVAL(pdata,0,consumedcnt * 2); /* path consumed */
1029 SSVAL(pdata,2,junction->referral_count); /* number of referral */
1030 if(self_referral) {
1031 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
1032 } else {
1033 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
1036 /* copy in the reqpaths */
1037 memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen);
1038 memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen);
1040 offset = 8;
1041 for(i=0;i<junction->referral_count;i++) {
1042 struct referral* ref = &(junction->referral_list[i]);
1043 int unilen;
1045 SSVAL(pdata,offset,3); /* version 3 */
1046 SSVAL(pdata,offset+2,VERSION3_REFERRAL_SIZE);
1047 if(self_referral) {
1048 SSVAL(pdata,offset+4,1);
1049 } else {
1050 SSVAL(pdata,offset+4,0);
1053 /* ref_flags :use path_consumed bytes? */
1054 SSVAL(pdata,offset+6,0);
1055 SIVAL(pdata,offset+8,ref->ttl);
1057 SSVAL(pdata,offset+12,uni_reqpathoffset1-offset);
1058 SSVAL(pdata,offset+14,uni_reqpathoffset2-offset);
1059 /* copy referred path into current offset */
1060 unilen = rpcstr_push(pdata+uni_curroffset,ref->alternate_path,
1061 reply_size - uni_curroffset,
1062 STR_UNICODE | STR_TERMINATE);
1063 SSVAL(pdata,offset+16,uni_curroffset-offset);
1064 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
1065 memset(pdata+offset+18,'\0',16);
1067 uni_curroffset += unilen;
1068 offset += VERSION3_REFERRAL_SIZE;
1070 return reply_size;
1073 /******************************************************************
1074 Set up the DFS referral for the dfs pathname. This call returns
1075 the amount of the path covered by this server, and where the
1076 client should be redirected to. This is the meat of the
1077 TRANS2_GET_DFS_REFERRAL call.
1078 ******************************************************************/
1080 int setup_dfs_referral(connection_struct *orig_conn,
1081 const char *dfs_path,
1082 int max_referral_level,
1083 char **ppdata, NTSTATUS *pstatus)
1085 struct junction_map *junction = NULL;
1086 int consumedcnt = 0;
1087 bool self_referral = False;
1088 int reply_size = 0;
1089 char *pathnamep = NULL;
1090 char *local_dfs_path = NULL;
1091 TALLOC_CTX *ctx;
1093 if (!(ctx=talloc_init("setup_dfs_referral"))) {
1094 *pstatus = NT_STATUS_NO_MEMORY;
1095 return -1;
1098 /* get the junction entry */
1099 if (!dfs_path) {
1100 talloc_destroy(ctx);
1101 *pstatus = NT_STATUS_NOT_FOUND;
1102 return -1;
1106 * Trim pathname sent by client so it begins with only one backslash.
1107 * Two backslashes confuse some dfs clients
1110 local_dfs_path = talloc_strdup(ctx,dfs_path);
1111 if (!local_dfs_path) {
1112 *pstatus = NT_STATUS_NO_MEMORY;
1113 talloc_destroy(ctx);
1114 return -1;
1116 pathnamep = local_dfs_path;
1117 while (IS_DIRECTORY_SEP(pathnamep[0]) &&
1118 IS_DIRECTORY_SEP(pathnamep[1])) {
1119 pathnamep++;
1122 junction = TALLOC_ZERO_P(ctx, struct junction_map);
1123 if (!junction) {
1124 *pstatus = NT_STATUS_NO_MEMORY;
1125 talloc_destroy(ctx);
1126 return -1;
1129 /* The following call can change cwd. */
1130 *pstatus = get_referred_path(ctx, pathnamep, junction,
1131 &consumedcnt, &self_referral);
1132 if (!NT_STATUS_IS_OK(*pstatus)) {
1133 vfs_ChDir(orig_conn,orig_conn->connectpath);
1134 talloc_destroy(ctx);
1135 return -1;
1137 vfs_ChDir(orig_conn,orig_conn->connectpath);
1139 if (!self_referral) {
1140 pathnamep[consumedcnt] = '\0';
1142 if( DEBUGLVL( 3 ) ) {
1143 int i=0;
1144 dbgtext("setup_dfs_referral: Path %s to "
1145 "alternate path(s):",
1146 pathnamep);
1147 for(i=0;i<junction->referral_count;i++)
1148 dbgtext(" %s",
1149 junction->referral_list[i].alternate_path);
1150 dbgtext(".\n");
1154 /* create the referral depeding on version */
1155 DEBUG(10,("max_referral_level :%d\n",max_referral_level));
1157 if (max_referral_level < 2) {
1158 max_referral_level = 2;
1160 if (max_referral_level > 3) {
1161 max_referral_level = 3;
1164 switch(max_referral_level) {
1165 case 2:
1166 reply_size = setup_ver2_dfs_referral(pathnamep,
1167 ppdata, junction,
1168 consumedcnt, self_referral);
1169 break;
1170 case 3:
1171 reply_size = setup_ver3_dfs_referral(pathnamep, ppdata,
1172 junction, consumedcnt, self_referral);
1173 break;
1174 default:
1175 DEBUG(0,("setup_dfs_referral: Invalid dfs referral "
1176 "version: %d\n",
1177 max_referral_level));
1178 talloc_destroy(ctx);
1179 *pstatus = NT_STATUS_INVALID_LEVEL;
1180 return -1;
1183 if (DEBUGLVL(10)) {
1184 DEBUGADD(0,("DFS Referral pdata:\n"));
1185 dump_data(0,(uint8 *)*ppdata,reply_size);
1188 talloc_destroy(ctx);
1189 *pstatus = NT_STATUS_OK;
1190 return reply_size;
1193 /**********************************************************************
1194 The following functions are called by the NETDFS RPC pipe functions
1195 **********************************************************************/
1197 /*********************************************************************
1198 Creates a junction structure from a DFS pathname
1199 **********************************************************************/
1201 bool create_junction(TALLOC_CTX *ctx,
1202 const char *dfs_path,
1203 struct junction_map *jucn)
1205 int snum;
1206 bool dummy;
1207 struct dfs_path *pdp = TALLOC_P(ctx,struct dfs_path);
1208 NTSTATUS status;
1210 if (!pdp) {
1211 return False;
1213 status = parse_dfs_path(dfs_path, False, pdp, &dummy);
1214 if (!NT_STATUS_IS_OK(status)) {
1215 return False;
1218 /* check if path is dfs : validate first token */
1219 if (!is_myname_or_ipaddr(pdp->hostname)) {
1220 DEBUG(4,("create_junction: Invalid hostname %s "
1221 "in dfs path %s\n",
1222 pdp->hostname, dfs_path));
1223 TALLOC_FREE(pdp);
1224 return False;
1227 /* Check for a non-DFS share */
1228 snum = lp_servicenumber(pdp->servicename);
1230 if(snum < 0 || !lp_msdfs_root(snum)) {
1231 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1232 pdp->servicename));
1233 TALLOC_FREE(pdp);
1234 return False;
1237 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1238 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1239 jucn->comment = talloc_strdup(ctx, lp_comment(snum));
1241 TALLOC_FREE(pdp);
1242 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1243 return False;
1245 return True;
1248 /**********************************************************************
1249 Forms a valid Unix pathname from the junction
1250 **********************************************************************/
1252 static bool junction_to_local_path(const struct junction_map *jucn,
1253 char **pp_path_out,
1254 connection_struct *conn_out)
1256 int snum;
1258 snum = lp_servicenumber(jucn->service_name);
1259 if(snum < 0) {
1260 return False;
1262 if (!NT_STATUS_IS_OK(create_conn_struct(talloc_tos(),
1263 conn_out, snum,
1264 lp_pathname(snum)))) {
1265 return False;
1268 *pp_path_out = talloc_asprintf(conn_out->mem_ctx,
1269 "%s/%s",
1270 lp_pathname(snum),
1271 jucn->volume_name);
1272 if (!*pp_path_out) {
1273 return False;
1275 return True;
1278 bool create_msdfs_link(const struct junction_map *jucn,
1279 bool exists)
1281 char *path = NULL;
1282 char *msdfs_link = NULL;
1283 connection_struct conns;
1284 connection_struct *conn = &conns;
1285 int i=0;
1286 bool insert_comma = False;
1287 bool ret = False;
1289 ZERO_STRUCT(conns);
1291 if(!junction_to_local_path(jucn, &path, conn)) {
1292 return False;
1295 /* Form the msdfs_link contents */
1296 msdfs_link = talloc_strdup(conn->mem_ctx, "msdfs:");
1297 if (!msdfs_link) {
1298 goto out;
1300 for(i=0; i<jucn->referral_count; i++) {
1301 char *refpath = jucn->referral_list[i].alternate_path;
1303 /* Alternate paths always use Windows separators. */
1304 trim_char(refpath, '\\', '\\');
1305 if(*refpath == '\0') {
1306 if (i == 0) {
1307 insert_comma = False;
1309 continue;
1311 if (i > 0 && insert_comma) {
1312 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1313 ",%s",
1314 refpath);
1315 } else {
1316 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1317 "%s",
1318 refpath);
1321 if (!msdfs_link) {
1322 goto out;
1324 if (!insert_comma) {
1325 insert_comma = True;
1329 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1330 path, msdfs_link));
1332 if(exists) {
1333 if(SMB_VFS_UNLINK(conn,path)!=0) {
1334 goto out;
1338 if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1339 DEBUG(1,("create_msdfs_link: symlink failed "
1340 "%s -> %s\nError: %s\n",
1341 path, msdfs_link, strerror(errno)));
1342 goto out;
1345 ret = True;
1347 out:
1349 conn_free_internal(conn);
1350 return ret;
1353 bool remove_msdfs_link(const struct junction_map *jucn)
1355 char *path = NULL;
1356 connection_struct conns;
1357 connection_struct *conn = &conns;
1358 bool ret = False;
1360 ZERO_STRUCT(conns);
1362 if( junction_to_local_path(jucn, &path, conn) ) {
1363 if( SMB_VFS_UNLINK(conn, path) == 0 ) {
1364 ret = True;
1368 conn_free_internal(conn);
1369 return ret;
1372 /*********************************************************************
1373 Return the number of DFS links at the root of this share.
1374 *********************************************************************/
1376 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1378 size_t cnt = 0;
1379 SMB_STRUCT_DIR *dirp = NULL;
1380 char *dname = NULL;
1381 const char *connect_path = lp_pathname(snum);
1382 const char *msdfs_proxy = lp_msdfs_proxy(snum);
1383 connection_struct conn;
1385 ZERO_STRUCT(conn);
1387 if(*connect_path == '\0') {
1388 return 0;
1392 * Fake up a connection struct for the VFS layer.
1395 if (!NT_STATUS_IS_OK(create_conn_struct(talloc_tos(),
1396 &conn, snum, connect_path))) {
1397 return 0;
1400 /* Count a link for the msdfs root - convention */
1401 cnt = 1;
1403 /* No more links if this is an msdfs proxy. */
1404 if (*msdfs_proxy != '\0') {
1405 goto out;
1408 /* Now enumerate all dfs links */
1409 dirp = SMB_VFS_OPENDIR(&conn, ".", NULL, 0);
1410 if(!dirp) {
1411 goto out;
1414 while ((dname = vfs_readdirname(&conn, dirp)) != NULL) {
1415 if (is_msdfs_link(&conn,
1416 dname,
1417 NULL)) {
1418 cnt++;
1422 SMB_VFS_CLOSEDIR(&conn,dirp);
1424 out:
1426 conn_free_internal(&conn);
1427 return cnt;
1430 /*********************************************************************
1431 *********************************************************************/
1433 static int form_junctions(TALLOC_CTX *ctx,
1434 int snum,
1435 struct junction_map *jucn,
1436 size_t jn_remain)
1438 size_t cnt = 0;
1439 SMB_STRUCT_DIR *dirp = NULL;
1440 char *dname = NULL;
1441 const char *connect_path = lp_pathname(snum);
1442 char *service_name = lp_servicename(snum);
1443 const char *msdfs_proxy = lp_msdfs_proxy(snum);
1444 connection_struct conn;
1445 struct referral *ref = NULL;
1447 ZERO_STRUCT(conn);
1449 if (jn_remain == 0) {
1450 return 0;
1453 if(*connect_path == '\0') {
1454 return 0;
1458 * Fake up a connection struct for the VFS layer.
1461 if (!NT_STATUS_IS_OK(create_conn_struct(ctx, &conn, snum, connect_path))) {
1462 return 0;
1465 /* form a junction for the msdfs root - convention
1466 DO NOT REMOVE THIS: NT clients will not work with us
1467 if this is not present
1469 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1470 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1471 if (!jucn[cnt].service_name || jucn[cnt].volume_name) {
1472 goto out;
1474 jucn[cnt].referral_count = 1;
1476 ref = jucn[cnt].referral_list = TALLOC_ZERO_P(ctx, struct referral);
1477 if (jucn[cnt].referral_list == NULL) {
1478 goto out;
1481 ref->proximity = 0;
1482 ref->ttl = REFERRAL_TTL;
1483 if (*msdfs_proxy != '\0') {
1484 ref->alternate_path = talloc_strdup(ctx,
1485 msdfs_proxy);
1486 } else {
1487 ref->alternate_path = talloc_asprintf(ctx,
1488 "\\\\%s\\%s",
1489 get_local_machine_name(),
1490 service_name);
1493 if (!ref->alternate_path) {
1494 goto out;
1496 cnt++;
1498 /* Don't enumerate if we're an msdfs proxy. */
1499 if (*msdfs_proxy != '\0') {
1500 goto out;
1503 /* Now enumerate all dfs links */
1504 dirp = SMB_VFS_OPENDIR(&conn, ".", NULL, 0);
1505 if(!dirp) {
1506 goto out;
1509 while ((dname = vfs_readdirname(&conn, dirp)) != NULL) {
1510 char *link_target = NULL;
1511 if (cnt >= jn_remain) {
1512 SMB_VFS_CLOSEDIR(&conn,dirp);
1513 DEBUG(2, ("form_junctions: ran out of MSDFS "
1514 "junction slots"));
1515 goto out;
1517 if (is_msdfs_link_internal(ctx,
1518 &conn,
1519 dname, &link_target,
1520 NULL)) {
1521 if (parse_msdfs_symlink(ctx,
1522 link_target,
1523 &jucn[cnt].referral_list,
1524 &jucn[cnt].referral_count)) {
1526 jucn[cnt].service_name = talloc_strdup(ctx,
1527 service_name);
1528 jucn[cnt].volume_name = talloc_strdup(ctx,
1529 dname);
1530 if (!jucn[cnt].service_name ||
1531 !jucn[cnt].volume_name) {
1532 goto out;
1534 cnt++;
1539 out:
1541 if (dirp) {
1542 SMB_VFS_CLOSEDIR(&conn,dirp);
1545 conn_free_internal(&conn);
1546 return cnt;
1549 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1551 struct junction_map *jn = NULL;
1552 int i=0;
1553 size_t jn_count = 0;
1554 int sharecount = 0;
1556 *p_num_jn = 0;
1557 if(!lp_host_msdfs()) {
1558 return NULL;
1561 /* Ensure all the usershares are loaded. */
1562 become_root();
1563 load_registry_shares();
1564 sharecount = load_usershare_shares();
1565 unbecome_root();
1567 for(i=0;i < sharecount;i++) {
1568 if(lp_msdfs_root(i)) {
1569 jn_count += count_dfs_links(ctx, i);
1572 if (jn_count == 0) {
1573 return NULL;
1575 jn = TALLOC_ARRAY(ctx, struct junction_map, jn_count);
1576 if (!jn) {
1577 return NULL;
1579 for(i=0; i < sharecount; i++) {
1580 if (*p_num_jn >= jn_count) {
1581 break;
1583 if(lp_msdfs_root(i)) {
1584 *p_num_jn += form_junctions(ctx, i,
1585 &jn[*p_num_jn],
1586 jn_count - *p_num_jn);
1589 return jn;
1592 /******************************************************************************
1593 Core function to resolve a dfs pathname.
1594 ******************************************************************************/
1596 NTSTATUS resolve_dfspath(TALLOC_CTX *ctx,
1597 connection_struct *conn,
1598 bool dfs_pathnames,
1599 const char *name_in,
1600 char **pp_name_out)
1602 NTSTATUS status = NT_STATUS_OK;
1603 bool dummy;
1604 if (dfs_pathnames) {
1605 status = dfs_redirect(ctx,
1606 conn,
1607 name_in,
1608 False,
1609 pp_name_out,
1610 &dummy);
1611 } else {
1613 * Cheat and just return a copy of the in ptr.
1614 * Once srvstr_get_path() uses talloc it'll
1615 * be a talloced ptr anyway.
1617 *pp_name_out = CONST_DISCARD(char *,name_in);
1619 return status;
1622 /******************************************************************************
1623 Core function to resolve a dfs pathname possibly containing a wildcard.
1624 This function is identical to the above except for the bool param to
1625 dfs_redirect but I need this to be separate so it's really clear when
1626 we're allowing wildcards and when we're not. JRA.
1627 ******************************************************************************/
1629 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1630 connection_struct *conn,
1631 bool dfs_pathnames,
1632 const char *name_in,
1633 char **pp_name_out,
1634 bool *ppath_contains_wcard)
1636 NTSTATUS status = NT_STATUS_OK;
1637 if (dfs_pathnames) {
1638 status = dfs_redirect(ctx,
1639 conn,
1640 name_in,
1641 True,
1642 pp_name_out,
1643 ppath_contains_wcard);
1644 } else {
1646 * Cheat and just return a copy of the in ptr.
1647 * Once srvstr_get_path() uses talloc it'll
1648 * be a talloced ptr anyway.
1650 *pp_name_out = CONST_DISCARD(char *,name_in);
1652 return status;