fix build warning.
[Samba.git] / source / smbd / msdfs.c
blobaef4ff66385635027e1a74a33d7b092770a996e5
1 /*
2 Unix SMB/Netbios implementation.
3 Version 3.0
4 MSDFS services for Samba
5 Copyright (C) Shirish Kalele 2000
6 Copyright (C) Jeremy Allison 2007
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #define DBGC_CLASS DBGC_MSDFS
24 #include "includes.h"
26 extern uint32 global_client_caps;
28 /**********************************************************************
29 Parse a DFS pathname of the form \hostname\service\reqpath
30 into the dfs_path structure.
31 If POSIX pathnames is true, the pathname may also be of the
32 form /hostname/service/reqpath.
33 We cope with either here.
35 Unfortunately, due to broken clients who might set the
36 SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
37 send a local path, we have to cope with that too....
39 If conn != NULL then ensure the provided service is
40 the one pointed to by the connection.
42 This version does everything using pointers within one copy of the
43 pathname string, talloced on the struct dfs_path pointer (which
44 must be talloced). This may be too clever to live....
45 JRA.
46 **********************************************************************/
48 static NTSTATUS parse_dfs_path(connection_struct *conn,
49 const char *pathname,
50 bool allow_wcards,
51 struct dfs_path *pdp, /* MUST BE TALLOCED */
52 bool *ppath_contains_wcard)
54 char *pathname_local;
55 char *p,*temp;
56 char *servicename;
57 char *eos_ptr;
58 NTSTATUS status = NT_STATUS_OK;
59 char sepchar;
61 ZERO_STRUCTP(pdp);
64 * This is the only talloc we should need to do
65 * on the struct dfs_path. All the pointers inside
66 * it should point to offsets within this string.
69 pathname_local = talloc_strdup(pdp, pathname);
70 if (!pathname_local) {
71 return NT_STATUS_NO_MEMORY;
73 /* Get a pointer to the terminating '\0' */
74 eos_ptr = &pathname_local[strlen(pathname_local)];
75 p = temp = pathname_local;
77 pdp->posix_path = (lp_posix_pathnames() && *pathname == '/');
79 sepchar = pdp->posix_path ? '/' : '\\';
81 if (*pathname != sepchar) {
82 DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
83 pathname, sepchar ));
85 * Possibly client sent a local path by mistake.
86 * Try and convert to a local path.
89 pdp->hostname = eos_ptr; /* "" */
90 pdp->servicename = eos_ptr; /* "" */
92 /* We've got no info about separators. */
93 pdp->posix_path = lp_posix_pathnames();
94 p = temp;
95 DEBUG(10,("parse_dfs_path: trying to convert %s to a "
96 "local path\n",
97 temp));
98 goto local_path;
102 * Safe to use on talloc'ed string as it only shrinks.
103 * It also doesn't affect the eos_ptr.
105 trim_char(temp,sepchar,sepchar);
107 DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
108 temp, sepchar));
110 /* Now tokenize. */
111 /* Parse out hostname. */
112 p = strchr_m(temp,sepchar);
113 if(p == NULL) {
114 DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
115 temp));
117 * Possibly client sent a local path by mistake.
118 * Try and convert to a local path.
121 pdp->hostname = eos_ptr; /* "" */
122 pdp->servicename = eos_ptr; /* "" */
124 p = temp;
125 DEBUG(10,("parse_dfs_path: trying to convert %s "
126 "to a local path\n",
127 temp));
128 goto local_path;
130 *p = '\0';
131 pdp->hostname = temp;
133 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
135 /* Parse out servicename. */
136 servicename = p+1;
137 p = strchr_m(servicename,sepchar);
138 if (p) {
139 *p = '\0';
142 /* Is this really our servicename ? */
143 if (conn && !( strequal(servicename, lp_servicename(SNUM(conn)))
144 || (strequal(servicename, HOMES_NAME)
145 && strequal(lp_servicename(SNUM(conn)),
146 get_current_username()) )) ) {
147 DEBUG(10,("parse_dfs_path: %s is not our servicename\n",
148 servicename));
151 * Possibly client sent a local path by mistake.
152 * Try and convert to a local path.
155 pdp->hostname = eos_ptr; /* "" */
156 pdp->servicename = eos_ptr; /* "" */
158 /* Repair the path - replace the sepchar's
159 we nulled out */
160 servicename--;
161 *servicename = sepchar;
162 if (p) {
163 *p = sepchar;
166 p = temp;
167 DEBUG(10,("parse_dfs_path: trying to convert %s "
168 "to a local path\n",
169 temp));
170 goto local_path;
173 pdp->servicename = servicename;
175 DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
177 if(p == NULL) {
178 /* Client sent self referral \server\share. */
179 pdp->reqpath = eos_ptr; /* "" */
180 return NT_STATUS_OK;
183 p++;
185 local_path:
187 *ppath_contains_wcard = False;
189 pdp->reqpath = p;
191 /* Rest is reqpath. */
192 if (pdp->posix_path) {
193 status = check_path_syntax_posix(pdp->reqpath);
194 } else {
195 if (allow_wcards) {
196 status = check_path_syntax_wcard(pdp->reqpath,
197 ppath_contains_wcard);
198 } else {
199 status = check_path_syntax(pdp->reqpath);
203 if (!NT_STATUS_IS_OK(status)) {
204 DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
205 p, nt_errstr(status) ));
206 return status;
209 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
210 return NT_STATUS_OK;
213 /********************************************************
214 Fake up a connection struct for the VFS layer.
215 Note this CHANGES CWD !!!! JRA.
216 *********************************************************/
218 static NTSTATUS create_conn_struct(TALLOC_CTX *ctx,
219 connection_struct *conn,
220 int snum,
221 const char *path)
223 char *connpath;
225 ZERO_STRUCTP(conn);
227 connpath = talloc_strdup(ctx, path);
228 if (!connpath) {
229 return NT_STATUS_NO_MEMORY;
231 connpath = talloc_string_sub(ctx,
232 connpath,
233 "%S",
234 lp_servicename(snum));
235 if (!connpath) {
236 return NT_STATUS_NO_MEMORY;
239 /* needed for smbd_vfs_init() */
241 if ((conn->mem_ctx=talloc_init("connection_struct")) == NULL) {
242 DEBUG(0,("talloc_init(connection_struct) failed!\n"));
243 return NT_STATUS_NO_MEMORY;
246 if (!(conn->params = TALLOC_ZERO_P(conn->mem_ctx,
247 struct share_params))) {
248 DEBUG(0, ("TALLOC failed\n"));
249 return NT_STATUS_NO_MEMORY;
252 conn->params->service = snum;
254 set_conn_connectpath(conn, connpath);
256 if (!smbd_vfs_init(conn)) {
257 NTSTATUS status = map_nt_error_from_unix(errno);
258 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
259 conn_free_internal(conn);
260 return status;
264 * Windows seems to insist on doing trans2getdfsreferral() calls on
265 * the IPC$ share as the anonymous user. If we try to chdir as that
266 * user we will fail.... WTF ? JRA.
269 if (vfs_ChDir(conn,conn->connectpath) != 0) {
270 NTSTATUS status = map_nt_error_from_unix(errno);
271 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
272 "Error was %s\n",
273 conn->connectpath, strerror(errno) ));
274 conn_free_internal(conn);
275 return status;
278 return NT_STATUS_OK;
281 /**********************************************************************
282 Parse the contents of a symlink to verify if it is an msdfs referral
283 A valid referral is of the form:
285 msdfs:server1\share1,server2\share2
286 msdfs:server1\share1\pathname,server2\share2\pathname
287 msdfs:server1/share1,server2/share2
288 msdfs:server1/share1/pathname,server2/share2/pathname.
290 Note that the alternate paths returned here must be of the canonicalized
291 form:
293 \server\share or
294 \server\share\path\to\file,
296 even in posix path mode. This is because we have no knowledge if the
297 server we're referring to understands posix paths.
298 **********************************************************************/
300 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
301 const char *target,
302 struct referral **preflist,
303 int *refcount)
305 char *temp = NULL;
306 char *prot;
307 char **alt_path = NULL;
308 int count = 0, i;
309 struct referral *reflist;
310 char *saveptr;
312 temp = talloc_strdup(ctx, target);
313 if (!temp) {
314 return False;
316 prot = strtok_r(temp, ":", &saveptr);
317 if (!prot) {
318 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
319 return False;
322 alt_path = TALLOC_ARRAY(ctx, char *, MAX_REFERRAL_COUNT);
323 if (!alt_path) {
324 return False;
327 /* parse out the alternate paths */
328 while((count<MAX_REFERRAL_COUNT) &&
329 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
330 count++;
333 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
335 if (count) {
336 reflist = *preflist = TALLOC_ZERO_ARRAY(ctx,
337 struct referral, count);
338 if(reflist == NULL) {
339 TALLOC_FREE(alt_path);
340 return False;
342 } else {
343 reflist = *preflist = NULL;
346 for(i=0;i<count;i++) {
347 char *p;
349 /* Canonicalize link target.
350 * Replace all /'s in the path by a \ */
351 string_replace(alt_path[i], '/', '\\');
353 /* Remove leading '\\'s */
354 p = alt_path[i];
355 while (*p && (*p == '\\')) {
356 p++;
359 reflist[i].alternate_path = talloc_asprintf(ctx,
360 "\\%s",
362 if (!reflist[i].alternate_path) {
363 return False;
366 reflist[i].proximity = 0;
367 reflist[i].ttl = REFERRAL_TTL;
368 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
369 reflist[i].alternate_path));
372 *refcount = count;
374 TALLOC_FREE(alt_path);
375 return True;
378 /**********************************************************************
379 Returns true if the unix path is a valid msdfs symlink and also
380 returns the target string from inside the link.
381 **********************************************************************/
383 static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
384 connection_struct *conn,
385 const char *path,
386 char **pp_link_target,
387 SMB_STRUCT_STAT *sbufp)
389 SMB_STRUCT_STAT st;
390 int referral_len = 0;
391 char link_target_buf[7];
392 size_t bufsize = 0;
393 char *link_target = NULL;
395 if (pp_link_target) {
396 bufsize = 1024;
397 link_target = TALLOC_ARRAY(ctx, char, bufsize);
398 if (!link_target) {
399 return False;
401 *pp_link_target = link_target;
402 } else {
403 bufsize = sizeof(link_target_buf);
404 link_target = link_target_buf;
407 if (sbufp == NULL) {
408 sbufp = &st;
411 if (SMB_VFS_LSTAT(conn, path, sbufp) != 0) {
412 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
413 path));
414 goto err;
417 if (!S_ISLNK(sbufp->st_mode)) {
418 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
419 path));
420 goto err;
423 referral_len = SMB_VFS_READLINK(conn, path, link_target, bufsize - 1);
424 if (referral_len == -1) {
425 DEBUG(0,("is_msdfs_link_read_target: Error reading "
426 "msdfs link %s: %s\n",
427 path, strerror(errno)));
428 goto err;
430 link_target[referral_len] = '\0';
432 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path,
433 link_target));
435 if (!strnequal(link_target, "msdfs:", 6)) {
436 goto err;
438 return True;
440 err:
442 if (link_target != link_target_buf) {
443 TALLOC_FREE(link_target);
445 return False;
448 /**********************************************************************
449 Returns true if the unix path is a valid msdfs symlink.
450 **********************************************************************/
452 bool is_msdfs_link(connection_struct *conn,
453 const char *path,
454 SMB_STRUCT_STAT *sbufp)
456 return is_msdfs_link_internal(talloc_tos(),
457 conn,
458 path,
459 NULL,
460 sbufp);
463 /*****************************************************************
464 Used by other functions to decide if a dfs path is remote,
465 and to get the list of referred locations for that remote path.
467 search_flag: For findfirsts, dfs links themselves are not
468 redirected, but paths beyond the links are. For normal smb calls,
469 even dfs links need to be redirected.
471 consumedcntp: how much of the dfs path is being redirected. the client
472 should try the remaining path on the redirected server.
474 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
475 link redirect are in targetpath.
476 *****************************************************************/
478 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
479 connection_struct *conn,
480 const char *dfspath, /* Incoming complete dfs path */
481 const struct dfs_path *pdp, /* Parsed out
482 server+share+extrapath. */
483 bool search_flag, /* Called from a findfirst ? */
484 int *consumedcntp,
485 char **pp_targetpath)
487 char *p = NULL;
488 char *q = NULL;
489 SMB_STRUCT_STAT sbuf;
490 NTSTATUS status;
491 char *localpath = NULL;
492 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
493 components). */
495 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
496 conn->connectpath, pdp->reqpath));
499 * Note the unix path conversion here we're doing we can
500 * throw away. We're looking for a symlink for a dfs
501 * resolution, if we don't find it we'll do another
502 * unix_convert later in the codepath.
503 * If we needed to remember what we'd resolved in
504 * dp->reqpath (as the original code did) we'd
505 * copy (localhost, dp->reqpath) on any code
506 * path below that returns True - but I don't
507 * think this is needed. JRA.
510 status = unix_convert(ctx, conn, pdp->reqpath, search_flag, &localpath,
511 NULL, &sbuf);
512 if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status,
513 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
514 return status;
517 /* Optimization - check if we can redirect the whole path. */
519 if (is_msdfs_link_internal(ctx, conn, localpath, pp_targetpath, NULL)) {
520 if (search_flag) {
521 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
522 "for dfs link %s.\n", dfspath));
523 return NT_STATUS_OK;
526 DEBUG(6,("dfs_path_lookup: %s resolves to a "
527 "valid dfs link %s.\n", dfspath,
528 pp_targetpath ? *pp_targetpath : ""));
530 if (consumedcntp) {
531 *consumedcntp = strlen(dfspath);
533 return NT_STATUS_PATH_NOT_COVERED;
536 /* Prepare to test only for '/' components in the given path,
537 * so if a Windows path replace all '\\' characters with '/'.
538 * For a POSIX DFS path we know all separators are already '/'. */
540 canon_dfspath = talloc_strdup(ctx, dfspath);
541 if (!canon_dfspath) {
542 return NT_STATUS_NO_MEMORY;
544 if (!pdp->posix_path) {
545 string_replace(canon_dfspath, '\\', '/');
549 * localpath comes out of unix_convert, so it has
550 * no trailing backslash. Make sure that canon_dfspath hasn't either.
551 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
554 trim_char(canon_dfspath,0,'/');
557 * Redirect if any component in the path is a link.
558 * We do this by walking backwards through the
559 * local path, chopping off the last component
560 * in both the local path and the canonicalized
561 * DFS path. If we hit a DFS link then we're done.
564 p = strrchr_m(localpath, '/');
565 if (consumedcntp) {
566 q = strrchr_m(canon_dfspath, '/');
569 while (p) {
570 *p = '\0';
571 if (q) {
572 *q = '\0';
575 if (is_msdfs_link_internal(ctx, conn,
576 localpath, pp_targetpath, NULL)) {
577 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
578 "parent %s is dfs link\n", dfspath, localpath));
580 if (consumedcntp) {
581 *consumedcntp = strlen(canon_dfspath);
582 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
583 "(%d)\n",
584 canon_dfspath,
585 *consumedcntp));
588 return NT_STATUS_PATH_NOT_COVERED;
591 /* Step back on the filesystem. */
592 p = strrchr_m(localpath, '/');
594 if (consumedcntp) {
595 /* And in the canonicalized dfs path. */
596 q = strrchr_m(canon_dfspath, '/');
600 return NT_STATUS_OK;
603 /*****************************************************************
604 Decides if a dfs pathname should be redirected or not.
605 If not, the pathname is converted to a tcon-relative local unix path
607 search_wcard_flag: this flag performs 2 functions both related
608 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
609 for details.
611 This function can return NT_STATUS_OK, meaning use the returned path as-is
612 (mapped into a local path).
613 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
614 any other NT_STATUS error which is a genuine error to be
615 returned to the client.
616 *****************************************************************/
618 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
619 connection_struct *conn,
620 const char *path_in,
621 bool search_wcard_flag,
622 char **pp_path_out,
623 bool *ppath_contains_wcard)
625 NTSTATUS status;
626 struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
628 if (!pdp) {
629 return NT_STATUS_NO_MEMORY;
632 status = parse_dfs_path(conn, path_in, search_wcard_flag, pdp,
633 ppath_contains_wcard);
634 if (!NT_STATUS_IS_OK(status)) {
635 TALLOC_FREE(pdp);
636 return status;
639 if (pdp->reqpath[0] == '\0') {
640 TALLOC_FREE(pdp);
641 *pp_path_out = talloc_strdup(ctx, "");
642 if (!*pp_path_out) {
643 return NT_STATUS_NO_MEMORY;
645 DEBUG(5,("dfs_redirect: self-referral.\n"));
646 return NT_STATUS_OK;
649 /* If dfs pathname for a non-dfs share, convert to tcon-relative
650 path and return OK */
652 if (!lp_msdfs_root(SNUM(conn))) {
653 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
654 TALLOC_FREE(pdp);
655 if (!*pp_path_out) {
656 return NT_STATUS_NO_MEMORY;
658 return NT_STATUS_OK;
661 /* If it looked like a local path (zero hostname/servicename)
662 * just treat as a tcon-relative path. */
664 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
665 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
666 TALLOC_FREE(pdp);
667 if (!*pp_path_out) {
668 return NT_STATUS_NO_MEMORY;
670 return NT_STATUS_OK;
673 status = dfs_path_lookup(ctx, conn, path_in, pdp,
674 search_wcard_flag, NULL, NULL);
675 if (!NT_STATUS_IS_OK(status)) {
676 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
677 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
678 } else {
679 DEBUG(10,("dfs_redirect: dfs_path_lookup "
680 "failed for %s with %s\n",
681 path_in, nt_errstr(status) ));
683 return status;
686 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
688 /* Form non-dfs tcon-relative path */
689 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
690 TALLOC_FREE(pdp);
691 if (!*pp_path_out) {
692 return NT_STATUS_NO_MEMORY;
695 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
696 path_in,
697 *pp_path_out));
699 return NT_STATUS_OK;
702 /**********************************************************************
703 Return a self referral.
704 **********************************************************************/
706 static NTSTATUS self_ref(TALLOC_CTX *ctx,
707 const char *dfs_path,
708 struct junction_map *jucn,
709 int *consumedcntp,
710 bool *self_referralp)
712 struct referral *ref;
714 *self_referralp = True;
716 jucn->referral_count = 1;
717 if((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
718 return NT_STATUS_NO_MEMORY;
721 ref->alternate_path = talloc_strdup(ctx, dfs_path);
722 if (!ref->alternate_path) {
723 return NT_STATUS_NO_MEMORY;
725 ref->proximity = 0;
726 ref->ttl = REFERRAL_TTL;
727 jucn->referral_list = ref;
728 *consumedcntp = strlen(dfs_path);
729 return NT_STATUS_OK;
732 /**********************************************************************
733 Gets valid referrals for a dfs path and fills up the
734 junction_map structure.
735 **********************************************************************/
737 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
738 const char *dfs_path,
739 struct junction_map *jucn,
740 int *consumedcntp,
741 bool *self_referralp)
743 struct connection_struct conns;
744 struct connection_struct *conn = &conns;
745 char *targetpath = NULL;
746 int snum;
747 NTSTATUS status = NT_STATUS_NOT_FOUND;
748 bool dummy;
749 struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
751 if (!pdp) {
752 return NT_STATUS_NO_MEMORY;
755 ZERO_STRUCT(conns);
756 *self_referralp = False;
758 status = parse_dfs_path(NULL, dfs_path, False, pdp, &dummy);
759 if (!NT_STATUS_IS_OK(status)) {
760 return status;
763 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
764 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
765 if (!jucn->service_name || !jucn->volume_name) {
766 TALLOC_FREE(pdp);
767 return NT_STATUS_NO_MEMORY;
770 /* Verify the share is a dfs root */
771 snum = lp_servicenumber(jucn->service_name);
772 if(snum < 0) {
773 fstring service_name;
774 fstrcpy(service_name, jucn->service_name);
775 if ((snum = find_service(service_name)) < 0) {
776 return NT_STATUS_NOT_FOUND;
778 TALLOC_FREE(jucn->service_name);
779 jucn->service_name = talloc_strdup(ctx, service_name);
780 if (!jucn->service_name) {
781 TALLOC_FREE(pdp);
782 return NT_STATUS_NO_MEMORY;
786 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(snum) == '\0')) {
787 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
788 "a dfs root.\n",
789 pdp->servicename, dfs_path));
790 TALLOC_FREE(pdp);
791 return NT_STATUS_NOT_FOUND;
795 * Self referrals are tested with a anonymous IPC connection and
796 * a GET_DFS_REFERRAL call to \\server\share. (which means
797 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
798 * into the directory and will fail if it cannot (as the anonymous
799 * user). Cope with this.
802 if (pdp->reqpath[0] == '\0') {
803 char *tmp;
804 struct referral *ref;
806 if (*lp_msdfs_proxy(snum) == '\0') {
807 TALLOC_FREE(pdp);
808 return self_ref(ctx,
809 dfs_path,
810 jucn,
811 consumedcntp,
812 self_referralp);
816 * It's an msdfs proxy share. Redirect to
817 * the configured target share.
820 jucn->referral_count = 1;
821 if ((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
822 TALLOC_FREE(pdp);
823 return NT_STATUS_NO_MEMORY;
826 if (!(tmp = talloc_strdup(ctx, lp_msdfs_proxy(snum)))) {
827 TALLOC_FREE(pdp);
828 return NT_STATUS_NO_MEMORY;
831 trim_string(tmp, "\\", 0);
833 ref->alternate_path = talloc_asprintf(ctx, "\\%s", tmp);
834 TALLOC_FREE(tmp);
836 if (!ref->alternate_path) {
837 TALLOC_FREE(pdp);
838 return NT_STATUS_NO_MEMORY;
841 if (pdp->reqpath[0] != '\0') {
842 ref->alternate_path = talloc_asprintf_append(
843 ref->alternate_path,
844 "%s",
845 pdp->reqpath);
846 if (!ref->alternate_path) {
847 TALLOC_FREE(pdp);
848 return NT_STATUS_NO_MEMORY;
851 ref->proximity = 0;
852 ref->ttl = REFERRAL_TTL;
853 jucn->referral_list = ref;
854 *consumedcntp = strlen(dfs_path);
855 TALLOC_FREE(pdp);
856 return NT_STATUS_OK;
859 status = create_conn_struct(ctx, conn, snum, lp_pathname(snum));
860 if (!NT_STATUS_IS_OK(status)) {
861 TALLOC_FREE(pdp);
862 return status;
865 /* If this is a DFS path dfs_lookup should return
866 * NT_STATUS_PATH_NOT_COVERED. */
868 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
869 False, consumedcntp, &targetpath);
871 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
872 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
873 dfs_path));
874 conn_free_internal(conn);
875 TALLOC_FREE(pdp);
876 return status;
879 /* We know this is a valid dfs link. Parse the targetpath. */
880 if (!parse_msdfs_symlink(ctx, targetpath,
881 &jucn->referral_list,
882 &jucn->referral_count)) {
883 DEBUG(3,("get_referred_path: failed to parse symlink "
884 "target %s\n", targetpath ));
885 conn_free_internal(conn);
886 TALLOC_FREE(pdp);
887 return NT_STATUS_NOT_FOUND;
890 conn_free_internal(conn);
891 TALLOC_FREE(pdp);
892 return NT_STATUS_OK;
895 static int setup_ver2_dfs_referral(const char *pathname,
896 char **ppdata,
897 struct junction_map *junction,
898 int consumedcnt,
899 bool self_referral)
901 char* pdata = *ppdata;
903 smb_ucs2_t *uni_requestedpath = NULL;
904 int uni_reqpathoffset1,uni_reqpathoffset2;
905 int uni_curroffset;
906 int requestedpathlen=0;
907 int offset;
908 int reply_size = 0;
909 int i=0;
911 DEBUG(10,("Setting up version2 referral\nRequested path:\n"));
913 requestedpathlen = rpcstr_push_talloc(talloc_tos(),
914 &uni_requestedpath, pathname);
915 if (uni_requestedpath == NULL || requestedpathlen == 0) {
916 return -1;
919 if (DEBUGLVL(10)) {
920 dump_data(0, (unsigned char *)uni_requestedpath,
921 requestedpathlen);
924 DEBUG(10,("ref count = %u\n",junction->referral_count));
926 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
927 VERSION2_REFERRAL_SIZE * junction->referral_count;
929 uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen;
931 uni_curroffset = uni_reqpathoffset2 + requestedpathlen;
933 reply_size = REFERRAL_HEADER_SIZE +
934 VERSION2_REFERRAL_SIZE*junction->referral_count +
935 2 * requestedpathlen;
936 DEBUG(10,("reply_size: %u\n",reply_size));
938 /* add up the unicode lengths of all the referral paths */
939 for(i=0;i<junction->referral_count;i++) {
940 DEBUG(10,("referral %u : %s\n",
942 junction->referral_list[i].alternate_path));
943 reply_size +=
944 (strlen(junction->referral_list[i].alternate_path)+1)*2;
947 DEBUG(10,("reply_size = %u\n",reply_size));
948 /* add the unexplained 0x16 bytes */
949 reply_size += 0x16;
951 pdata = (char *)SMB_REALLOC(pdata,reply_size);
952 if(pdata == NULL) {
953 DEBUG(0,("Realloc failed!\n"));
954 return -1;
956 *ppdata = pdata;
958 /* copy in the dfs requested paths.. required for offset calculations */
959 memcpy(pdata+uni_reqpathoffset1,uni_requestedpath,requestedpathlen);
960 memcpy(pdata+uni_reqpathoffset2,uni_requestedpath,requestedpathlen);
962 /* create the header */
963 SSVAL(pdata,0,consumedcnt * 2); /* path consumed */
964 /* number of referral in this pkt */
965 SSVAL(pdata,2,junction->referral_count);
966 if(self_referral) {
967 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
968 } else {
969 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
972 offset = 8;
973 /* add the referral elements */
974 for(i=0;i<junction->referral_count;i++) {
975 struct referral* ref = &junction->referral_list[i];
976 int unilen;
978 SSVAL(pdata,offset,2); /* version 2 */
979 SSVAL(pdata,offset+2,VERSION2_REFERRAL_SIZE);
980 if(self_referral) {
981 SSVAL(pdata,offset+4,1);
982 } else {
983 SSVAL(pdata,offset+4,0);
986 /* ref_flags :use path_consumed bytes? */
987 SSVAL(pdata,offset+6,0);
988 SIVAL(pdata,offset+8,ref->proximity);
989 SIVAL(pdata,offset+12,ref->ttl);
991 SSVAL(pdata,offset+16,uni_reqpathoffset1-offset);
992 SSVAL(pdata,offset+18,uni_reqpathoffset2-offset);
993 /* copy referred path into current offset */
994 unilen = rpcstr_push(pdata+uni_curroffset,
995 ref->alternate_path,
996 reply_size - uni_curroffset,
997 STR_UNICODE);
999 SSVAL(pdata,offset+20,uni_curroffset-offset);
1001 uni_curroffset += unilen;
1002 offset += VERSION2_REFERRAL_SIZE;
1004 /* add in the unexplained 22 (0x16) bytes at the end */
1005 memset(pdata+uni_curroffset,'\0',0x16);
1006 return reply_size;
1009 static int setup_ver3_dfs_referral(const char *pathname,
1010 char **ppdata,
1011 struct junction_map *junction,
1012 int consumedcnt,
1013 bool self_referral)
1015 char *pdata = *ppdata;
1017 smb_ucs2_t *uni_reqpath = NULL;
1018 int uni_reqpathoffset1, uni_reqpathoffset2;
1019 int uni_curroffset;
1020 int reply_size = 0;
1022 int reqpathlen = 0;
1023 int offset,i=0;
1025 DEBUG(10,("setting up version3 referral\n"));
1027 reqpathlen = rpcstr_push_talloc(talloc_tos(), &uni_reqpath, pathname);
1028 if (uni_reqpath == NULL || reqpathlen == 0) {
1029 return -1;
1032 if (DEBUGLVL(10)) {
1033 dump_data(0, (unsigned char *)uni_reqpath,
1034 reqpathlen);
1037 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
1038 VERSION3_REFERRAL_SIZE * junction->referral_count;
1039 uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen;
1040 reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen;
1042 for(i=0;i<junction->referral_count;i++) {
1043 DEBUG(10,("referral %u : %s\n",
1045 junction->referral_list[i].alternate_path));
1046 reply_size +=
1047 (strlen(junction->referral_list[i].alternate_path)+1)*2;
1050 pdata = (char *)SMB_REALLOC(pdata,reply_size);
1051 if(pdata == NULL) {
1052 DEBUG(0,("version3 referral setup:"
1053 "malloc failed for Realloc!\n"));
1054 return -1;
1056 *ppdata = pdata;
1058 /* create the header */
1059 SSVAL(pdata,0,consumedcnt * 2); /* path consumed */
1060 SSVAL(pdata,2,junction->referral_count); /* number of referral */
1061 if(self_referral) {
1062 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
1063 } else {
1064 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
1067 /* copy in the reqpaths */
1068 memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen);
1069 memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen);
1071 offset = 8;
1072 for(i=0;i<junction->referral_count;i++) {
1073 struct referral* ref = &(junction->referral_list[i]);
1074 int unilen;
1076 SSVAL(pdata,offset,3); /* version 3 */
1077 SSVAL(pdata,offset+2,VERSION3_REFERRAL_SIZE);
1078 if(self_referral) {
1079 SSVAL(pdata,offset+4,1);
1080 } else {
1081 SSVAL(pdata,offset+4,0);
1084 /* ref_flags :use path_consumed bytes? */
1085 SSVAL(pdata,offset+6,0);
1086 SIVAL(pdata,offset+8,ref->ttl);
1088 SSVAL(pdata,offset+12,uni_reqpathoffset1-offset);
1089 SSVAL(pdata,offset+14,uni_reqpathoffset2-offset);
1090 /* copy referred path into current offset */
1091 unilen = rpcstr_push(pdata+uni_curroffset,ref->alternate_path,
1092 reply_size - uni_curroffset,
1093 STR_UNICODE | STR_TERMINATE);
1094 SSVAL(pdata,offset+16,uni_curroffset-offset);
1095 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
1096 memset(pdata+offset+18,'\0',16);
1098 uni_curroffset += unilen;
1099 offset += VERSION3_REFERRAL_SIZE;
1101 return reply_size;
1104 /******************************************************************
1105 Set up the DFS referral for the dfs pathname. This call returns
1106 the amount of the path covered by this server, and where the
1107 client should be redirected to. This is the meat of the
1108 TRANS2_GET_DFS_REFERRAL call.
1109 ******************************************************************/
1111 int setup_dfs_referral(connection_struct *orig_conn,
1112 const char *dfs_path,
1113 int max_referral_level,
1114 char **ppdata, NTSTATUS *pstatus)
1116 struct junction_map *junction = NULL;
1117 int consumedcnt = 0;
1118 bool self_referral = False;
1119 int reply_size = 0;
1120 char *pathnamep = NULL;
1121 char *local_dfs_path = NULL;
1122 TALLOC_CTX *ctx;
1124 if (!(ctx=talloc_init("setup_dfs_referral"))) {
1125 *pstatus = NT_STATUS_NO_MEMORY;
1126 return -1;
1129 /* get the junction entry */
1130 if (!dfs_path) {
1131 talloc_destroy(ctx);
1132 *pstatus = NT_STATUS_NOT_FOUND;
1133 return -1;
1137 * Trim pathname sent by client so it begins with only one backslash.
1138 * Two backslashes confuse some dfs clients
1141 local_dfs_path = talloc_strdup(ctx,dfs_path);
1142 if (!local_dfs_path) {
1143 *pstatus = NT_STATUS_NO_MEMORY;
1144 talloc_destroy(ctx);
1145 return -1;
1147 pathnamep = local_dfs_path;
1148 while (IS_DIRECTORY_SEP(pathnamep[0]) &&
1149 IS_DIRECTORY_SEP(pathnamep[1])) {
1150 pathnamep++;
1153 junction = TALLOC_ZERO_P(ctx, struct junction_map);
1154 if (!junction) {
1155 *pstatus = NT_STATUS_NO_MEMORY;
1156 talloc_destroy(ctx);
1157 return -1;
1160 /* The following call can change cwd. */
1161 *pstatus = get_referred_path(ctx, pathnamep, junction,
1162 &consumedcnt, &self_referral);
1163 if (!NT_STATUS_IS_OK(*pstatus)) {
1164 vfs_ChDir(orig_conn,orig_conn->connectpath);
1165 talloc_destroy(ctx);
1166 return -1;
1168 vfs_ChDir(orig_conn,orig_conn->connectpath);
1170 if (!self_referral) {
1171 pathnamep[consumedcnt] = '\0';
1173 if( DEBUGLVL( 3 ) ) {
1174 int i=0;
1175 dbgtext("setup_dfs_referral: Path %s to "
1176 "alternate path(s):",
1177 pathnamep);
1178 for(i=0;i<junction->referral_count;i++)
1179 dbgtext(" %s",
1180 junction->referral_list[i].alternate_path);
1181 dbgtext(".\n");
1185 /* create the referral depeding on version */
1186 DEBUG(10,("max_referral_level :%d\n",max_referral_level));
1188 if (max_referral_level < 2) {
1189 max_referral_level = 2;
1191 if (max_referral_level > 3) {
1192 max_referral_level = 3;
1195 switch(max_referral_level) {
1196 case 2:
1197 reply_size = setup_ver2_dfs_referral(pathnamep,
1198 ppdata, junction,
1199 consumedcnt, self_referral);
1200 break;
1201 case 3:
1202 reply_size = setup_ver3_dfs_referral(pathnamep, ppdata,
1203 junction, consumedcnt, self_referral);
1204 break;
1205 default:
1206 DEBUG(0,("setup_dfs_referral: Invalid dfs referral "
1207 "version: %d\n",
1208 max_referral_level));
1209 talloc_destroy(ctx);
1210 *pstatus = NT_STATUS_INVALID_LEVEL;
1211 return -1;
1214 if (DEBUGLVL(10)) {
1215 DEBUGADD(0,("DFS Referral pdata:\n"));
1216 dump_data(0,(uint8 *)*ppdata,reply_size);
1219 talloc_destroy(ctx);
1220 *pstatus = NT_STATUS_OK;
1221 return reply_size;
1224 /**********************************************************************
1225 The following functions are called by the NETDFS RPC pipe functions
1226 **********************************************************************/
1228 /*********************************************************************
1229 Creates a junction structure from a DFS pathname
1230 **********************************************************************/
1232 bool create_junction(TALLOC_CTX *ctx,
1233 const char *dfs_path,
1234 struct junction_map *jucn)
1236 int snum;
1237 bool dummy;
1238 struct dfs_path *pdp = TALLOC_P(ctx,struct dfs_path);
1239 NTSTATUS status;
1241 if (!pdp) {
1242 return False;
1244 status = parse_dfs_path(NULL, dfs_path, False, pdp, &dummy);
1245 if (!NT_STATUS_IS_OK(status)) {
1246 return False;
1249 /* check if path is dfs : validate first token */
1250 if (!is_myname_or_ipaddr(pdp->hostname)) {
1251 DEBUG(4,("create_junction: Invalid hostname %s "
1252 "in dfs path %s\n",
1253 pdp->hostname, dfs_path));
1254 TALLOC_FREE(pdp);
1255 return False;
1258 /* Check for a non-DFS share */
1259 snum = lp_servicenumber(pdp->servicename);
1261 if(snum < 0 || !lp_msdfs_root(snum)) {
1262 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1263 pdp->servicename));
1264 TALLOC_FREE(pdp);
1265 return False;
1268 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1269 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1270 jucn->comment = talloc_strdup(ctx, lp_comment(snum));
1272 TALLOC_FREE(pdp);
1273 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1274 return False;
1276 return True;
1279 /**********************************************************************
1280 Forms a valid Unix pathname from the junction
1281 **********************************************************************/
1283 static bool junction_to_local_path(const struct junction_map *jucn,
1284 char **pp_path_out,
1285 connection_struct *conn_out)
1287 int snum;
1289 snum = lp_servicenumber(jucn->service_name);
1290 if(snum < 0) {
1291 return False;
1293 if (!NT_STATUS_IS_OK(create_conn_struct(talloc_tos(),
1294 conn_out, snum,
1295 lp_pathname(snum)))) {
1296 return False;
1299 *pp_path_out = talloc_asprintf(conn_out->mem_ctx,
1300 "%s/%s",
1301 lp_pathname(snum),
1302 jucn->volume_name);
1303 if (!*pp_path_out) {
1304 return False;
1306 return True;
1309 bool create_msdfs_link(const struct junction_map *jucn)
1311 char *path = NULL;
1312 char *msdfs_link = NULL;
1313 connection_struct conns;
1314 connection_struct *conn = &conns;
1315 int i=0;
1316 bool insert_comma = False;
1317 bool ret = False;
1319 ZERO_STRUCT(conns);
1321 if(!junction_to_local_path(jucn, &path, conn)) {
1322 return False;
1325 /* Form the msdfs_link contents */
1326 msdfs_link = talloc_strdup(conn->mem_ctx, "msdfs:");
1327 if (!msdfs_link) {
1328 goto out;
1330 for(i=0; i<jucn->referral_count; i++) {
1331 char *refpath = jucn->referral_list[i].alternate_path;
1333 /* Alternate paths always use Windows separators. */
1334 trim_char(refpath, '\\', '\\');
1335 if(*refpath == '\0') {
1336 if (i == 0) {
1337 insert_comma = False;
1339 continue;
1341 if (i > 0 && insert_comma) {
1342 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1343 ",%s",
1344 refpath);
1345 } else {
1346 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1347 "%s",
1348 refpath);
1351 if (!msdfs_link) {
1352 goto out;
1354 if (!insert_comma) {
1355 insert_comma = True;
1359 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1360 path, msdfs_link));
1362 if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1363 if (errno == EEXIST) {
1364 if(SMB_VFS_UNLINK(conn,path)!=0) {
1365 goto out;
1368 if (SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1369 DEBUG(1,("create_msdfs_link: symlink failed "
1370 "%s -> %s\nError: %s\n",
1371 path, msdfs_link, strerror(errno)));
1372 goto out;
1376 ret = True;
1378 out:
1380 conn_free_internal(conn);
1381 return ret;
1384 bool remove_msdfs_link(const struct junction_map *jucn)
1386 char *path = NULL;
1387 connection_struct conns;
1388 connection_struct *conn = &conns;
1389 bool ret = False;
1391 ZERO_STRUCT(conns);
1393 if( junction_to_local_path(jucn, &path, conn) ) {
1394 if( SMB_VFS_UNLINK(conn, path) == 0 ) {
1395 ret = True;
1399 conn_free_internal(conn);
1400 return ret;
1403 /*********************************************************************
1404 Return the number of DFS links at the root of this share.
1405 *********************************************************************/
1407 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1409 size_t cnt = 0;
1410 SMB_STRUCT_DIR *dirp = NULL;
1411 char *dname = NULL;
1412 const char *connect_path = lp_pathname(snum);
1413 const char *msdfs_proxy = lp_msdfs_proxy(snum);
1414 connection_struct conn;
1416 ZERO_STRUCT(conn);
1418 if(*connect_path == '\0') {
1419 return 0;
1423 * Fake up a connection struct for the VFS layer.
1426 if (!NT_STATUS_IS_OK(create_conn_struct(talloc_tos(),
1427 &conn, snum, connect_path))) {
1428 return 0;
1431 /* Count a link for the msdfs root - convention */
1432 cnt = 1;
1434 /* No more links if this is an msdfs proxy. */
1435 if (*msdfs_proxy != '\0') {
1436 goto out;
1439 /* Now enumerate all dfs links */
1440 dirp = SMB_VFS_OPENDIR(&conn, ".", NULL, 0);
1441 if(!dirp) {
1442 goto out;
1445 while ((dname = vfs_readdirname(&conn, dirp)) != NULL) {
1446 if (is_msdfs_link(&conn,
1447 dname,
1448 NULL)) {
1449 cnt++;
1453 SMB_VFS_CLOSEDIR(&conn,dirp);
1455 out:
1457 conn_free_internal(&conn);
1458 return cnt;
1461 /*********************************************************************
1462 *********************************************************************/
1464 static int form_junctions(TALLOC_CTX *ctx,
1465 int snum,
1466 struct junction_map *jucn,
1467 size_t jn_remain)
1469 size_t cnt = 0;
1470 SMB_STRUCT_DIR *dirp = NULL;
1471 char *dname = NULL;
1472 const char *connect_path = lp_pathname(snum);
1473 char *service_name = lp_servicename(snum);
1474 const char *msdfs_proxy = lp_msdfs_proxy(snum);
1475 connection_struct conn;
1476 struct referral *ref = NULL;
1478 ZERO_STRUCT(conn);
1480 if (jn_remain == 0) {
1481 return 0;
1484 if(*connect_path == '\0') {
1485 return 0;
1489 * Fake up a connection struct for the VFS layer.
1492 if (!NT_STATUS_IS_OK(create_conn_struct(ctx, &conn, snum, connect_path))) {
1493 return 0;
1496 /* form a junction for the msdfs root - convention
1497 DO NOT REMOVE THIS: NT clients will not work with us
1498 if this is not present
1500 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1501 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1502 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1503 goto out;
1505 jucn[cnt].comment = "";
1506 jucn[cnt].referral_count = 1;
1508 ref = jucn[cnt].referral_list = TALLOC_ZERO_P(ctx, struct referral);
1509 if (jucn[cnt].referral_list == NULL) {
1510 goto out;
1513 ref->proximity = 0;
1514 ref->ttl = REFERRAL_TTL;
1515 if (*msdfs_proxy != '\0') {
1516 ref->alternate_path = talloc_strdup(ctx,
1517 msdfs_proxy);
1518 } else {
1519 ref->alternate_path = talloc_asprintf(ctx,
1520 "\\\\%s\\%s",
1521 get_local_machine_name(),
1522 service_name);
1525 if (!ref->alternate_path) {
1526 goto out;
1528 cnt++;
1530 /* Don't enumerate if we're an msdfs proxy. */
1531 if (*msdfs_proxy != '\0') {
1532 goto out;
1535 /* Now enumerate all dfs links */
1536 dirp = SMB_VFS_OPENDIR(&conn, ".", NULL, 0);
1537 if(!dirp) {
1538 goto out;
1541 while ((dname = vfs_readdirname(&conn, dirp)) != NULL) {
1542 char *link_target = NULL;
1543 if (cnt >= jn_remain) {
1544 DEBUG(2, ("form_junctions: ran out of MSDFS "
1545 "junction slots"));
1546 goto out;
1548 if (is_msdfs_link_internal(ctx,
1549 &conn,
1550 dname, &link_target,
1551 NULL)) {
1552 if (parse_msdfs_symlink(ctx,
1553 link_target,
1554 &jucn[cnt].referral_list,
1555 &jucn[cnt].referral_count)) {
1557 jucn[cnt].service_name = talloc_strdup(ctx,
1558 service_name);
1559 jucn[cnt].volume_name = talloc_strdup(ctx,
1560 dname);
1561 if (!jucn[cnt].service_name ||
1562 !jucn[cnt].volume_name) {
1563 goto out;
1565 jucn[cnt].comment = "";
1566 cnt++;
1568 TALLOC_FREE(link_target);
1572 out:
1574 if (dirp) {
1575 SMB_VFS_CLOSEDIR(&conn,dirp);
1578 conn_free_internal(&conn);
1579 return cnt;
1582 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1584 struct junction_map *jn = NULL;
1585 int i=0;
1586 size_t jn_count = 0;
1587 int sharecount = 0;
1589 *p_num_jn = 0;
1590 if(!lp_host_msdfs()) {
1591 return NULL;
1594 /* Ensure all the usershares are loaded. */
1595 become_root();
1596 load_registry_shares();
1597 sharecount = load_usershare_shares();
1598 unbecome_root();
1600 for(i=0;i < sharecount;i++) {
1601 if(lp_msdfs_root(i)) {
1602 jn_count += count_dfs_links(ctx, i);
1605 if (jn_count == 0) {
1606 return NULL;
1608 jn = TALLOC_ARRAY(ctx, struct junction_map, jn_count);
1609 if (!jn) {
1610 return NULL;
1612 for(i=0; i < sharecount; i++) {
1613 if (*p_num_jn >= jn_count) {
1614 break;
1616 if(lp_msdfs_root(i)) {
1617 *p_num_jn += form_junctions(ctx, i,
1618 &jn[*p_num_jn],
1619 jn_count - *p_num_jn);
1622 return jn;
1625 /******************************************************************************
1626 Core function to resolve a dfs pathname.
1627 ******************************************************************************/
1629 NTSTATUS resolve_dfspath(TALLOC_CTX *ctx,
1630 connection_struct *conn,
1631 bool dfs_pathnames,
1632 const char *name_in,
1633 char **pp_name_out)
1635 NTSTATUS status = NT_STATUS_OK;
1636 bool dummy;
1637 if (dfs_pathnames) {
1638 status = dfs_redirect(ctx,
1639 conn,
1640 name_in,
1641 False,
1642 pp_name_out,
1643 &dummy);
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;
1655 /******************************************************************************
1656 Core function to resolve a dfs pathname possibly containing a wildcard.
1657 This function is identical to the above except for the bool param to
1658 dfs_redirect but I need this to be separate so it's really clear when
1659 we're allowing wildcards and when we're not. JRA.
1660 ******************************************************************************/
1662 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1663 connection_struct *conn,
1664 bool dfs_pathnames,
1665 const char *name_in,
1666 char **pp_name_out,
1667 bool *ppath_contains_wcard)
1669 NTSTATUS status = NT_STATUS_OK;
1670 if (dfs_pathnames) {
1671 status = dfs_redirect(ctx,
1672 conn,
1673 name_in,
1674 True,
1675 pp_name_out,
1676 ppath_contains_wcard);
1677 } else {
1679 * Cheat and just return a copy of the in ptr.
1680 * Once srvstr_get_path() uses talloc it'll
1681 * be a talloced ptr anyway.
1683 *pp_name_out = CONST_DISCARD(char *,name_in);
1685 return status;