Fix for CVE-2009-2906.
[Samba.git] / source3 / smbd / msdfs.c
blobefbc05ceb00f332c96ddec132aac038e9364970f
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"
25 #include "smbd/globals.h"
27 /**********************************************************************
28 Parse a DFS pathname of the form \hostname\service\reqpath
29 into the dfs_path structure.
30 If POSIX pathnames is true, the pathname may also be of the
31 form /hostname/service/reqpath.
32 We cope with either here.
34 Unfortunately, due to broken clients who might set the
35 SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
36 send a local path, we have to cope with that too....
38 If conn != NULL then ensure the provided service is
39 the one pointed to by the connection.
41 This version does everything using pointers within one copy of the
42 pathname string, talloced on the struct dfs_path pointer (which
43 must be talloced). This may be too clever to live....
44 JRA.
45 **********************************************************************/
47 static NTSTATUS parse_dfs_path(connection_struct *conn,
48 const char *pathname,
49 bool allow_wcards,
50 struct dfs_path *pdp, /* MUST BE TALLOCED */
51 bool *ppath_contains_wcard)
53 char *pathname_local;
54 char *p,*temp;
55 char *servicename;
56 char *eos_ptr;
57 NTSTATUS status = NT_STATUS_OK;
58 char sepchar;
60 ZERO_STRUCTP(pdp);
63 * This is the only talloc we should need to do
64 * on the struct dfs_path. All the pointers inside
65 * it should point to offsets within this string.
68 pathname_local = talloc_strdup(pdp, pathname);
69 if (!pathname_local) {
70 return NT_STATUS_NO_MEMORY;
72 /* Get a pointer to the terminating '\0' */
73 eos_ptr = &pathname_local[strlen(pathname_local)];
74 p = temp = pathname_local;
76 pdp->posix_path = (lp_posix_pathnames() && *pathname == '/');
78 sepchar = pdp->posix_path ? '/' : '\\';
80 if (*pathname != sepchar) {
81 DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
82 pathname, sepchar ));
84 * Possibly client sent a local path by mistake.
85 * Try and convert to a local path.
88 pdp->hostname = eos_ptr; /* "" */
89 pdp->servicename = eos_ptr; /* "" */
91 /* We've got no info about separators. */
92 pdp->posix_path = lp_posix_pathnames();
93 p = temp;
94 DEBUG(10,("parse_dfs_path: trying to convert %s to a "
95 "local path\n",
96 temp));
97 goto local_path;
101 * Safe to use on talloc'ed string as it only shrinks.
102 * It also doesn't affect the eos_ptr.
104 trim_char(temp,sepchar,sepchar);
106 DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
107 temp, sepchar));
109 /* Now tokenize. */
110 /* Parse out hostname. */
111 p = strchr_m(temp,sepchar);
112 if(p == NULL) {
113 DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
114 temp));
116 * Possibly client sent a local path by mistake.
117 * Try and convert to a local path.
120 pdp->hostname = eos_ptr; /* "" */
121 pdp->servicename = eos_ptr; /* "" */
123 p = temp;
124 DEBUG(10,("parse_dfs_path: trying to convert %s "
125 "to a local path\n",
126 temp));
127 goto local_path;
129 *p = '\0';
130 pdp->hostname = temp;
132 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
134 /* Parse out servicename. */
135 servicename = p+1;
136 p = strchr_m(servicename,sepchar);
137 if (p) {
138 *p = '\0';
141 /* Is this really our servicename ? */
142 if (conn && !( strequal(servicename, lp_servicename(SNUM(conn)))
143 || (strequal(servicename, HOMES_NAME)
144 && strequal(lp_servicename(SNUM(conn)),
145 get_current_username()) )) ) {
146 DEBUG(10,("parse_dfs_path: %s is not our servicename\n",
147 servicename));
150 * Possibly client sent a local path by mistake.
151 * Try and convert to a local path.
154 pdp->hostname = eos_ptr; /* "" */
155 pdp->servicename = eos_ptr; /* "" */
157 /* Repair the path - replace the sepchar's
158 we nulled out */
159 servicename--;
160 *servicename = sepchar;
161 if (p) {
162 *p = sepchar;
165 p = temp;
166 DEBUG(10,("parse_dfs_path: trying to convert %s "
167 "to a local path\n",
168 temp));
169 goto local_path;
172 pdp->servicename = servicename;
174 DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
176 if(p == NULL) {
177 /* Client sent self referral \server\share. */
178 pdp->reqpath = eos_ptr; /* "" */
179 return NT_STATUS_OK;
182 p++;
184 local_path:
186 *ppath_contains_wcard = False;
188 pdp->reqpath = p;
190 /* Rest is reqpath. */
191 if (pdp->posix_path) {
192 status = check_path_syntax_posix(pdp->reqpath);
193 } else {
194 if (allow_wcards) {
195 status = check_path_syntax_wcard(pdp->reqpath,
196 ppath_contains_wcard);
197 } else {
198 status = check_path_syntax(pdp->reqpath);
202 if (!NT_STATUS_IS_OK(status)) {
203 DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
204 p, nt_errstr(status) ));
205 return status;
208 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
209 return NT_STATUS_OK;
212 /********************************************************
213 Fake up a connection struct for the VFS layer.
214 Note this CHANGES CWD !!!! JRA.
215 *********************************************************/
217 NTSTATUS create_conn_struct(TALLOC_CTX *ctx,
218 connection_struct **pconn,
219 int snum,
220 const char *path,
221 struct auth_serversupplied_info *server_info,
222 char **poldcwd)
224 connection_struct *conn;
225 char *connpath;
226 char *oldcwd;
228 conn = TALLOC_ZERO_P(ctx, connection_struct);
229 if (conn == NULL) {
230 return NT_STATUS_NO_MEMORY;
233 connpath = talloc_strdup(conn, path);
234 if (!connpath) {
235 TALLOC_FREE(conn);
236 return NT_STATUS_NO_MEMORY;
238 connpath = talloc_string_sub(conn,
239 connpath,
240 "%S",
241 lp_servicename(snum));
242 if (!connpath) {
243 TALLOC_FREE(conn);
244 return NT_STATUS_NO_MEMORY;
247 /* needed for smbd_vfs_init() */
249 if (!(conn->params = TALLOC_ZERO_P(conn, struct share_params))) {
250 DEBUG(0, ("TALLOC failed\n"));
251 TALLOC_FREE(conn);
252 return NT_STATUS_NO_MEMORY;
255 conn->params->service = snum;
257 if (server_info != NULL) {
258 conn->server_info = copy_serverinfo(conn, server_info);
259 if (conn->server_info == NULL) {
260 DEBUG(0, ("copy_serverinfo failed\n"));
261 TALLOC_FREE(conn);
262 return NT_STATUS_NO_MEMORY;
266 set_conn_connectpath(conn, connpath);
268 if (!smbd_vfs_init(conn)) {
269 NTSTATUS status = map_nt_error_from_unix(errno);
270 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
271 conn_free_internal(conn);
272 return status;
275 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn);
278 * Windows seems to insist on doing trans2getdfsreferral() calls on
279 * the IPC$ share as the anonymous user. If we try to chdir as that
280 * user we will fail.... WTF ? JRA.
283 oldcwd = vfs_GetWd(ctx, conn);
284 if (oldcwd == NULL) {
285 NTSTATUS status = map_nt_error_from_unix(errno);
286 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
287 conn_free_internal(conn);
288 return status;
291 if (vfs_ChDir(conn,conn->connectpath) != 0) {
292 NTSTATUS status = map_nt_error_from_unix(errno);
293 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
294 "Error was %s\n",
295 conn->connectpath, strerror(errno) ));
296 conn_free_internal(conn);
297 return status;
300 *pconn = conn;
301 *poldcwd = oldcwd;
303 return NT_STATUS_OK;
306 /**********************************************************************
307 Parse the contents of a symlink to verify if it is an msdfs referral
308 A valid referral is of the form:
310 msdfs:server1\share1,server2\share2
311 msdfs:server1\share1\pathname,server2\share2\pathname
312 msdfs:server1/share1,server2/share2
313 msdfs:server1/share1/pathname,server2/share2/pathname.
315 Note that the alternate paths returned here must be of the canonicalized
316 form:
318 \server\share or
319 \server\share\path\to\file,
321 even in posix path mode. This is because we have no knowledge if the
322 server we're referring to understands posix paths.
323 **********************************************************************/
325 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
326 const char *target,
327 struct referral **preflist,
328 int *refcount)
330 char *temp = NULL;
331 char *prot;
332 char **alt_path = NULL;
333 int count = 0, i;
334 struct referral *reflist;
335 char *saveptr;
337 temp = talloc_strdup(ctx, target);
338 if (!temp) {
339 return False;
341 prot = strtok_r(temp, ":", &saveptr);
342 if (!prot) {
343 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
344 return False;
347 alt_path = TALLOC_ARRAY(ctx, char *, MAX_REFERRAL_COUNT);
348 if (!alt_path) {
349 return False;
352 /* parse out the alternate paths */
353 while((count<MAX_REFERRAL_COUNT) &&
354 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
355 count++;
358 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
360 if (count) {
361 reflist = *preflist = TALLOC_ZERO_ARRAY(ctx,
362 struct referral, count);
363 if(reflist == NULL) {
364 TALLOC_FREE(alt_path);
365 return False;
367 } else {
368 reflist = *preflist = NULL;
371 for(i=0;i<count;i++) {
372 char *p;
374 /* Canonicalize link target.
375 * Replace all /'s in the path by a \ */
376 string_replace(alt_path[i], '/', '\\');
378 /* Remove leading '\\'s */
379 p = alt_path[i];
380 while (*p && (*p == '\\')) {
381 p++;
384 reflist[i].alternate_path = talloc_asprintf(ctx,
385 "\\%s",
387 if (!reflist[i].alternate_path) {
388 return False;
391 reflist[i].proximity = 0;
392 reflist[i].ttl = REFERRAL_TTL;
393 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
394 reflist[i].alternate_path));
397 *refcount = count;
399 TALLOC_FREE(alt_path);
400 return True;
403 /**********************************************************************
404 Returns true if the unix path is a valid msdfs symlink and also
405 returns the target string from inside the link.
406 **********************************************************************/
408 static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
409 connection_struct *conn,
410 const char *path,
411 char **pp_link_target,
412 SMB_STRUCT_STAT *sbufp)
414 SMB_STRUCT_STAT st;
415 int referral_len = 0;
416 #if defined(HAVE_BROKEN_READLINK)
417 char link_target_buf[PATH_MAX];
418 #else
419 char link_target_buf[7];
420 #endif
421 size_t bufsize = 0;
422 char *link_target = NULL;
424 if (pp_link_target) {
425 bufsize = 1024;
426 link_target = TALLOC_ARRAY(ctx, char, bufsize);
427 if (!link_target) {
428 return False;
430 *pp_link_target = link_target;
431 } else {
432 bufsize = sizeof(link_target_buf);
433 link_target = link_target_buf;
436 if (sbufp == NULL) {
437 sbufp = &st;
440 if (SMB_VFS_LSTAT(conn, path, sbufp) != 0) {
441 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
442 path));
443 goto err;
446 if (!S_ISLNK(sbufp->st_mode)) {
447 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
448 path));
449 goto err;
452 referral_len = SMB_VFS_READLINK(conn, path, link_target, bufsize - 1);
453 if (referral_len == -1) {
454 DEBUG(0,("is_msdfs_link_read_target: Error reading "
455 "msdfs link %s: %s\n",
456 path, strerror(errno)));
457 goto err;
459 link_target[referral_len] = '\0';
461 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path,
462 link_target));
464 if (!strnequal(link_target, "msdfs:", 6)) {
465 goto err;
467 return True;
469 err:
471 if (link_target != link_target_buf) {
472 TALLOC_FREE(link_target);
474 return False;
477 /**********************************************************************
478 Returns true if the unix path is a valid msdfs symlink.
479 **********************************************************************/
481 bool is_msdfs_link(connection_struct *conn,
482 const char *path,
483 SMB_STRUCT_STAT *sbufp)
485 return is_msdfs_link_internal(talloc_tos(),
486 conn,
487 path,
488 NULL,
489 sbufp);
492 /*****************************************************************
493 Used by other functions to decide if a dfs path is remote,
494 and to get the list of referred locations for that remote path.
496 search_flag: For findfirsts, dfs links themselves are not
497 redirected, but paths beyond the links are. For normal smb calls,
498 even dfs links need to be redirected.
500 consumedcntp: how much of the dfs path is being redirected. the client
501 should try the remaining path on the redirected server.
503 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
504 link redirect are in targetpath.
505 *****************************************************************/
507 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
508 connection_struct *conn,
509 const char *dfspath, /* Incoming complete dfs path */
510 const struct dfs_path *pdp, /* Parsed out
511 server+share+extrapath. */
512 bool search_flag, /* Called from a findfirst ? */
513 int *consumedcntp,
514 char **pp_targetpath)
516 char *p = NULL;
517 char *q = NULL;
518 SMB_STRUCT_STAT sbuf;
519 NTSTATUS status;
520 char *localpath = NULL;
521 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
522 components). */
524 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
525 conn->connectpath, pdp->reqpath));
528 * Note the unix path conversion here we're doing we can
529 * throw away. We're looking for a symlink for a dfs
530 * resolution, if we don't find it we'll do another
531 * unix_convert later in the codepath.
532 * If we needed to remember what we'd resolved in
533 * dp->reqpath (as the original code did) we'd
534 * copy (localhost, dp->reqpath) on any code
535 * path below that returns True - but I don't
536 * think this is needed. JRA.
539 status = unix_convert(ctx, conn, pdp->reqpath, search_flag, &localpath,
540 NULL, &sbuf);
541 if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status,
542 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
543 return status;
546 /* Optimization - check if we can redirect the whole path. */
548 if (is_msdfs_link_internal(ctx, conn, localpath, pp_targetpath, NULL)) {
549 if (search_flag) {
550 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
551 "for dfs link %s.\n", dfspath));
552 return NT_STATUS_OK;
555 DEBUG(6,("dfs_path_lookup: %s resolves to a "
556 "valid dfs link %s.\n", dfspath,
557 pp_targetpath ? *pp_targetpath : ""));
559 if (consumedcntp) {
560 *consumedcntp = strlen(dfspath);
562 return NT_STATUS_PATH_NOT_COVERED;
565 /* Prepare to test only for '/' components in the given path,
566 * so if a Windows path replace all '\\' characters with '/'.
567 * For a POSIX DFS path we know all separators are already '/'. */
569 canon_dfspath = talloc_strdup(ctx, dfspath);
570 if (!canon_dfspath) {
571 return NT_STATUS_NO_MEMORY;
573 if (!pdp->posix_path) {
574 string_replace(canon_dfspath, '\\', '/');
578 * localpath comes out of unix_convert, so it has
579 * no trailing backslash. Make sure that canon_dfspath hasn't either.
580 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
583 trim_char(canon_dfspath,0,'/');
586 * Redirect if any component in the path is a link.
587 * We do this by walking backwards through the
588 * local path, chopping off the last component
589 * in both the local path and the canonicalized
590 * DFS path. If we hit a DFS link then we're done.
593 p = strrchr_m(localpath, '/');
594 if (consumedcntp) {
595 q = strrchr_m(canon_dfspath, '/');
598 while (p) {
599 *p = '\0';
600 if (q) {
601 *q = '\0';
604 if (is_msdfs_link_internal(ctx, conn,
605 localpath, pp_targetpath, NULL)) {
606 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
607 "parent %s is dfs link\n", dfspath, localpath));
609 if (consumedcntp) {
610 *consumedcntp = strlen(canon_dfspath);
611 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
612 "(%d)\n",
613 canon_dfspath,
614 *consumedcntp));
617 return NT_STATUS_PATH_NOT_COVERED;
620 /* Step back on the filesystem. */
621 p = strrchr_m(localpath, '/');
623 if (consumedcntp) {
624 /* And in the canonicalized dfs path. */
625 q = strrchr_m(canon_dfspath, '/');
629 return NT_STATUS_OK;
632 /*****************************************************************
633 Decides if a dfs pathname should be redirected or not.
634 If not, the pathname is converted to a tcon-relative local unix path
636 search_wcard_flag: this flag performs 2 functions both related
637 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
638 for details.
640 This function can return NT_STATUS_OK, meaning use the returned path as-is
641 (mapped into a local path).
642 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
643 any other NT_STATUS error which is a genuine error to be
644 returned to the client.
645 *****************************************************************/
647 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
648 connection_struct *conn,
649 const char *path_in,
650 bool search_wcard_flag,
651 char **pp_path_out,
652 bool *ppath_contains_wcard)
654 NTSTATUS status;
655 struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
657 if (!pdp) {
658 return NT_STATUS_NO_MEMORY;
661 status = parse_dfs_path(conn, path_in, search_wcard_flag, pdp,
662 ppath_contains_wcard);
663 if (!NT_STATUS_IS_OK(status)) {
664 TALLOC_FREE(pdp);
665 return status;
668 if (pdp->reqpath[0] == '\0') {
669 TALLOC_FREE(pdp);
670 *pp_path_out = talloc_strdup(ctx, "");
671 if (!*pp_path_out) {
672 return NT_STATUS_NO_MEMORY;
674 DEBUG(5,("dfs_redirect: self-referral.\n"));
675 return NT_STATUS_OK;
678 /* If dfs pathname for a non-dfs share, convert to tcon-relative
679 path and return OK */
681 if (!lp_msdfs_root(SNUM(conn))) {
682 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
683 TALLOC_FREE(pdp);
684 if (!*pp_path_out) {
685 return NT_STATUS_NO_MEMORY;
687 return NT_STATUS_OK;
690 /* If it looked like a local path (zero hostname/servicename)
691 * just treat as a tcon-relative path. */
693 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
694 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
695 TALLOC_FREE(pdp);
696 if (!*pp_path_out) {
697 return NT_STATUS_NO_MEMORY;
699 return NT_STATUS_OK;
702 if (!( strequal(pdp->servicename, lp_servicename(SNUM(conn)))
703 || (strequal(pdp->servicename, HOMES_NAME)
704 && strequal(lp_servicename(SNUM(conn)),
705 conn->server_info->sanitized_username) )) ) {
707 /* The given sharename doesn't match this connection. */
708 TALLOC_FREE(pdp);
710 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
713 status = dfs_path_lookup(ctx, conn, path_in, pdp,
714 search_wcard_flag, NULL, NULL);
715 if (!NT_STATUS_IS_OK(status)) {
716 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
717 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
718 } else {
719 DEBUG(10,("dfs_redirect: dfs_path_lookup "
720 "failed for %s with %s\n",
721 path_in, nt_errstr(status) ));
723 return status;
726 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
728 /* Form non-dfs tcon-relative path */
729 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
730 TALLOC_FREE(pdp);
731 if (!*pp_path_out) {
732 return NT_STATUS_NO_MEMORY;
735 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
736 path_in,
737 *pp_path_out));
739 return NT_STATUS_OK;
742 /**********************************************************************
743 Return a self referral.
744 **********************************************************************/
746 static NTSTATUS self_ref(TALLOC_CTX *ctx,
747 const char *dfs_path,
748 struct junction_map *jucn,
749 int *consumedcntp,
750 bool *self_referralp)
752 struct referral *ref;
754 *self_referralp = True;
756 jucn->referral_count = 1;
757 if((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
758 return NT_STATUS_NO_MEMORY;
761 ref->alternate_path = talloc_strdup(ctx, dfs_path);
762 if (!ref->alternate_path) {
763 return NT_STATUS_NO_MEMORY;
765 ref->proximity = 0;
766 ref->ttl = REFERRAL_TTL;
767 jucn->referral_list = ref;
768 *consumedcntp = strlen(dfs_path);
769 return NT_STATUS_OK;
772 /**********************************************************************
773 Gets valid referrals for a dfs path and fills up the
774 junction_map structure.
775 **********************************************************************/
777 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
778 const char *dfs_path,
779 struct junction_map *jucn,
780 int *consumedcntp,
781 bool *self_referralp)
783 struct connection_struct *conn;
784 char *targetpath = NULL;
785 int snum;
786 NTSTATUS status = NT_STATUS_NOT_FOUND;
787 bool dummy;
788 struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
789 char *oldpath;
791 if (!pdp) {
792 return NT_STATUS_NO_MEMORY;
795 *self_referralp = False;
797 status = parse_dfs_path(NULL, dfs_path, False, pdp, &dummy);
798 if (!NT_STATUS_IS_OK(status)) {
799 return status;
802 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
803 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
804 if (!jucn->service_name || !jucn->volume_name) {
805 TALLOC_FREE(pdp);
806 return NT_STATUS_NO_MEMORY;
809 /* Verify the share is a dfs root */
810 snum = lp_servicenumber(jucn->service_name);
811 if(snum < 0) {
812 fstring service_name;
813 fstrcpy(service_name, jucn->service_name);
814 if ((snum = find_service(service_name)) < 0) {
815 return NT_STATUS_NOT_FOUND;
817 TALLOC_FREE(jucn->service_name);
818 jucn->service_name = talloc_strdup(ctx, service_name);
819 if (!jucn->service_name) {
820 TALLOC_FREE(pdp);
821 return NT_STATUS_NO_MEMORY;
825 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(snum) == '\0')) {
826 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
827 "a dfs root.\n",
828 pdp->servicename, dfs_path));
829 TALLOC_FREE(pdp);
830 return NT_STATUS_NOT_FOUND;
834 * Self referrals are tested with a anonymous IPC connection and
835 * a GET_DFS_REFERRAL call to \\server\share. (which means
836 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
837 * into the directory and will fail if it cannot (as the anonymous
838 * user). Cope with this.
841 if (pdp->reqpath[0] == '\0') {
842 char *tmp;
843 struct referral *ref;
845 if (*lp_msdfs_proxy(snum) == '\0') {
846 TALLOC_FREE(pdp);
847 return self_ref(ctx,
848 dfs_path,
849 jucn,
850 consumedcntp,
851 self_referralp);
855 * It's an msdfs proxy share. Redirect to
856 * the configured target share.
859 jucn->referral_count = 1;
860 if ((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
861 TALLOC_FREE(pdp);
862 return NT_STATUS_NO_MEMORY;
865 if (!(tmp = talloc_strdup(ctx, lp_msdfs_proxy(snum)))) {
866 TALLOC_FREE(pdp);
867 return NT_STATUS_NO_MEMORY;
870 trim_string(tmp, "\\", 0);
872 ref->alternate_path = talloc_asprintf(ctx, "\\%s", tmp);
873 TALLOC_FREE(tmp);
875 if (!ref->alternate_path) {
876 TALLOC_FREE(pdp);
877 return NT_STATUS_NO_MEMORY;
880 if (pdp->reqpath[0] != '\0') {
881 ref->alternate_path = talloc_asprintf_append(
882 ref->alternate_path,
883 "%s",
884 pdp->reqpath);
885 if (!ref->alternate_path) {
886 TALLOC_FREE(pdp);
887 return NT_STATUS_NO_MEMORY;
890 ref->proximity = 0;
891 ref->ttl = REFERRAL_TTL;
892 jucn->referral_list = ref;
893 *consumedcntp = strlen(dfs_path);
894 TALLOC_FREE(pdp);
895 return NT_STATUS_OK;
898 status = create_conn_struct(ctx, &conn, snum, lp_pathname(snum),
899 NULL, &oldpath);
900 if (!NT_STATUS_IS_OK(status)) {
901 TALLOC_FREE(pdp);
902 return status;
905 /* If this is a DFS path dfs_lookup should return
906 * NT_STATUS_PATH_NOT_COVERED. */
908 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
909 False, consumedcntp, &targetpath);
911 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
912 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
913 dfs_path));
914 vfs_ChDir(conn, oldpath);
915 conn_free_internal(conn);
916 TALLOC_FREE(pdp);
917 return status;
920 /* We know this is a valid dfs link. Parse the targetpath. */
921 if (!parse_msdfs_symlink(ctx, targetpath,
922 &jucn->referral_list,
923 &jucn->referral_count)) {
924 DEBUG(3,("get_referred_path: failed to parse symlink "
925 "target %s\n", targetpath ));
926 vfs_ChDir(conn, oldpath);
927 conn_free_internal(conn);
928 TALLOC_FREE(pdp);
929 return NT_STATUS_NOT_FOUND;
932 vfs_ChDir(conn, oldpath);
933 conn_free_internal(conn);
934 TALLOC_FREE(pdp);
935 return NT_STATUS_OK;
938 static int setup_ver2_dfs_referral(const char *pathname,
939 char **ppdata,
940 struct junction_map *junction,
941 bool self_referral)
943 char* pdata = *ppdata;
945 smb_ucs2_t *uni_requestedpath = NULL;
946 int uni_reqpathoffset1,uni_reqpathoffset2;
947 int uni_curroffset;
948 int requestedpathlen=0;
949 int offset;
950 int reply_size = 0;
951 int i=0;
953 DEBUG(10,("Setting up version2 referral\nRequested path:\n"));
955 requestedpathlen = rpcstr_push_talloc(talloc_tos(),
956 &uni_requestedpath, pathname);
957 if (uni_requestedpath == NULL || requestedpathlen == 0) {
958 return -1;
961 if (DEBUGLVL(10)) {
962 dump_data(0, (unsigned char *)uni_requestedpath,
963 requestedpathlen);
966 DEBUG(10,("ref count = %u\n",junction->referral_count));
968 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
969 VERSION2_REFERRAL_SIZE * junction->referral_count;
971 uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen;
973 uni_curroffset = uni_reqpathoffset2 + requestedpathlen;
975 reply_size = REFERRAL_HEADER_SIZE +
976 VERSION2_REFERRAL_SIZE*junction->referral_count +
977 2 * requestedpathlen;
978 DEBUG(10,("reply_size: %u\n",reply_size));
980 /* add up the unicode lengths of all the referral paths */
981 for(i=0;i<junction->referral_count;i++) {
982 DEBUG(10,("referral %u : %s\n",
984 junction->referral_list[i].alternate_path));
985 reply_size +=
986 (strlen(junction->referral_list[i].alternate_path)+1)*2;
989 DEBUG(10,("reply_size = %u\n",reply_size));
990 /* add the unexplained 0x16 bytes */
991 reply_size += 0x16;
993 pdata = (char *)SMB_REALLOC(pdata,reply_size);
994 if(pdata == NULL) {
995 DEBUG(0,("Realloc failed!\n"));
996 return -1;
998 *ppdata = pdata;
1000 /* copy in the dfs requested paths.. required for offset calculations */
1001 memcpy(pdata+uni_reqpathoffset1,uni_requestedpath,requestedpathlen);
1002 memcpy(pdata+uni_reqpathoffset2,uni_requestedpath,requestedpathlen);
1004 /* create the header */
1005 SSVAL(pdata,0,requestedpathlen - 2); /* UCS2 of path consumed minus
1006 2 byte null */
1007 /* number of referral in this pkt */
1008 SSVAL(pdata,2,junction->referral_count);
1009 if(self_referral) {
1010 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
1011 } else {
1012 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
1015 offset = 8;
1016 /* add the referral elements */
1017 for(i=0;i<junction->referral_count;i++) {
1018 struct referral* ref = &junction->referral_list[i];
1019 int unilen;
1021 SSVAL(pdata,offset,2); /* version 2 */
1022 SSVAL(pdata,offset+2,VERSION2_REFERRAL_SIZE);
1023 if(self_referral) {
1024 SSVAL(pdata,offset+4,1);
1025 } else {
1026 SSVAL(pdata,offset+4,0);
1029 /* ref_flags :use path_consumed bytes? */
1030 SSVAL(pdata,offset+6,0);
1031 SIVAL(pdata,offset+8,ref->proximity);
1032 SIVAL(pdata,offset+12,ref->ttl);
1034 SSVAL(pdata,offset+16,uni_reqpathoffset1-offset);
1035 SSVAL(pdata,offset+18,uni_reqpathoffset2-offset);
1036 /* copy referred path into current offset */
1037 unilen = rpcstr_push(pdata+uni_curroffset,
1038 ref->alternate_path,
1039 reply_size - uni_curroffset,
1040 STR_UNICODE);
1042 SSVAL(pdata,offset+20,uni_curroffset-offset);
1044 uni_curroffset += unilen;
1045 offset += VERSION2_REFERRAL_SIZE;
1047 /* add in the unexplained 22 (0x16) bytes at the end */
1048 memset(pdata+uni_curroffset,'\0',0x16);
1049 return reply_size;
1052 static int setup_ver3_dfs_referral(const char *pathname,
1053 char **ppdata,
1054 struct junction_map *junction,
1055 bool self_referral)
1057 char *pdata = *ppdata;
1059 smb_ucs2_t *uni_reqpath = NULL;
1060 int uni_reqpathoffset1, uni_reqpathoffset2;
1061 int uni_curroffset;
1062 int reply_size = 0;
1064 int reqpathlen = 0;
1065 int offset,i=0;
1067 DEBUG(10,("setting up version3 referral\n"));
1069 reqpathlen = rpcstr_push_talloc(talloc_tos(), &uni_reqpath, pathname);
1070 if (uni_reqpath == NULL || reqpathlen == 0) {
1071 return -1;
1074 if (DEBUGLVL(10)) {
1075 dump_data(0, (unsigned char *)uni_reqpath,
1076 reqpathlen);
1079 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
1080 VERSION3_REFERRAL_SIZE * junction->referral_count;
1081 uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen;
1082 reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen;
1084 for(i=0;i<junction->referral_count;i++) {
1085 DEBUG(10,("referral %u : %s\n",
1087 junction->referral_list[i].alternate_path));
1088 reply_size +=
1089 (strlen(junction->referral_list[i].alternate_path)+1)*2;
1092 pdata = (char *)SMB_REALLOC(pdata,reply_size);
1093 if(pdata == NULL) {
1094 DEBUG(0,("version3 referral setup:"
1095 "malloc failed for Realloc!\n"));
1096 return -1;
1098 *ppdata = pdata;
1100 /* create the header */
1101 SSVAL(pdata,0,reqpathlen - 2); /* UCS2 of path consumed minus
1102 2 byte null */
1103 SSVAL(pdata,2,junction->referral_count); /* number of referral */
1104 if(self_referral) {
1105 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
1106 } else {
1107 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
1110 /* copy in the reqpaths */
1111 memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen);
1112 memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen);
1114 offset = 8;
1115 for(i=0;i<junction->referral_count;i++) {
1116 struct referral* ref = &(junction->referral_list[i]);
1117 int unilen;
1119 SSVAL(pdata,offset,3); /* version 3 */
1120 SSVAL(pdata,offset+2,VERSION3_REFERRAL_SIZE);
1121 if(self_referral) {
1122 SSVAL(pdata,offset+4,1);
1123 } else {
1124 SSVAL(pdata,offset+4,0);
1127 /* ref_flags :use path_consumed bytes? */
1128 SSVAL(pdata,offset+6,0);
1129 SIVAL(pdata,offset+8,ref->ttl);
1131 SSVAL(pdata,offset+12,uni_reqpathoffset1-offset);
1132 SSVAL(pdata,offset+14,uni_reqpathoffset2-offset);
1133 /* copy referred path into current offset */
1134 unilen = rpcstr_push(pdata+uni_curroffset,ref->alternate_path,
1135 reply_size - uni_curroffset,
1136 STR_UNICODE | STR_TERMINATE);
1137 SSVAL(pdata,offset+16,uni_curroffset-offset);
1138 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
1139 memset(pdata+offset+18,'\0',16);
1141 uni_curroffset += unilen;
1142 offset += VERSION3_REFERRAL_SIZE;
1144 return reply_size;
1147 /******************************************************************
1148 Set up the DFS referral for the dfs pathname. This call returns
1149 the amount of the path covered by this server, and where the
1150 client should be redirected to. This is the meat of the
1151 TRANS2_GET_DFS_REFERRAL call.
1152 ******************************************************************/
1154 int setup_dfs_referral(connection_struct *orig_conn,
1155 const char *dfs_path,
1156 int max_referral_level,
1157 char **ppdata, NTSTATUS *pstatus)
1159 struct junction_map *junction = NULL;
1160 int consumedcnt = 0;
1161 bool self_referral = False;
1162 int reply_size = 0;
1163 char *pathnamep = NULL;
1164 char *local_dfs_path = NULL;
1165 TALLOC_CTX *ctx;
1167 if (!(ctx=talloc_init("setup_dfs_referral"))) {
1168 *pstatus = NT_STATUS_NO_MEMORY;
1169 return -1;
1172 /* get the junction entry */
1173 if (!dfs_path) {
1174 talloc_destroy(ctx);
1175 *pstatus = NT_STATUS_NOT_FOUND;
1176 return -1;
1180 * Trim pathname sent by client so it begins with only one backslash.
1181 * Two backslashes confuse some dfs clients
1184 local_dfs_path = talloc_strdup(ctx,dfs_path);
1185 if (!local_dfs_path) {
1186 *pstatus = NT_STATUS_NO_MEMORY;
1187 talloc_destroy(ctx);
1188 return -1;
1190 pathnamep = local_dfs_path;
1191 while (IS_DIRECTORY_SEP(pathnamep[0]) &&
1192 IS_DIRECTORY_SEP(pathnamep[1])) {
1193 pathnamep++;
1196 junction = TALLOC_ZERO_P(ctx, struct junction_map);
1197 if (!junction) {
1198 *pstatus = NT_STATUS_NO_MEMORY;
1199 talloc_destroy(ctx);
1200 return -1;
1203 /* The following call can change cwd. */
1204 *pstatus = get_referred_path(ctx, pathnamep, junction,
1205 &consumedcnt, &self_referral);
1206 if (!NT_STATUS_IS_OK(*pstatus)) {
1207 vfs_ChDir(orig_conn,orig_conn->connectpath);
1208 talloc_destroy(ctx);
1209 return -1;
1211 vfs_ChDir(orig_conn,orig_conn->connectpath);
1213 if (!self_referral) {
1214 pathnamep[consumedcnt] = '\0';
1216 if( DEBUGLVL( 3 ) ) {
1217 int i=0;
1218 dbgtext("setup_dfs_referral: Path %s to "
1219 "alternate path(s):",
1220 pathnamep);
1221 for(i=0;i<junction->referral_count;i++)
1222 dbgtext(" %s",
1223 junction->referral_list[i].alternate_path);
1224 dbgtext(".\n");
1228 /* create the referral depeding on version */
1229 DEBUG(10,("max_referral_level :%d\n",max_referral_level));
1231 if (max_referral_level < 2) {
1232 max_referral_level = 2;
1234 if (max_referral_level > 3) {
1235 max_referral_level = 3;
1238 switch(max_referral_level) {
1239 case 2:
1240 reply_size = setup_ver2_dfs_referral(pathnamep,
1241 ppdata, junction,
1242 self_referral);
1243 break;
1244 case 3:
1245 reply_size = setup_ver3_dfs_referral(pathnamep, ppdata,
1246 junction, self_referral);
1247 break;
1248 default:
1249 DEBUG(0,("setup_dfs_referral: Invalid dfs referral "
1250 "version: %d\n",
1251 max_referral_level));
1252 talloc_destroy(ctx);
1253 *pstatus = NT_STATUS_INVALID_LEVEL;
1254 return -1;
1257 if (DEBUGLVL(10)) {
1258 DEBUGADD(0,("DFS Referral pdata:\n"));
1259 dump_data(0,(uint8 *)*ppdata,reply_size);
1262 talloc_destroy(ctx);
1263 *pstatus = NT_STATUS_OK;
1264 return reply_size;
1267 /**********************************************************************
1268 The following functions are called by the NETDFS RPC pipe functions
1269 **********************************************************************/
1271 /*********************************************************************
1272 Creates a junction structure from a DFS pathname
1273 **********************************************************************/
1275 bool create_junction(TALLOC_CTX *ctx,
1276 const char *dfs_path,
1277 struct junction_map *jucn)
1279 int snum;
1280 bool dummy;
1281 struct dfs_path *pdp = TALLOC_P(ctx,struct dfs_path);
1282 NTSTATUS status;
1284 if (!pdp) {
1285 return False;
1287 status = parse_dfs_path(NULL, dfs_path, False, pdp, &dummy);
1288 if (!NT_STATUS_IS_OK(status)) {
1289 return False;
1292 /* check if path is dfs : validate first token */
1293 if (!is_myname_or_ipaddr(pdp->hostname)) {
1294 DEBUG(4,("create_junction: Invalid hostname %s "
1295 "in dfs path %s\n",
1296 pdp->hostname, dfs_path));
1297 TALLOC_FREE(pdp);
1298 return False;
1301 /* Check for a non-DFS share */
1302 snum = lp_servicenumber(pdp->servicename);
1304 if(snum < 0 || !lp_msdfs_root(snum)) {
1305 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1306 pdp->servicename));
1307 TALLOC_FREE(pdp);
1308 return False;
1311 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1312 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1313 jucn->comment = talloc_strdup(ctx, lp_comment(snum));
1315 TALLOC_FREE(pdp);
1316 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1317 return False;
1319 return True;
1322 /**********************************************************************
1323 Forms a valid Unix pathname from the junction
1324 **********************************************************************/
1326 static bool junction_to_local_path(const struct junction_map *jucn,
1327 char **pp_path_out,
1328 connection_struct **conn_out,
1329 char **oldpath)
1331 int snum;
1332 NTSTATUS status;
1334 snum = lp_servicenumber(jucn->service_name);
1335 if(snum < 0) {
1336 return False;
1338 status = create_conn_struct(talloc_tos(), conn_out, snum,
1339 lp_pathname(snum), NULL, oldpath);
1340 if (!NT_STATUS_IS_OK(status)) {
1341 return False;
1344 *pp_path_out = talloc_asprintf(*conn_out,
1345 "%s/%s",
1346 lp_pathname(snum),
1347 jucn->volume_name);
1348 if (!*pp_path_out) {
1349 vfs_ChDir(*conn_out, *oldpath);
1350 conn_free_internal(*conn_out);
1351 return False;
1353 return True;
1356 bool create_msdfs_link(const struct junction_map *jucn)
1358 char *path = NULL;
1359 char *cwd;
1360 char *msdfs_link = NULL;
1361 connection_struct *conn;
1362 int i=0;
1363 bool insert_comma = False;
1364 bool ret = False;
1366 if(!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1367 return False;
1370 /* Form the msdfs_link contents */
1371 msdfs_link = talloc_strdup(conn, "msdfs:");
1372 if (!msdfs_link) {
1373 goto out;
1375 for(i=0; i<jucn->referral_count; i++) {
1376 char *refpath = jucn->referral_list[i].alternate_path;
1378 /* Alternate paths always use Windows separators. */
1379 trim_char(refpath, '\\', '\\');
1380 if(*refpath == '\0') {
1381 if (i == 0) {
1382 insert_comma = False;
1384 continue;
1386 if (i > 0 && insert_comma) {
1387 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1388 ",%s",
1389 refpath);
1390 } else {
1391 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1392 "%s",
1393 refpath);
1396 if (!msdfs_link) {
1397 goto out;
1399 if (!insert_comma) {
1400 insert_comma = True;
1404 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1405 path, msdfs_link));
1407 if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1408 if (errno == EEXIST) {
1409 if(SMB_VFS_UNLINK(conn,path)!=0) {
1410 goto out;
1413 if (SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1414 DEBUG(1,("create_msdfs_link: symlink failed "
1415 "%s -> %s\nError: %s\n",
1416 path, msdfs_link, strerror(errno)));
1417 goto out;
1421 ret = True;
1423 out:
1424 vfs_ChDir(conn, cwd);
1425 conn_free_internal(conn);
1426 return ret;
1429 bool remove_msdfs_link(const struct junction_map *jucn)
1431 char *path = NULL;
1432 char *cwd;
1433 connection_struct *conn;
1434 bool ret = False;
1436 if (!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1437 return false;
1440 if( SMB_VFS_UNLINK(conn, path) == 0 ) {
1441 ret = True;
1444 vfs_ChDir(conn, cwd);
1445 conn_free_internal(conn);
1446 return ret;
1449 /*********************************************************************
1450 Return the number of DFS links at the root of this share.
1451 *********************************************************************/
1453 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1455 size_t cnt = 0;
1456 SMB_STRUCT_DIR *dirp = NULL;
1457 char *dname = NULL;
1458 const char *connect_path = lp_pathname(snum);
1459 const char *msdfs_proxy = lp_msdfs_proxy(snum);
1460 connection_struct *conn;
1461 NTSTATUS status;
1462 char *cwd;
1464 if(*connect_path == '\0') {
1465 return 0;
1469 * Fake up a connection struct for the VFS layer.
1472 status = create_conn_struct(talloc_tos(), &conn, snum, connect_path,
1473 NULL, &cwd);
1474 if (!NT_STATUS_IS_OK(status)) {
1475 DEBUG(3, ("create_conn_struct failed: %s\n",
1476 nt_errstr(status)));
1477 return 0;
1480 /* Count a link for the msdfs root - convention */
1481 cnt = 1;
1483 /* No more links if this is an msdfs proxy. */
1484 if (*msdfs_proxy != '\0') {
1485 goto out;
1488 /* Now enumerate all dfs links */
1489 dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1490 if(!dirp) {
1491 goto out;
1494 while ((dname = vfs_readdirname(conn, dirp, NULL)) != NULL) {
1495 if (is_msdfs_link(conn,
1496 dname,
1497 NULL)) {
1498 cnt++;
1502 SMB_VFS_CLOSEDIR(conn,dirp);
1504 out:
1505 vfs_ChDir(conn, cwd);
1506 conn_free_internal(conn);
1507 return cnt;
1510 /*********************************************************************
1511 *********************************************************************/
1513 static int form_junctions(TALLOC_CTX *ctx,
1514 int snum,
1515 struct junction_map *jucn,
1516 size_t jn_remain)
1518 size_t cnt = 0;
1519 SMB_STRUCT_DIR *dirp = NULL;
1520 char *dname = NULL;
1521 const char *connect_path = lp_pathname(snum);
1522 char *service_name = lp_servicename(snum);
1523 const char *msdfs_proxy = lp_msdfs_proxy(snum);
1524 connection_struct *conn;
1525 struct referral *ref = NULL;
1526 char *cwd;
1527 NTSTATUS status;
1529 if (jn_remain == 0) {
1530 return 0;
1533 if(*connect_path == '\0') {
1534 return 0;
1538 * Fake up a connection struct for the VFS layer.
1541 status = create_conn_struct(ctx, &conn, snum, connect_path, NULL,
1542 &cwd);
1543 if (!NT_STATUS_IS_OK(status)) {
1544 DEBUG(3, ("create_conn_struct failed: %s\n",
1545 nt_errstr(status)));
1546 return 0;
1549 /* form a junction for the msdfs root - convention
1550 DO NOT REMOVE THIS: NT clients will not work with us
1551 if this is not present
1553 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1554 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1555 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1556 goto out;
1558 jucn[cnt].comment = "";
1559 jucn[cnt].referral_count = 1;
1561 ref = jucn[cnt].referral_list = TALLOC_ZERO_P(ctx, struct referral);
1562 if (jucn[cnt].referral_list == NULL) {
1563 goto out;
1566 ref->proximity = 0;
1567 ref->ttl = REFERRAL_TTL;
1568 if (*msdfs_proxy != '\0') {
1569 ref->alternate_path = talloc_strdup(ctx,
1570 msdfs_proxy);
1571 } else {
1572 ref->alternate_path = talloc_asprintf(ctx,
1573 "\\\\%s\\%s",
1574 get_local_machine_name(),
1575 service_name);
1578 if (!ref->alternate_path) {
1579 goto out;
1581 cnt++;
1583 /* Don't enumerate if we're an msdfs proxy. */
1584 if (*msdfs_proxy != '\0') {
1585 goto out;
1588 /* Now enumerate all dfs links */
1589 dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1590 if(!dirp) {
1591 goto out;
1594 while ((dname = vfs_readdirname(conn, dirp, NULL)) != NULL) {
1595 char *link_target = NULL;
1596 if (cnt >= jn_remain) {
1597 DEBUG(2, ("form_junctions: ran out of MSDFS "
1598 "junction slots"));
1599 goto out;
1601 if (is_msdfs_link_internal(ctx,
1602 conn,
1603 dname, &link_target,
1604 NULL)) {
1605 if (parse_msdfs_symlink(ctx,
1606 link_target,
1607 &jucn[cnt].referral_list,
1608 &jucn[cnt].referral_count)) {
1610 jucn[cnt].service_name = talloc_strdup(ctx,
1611 service_name);
1612 jucn[cnt].volume_name = talloc_strdup(ctx,
1613 dname);
1614 if (!jucn[cnt].service_name ||
1615 !jucn[cnt].volume_name) {
1616 goto out;
1618 jucn[cnt].comment = "";
1619 cnt++;
1621 TALLOC_FREE(link_target);
1625 out:
1627 if (dirp) {
1628 SMB_VFS_CLOSEDIR(conn,dirp);
1631 vfs_ChDir(conn, cwd);
1632 conn_free_internal(conn);
1633 return cnt;
1636 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1638 struct junction_map *jn = NULL;
1639 int i=0;
1640 size_t jn_count = 0;
1641 int sharecount = 0;
1643 *p_num_jn = 0;
1644 if(!lp_host_msdfs()) {
1645 return NULL;
1648 /* Ensure all the usershares are loaded. */
1649 become_root();
1650 load_registry_shares();
1651 sharecount = load_usershare_shares();
1652 unbecome_root();
1654 for(i=0;i < sharecount;i++) {
1655 if(lp_msdfs_root(i)) {
1656 jn_count += count_dfs_links(ctx, i);
1659 if (jn_count == 0) {
1660 return NULL;
1662 jn = TALLOC_ARRAY(ctx, struct junction_map, jn_count);
1663 if (!jn) {
1664 return NULL;
1666 for(i=0; i < sharecount; i++) {
1667 if (*p_num_jn >= jn_count) {
1668 break;
1670 if(lp_msdfs_root(i)) {
1671 *p_num_jn += form_junctions(ctx, i,
1672 &jn[*p_num_jn],
1673 jn_count - *p_num_jn);
1676 return jn;
1679 /******************************************************************************
1680 Core function to resolve a dfs pathname.
1681 ******************************************************************************/
1683 NTSTATUS resolve_dfspath(TALLOC_CTX *ctx,
1684 connection_struct *conn,
1685 bool dfs_pathnames,
1686 const char *name_in,
1687 char **pp_name_out)
1689 NTSTATUS status = NT_STATUS_OK;
1690 bool dummy;
1691 if (dfs_pathnames) {
1692 status = dfs_redirect(ctx,
1693 conn,
1694 name_in,
1695 False,
1696 pp_name_out,
1697 &dummy);
1698 } else {
1700 * Cheat and just return a copy of the in ptr.
1701 * Once srvstr_get_path() uses talloc it'll
1702 * be a talloced ptr anyway.
1704 *pp_name_out = CONST_DISCARD(char *,name_in);
1706 return status;
1709 /******************************************************************************
1710 Core function to resolve a dfs pathname possibly containing a wildcard.
1711 This function is identical to the above except for the bool param to
1712 dfs_redirect but I need this to be separate so it's really clear when
1713 we're allowing wildcards and when we're not. JRA.
1714 ******************************************************************************/
1716 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1717 connection_struct *conn,
1718 bool dfs_pathnames,
1719 const char *name_in,
1720 char **pp_name_out,
1721 bool *ppath_contains_wcard)
1723 NTSTATUS status = NT_STATUS_OK;
1724 if (dfs_pathnames) {
1725 status = dfs_redirect(ctx,
1726 conn,
1727 name_in,
1728 True,
1729 pp_name_out,
1730 ppath_contains_wcard);
1731 } else {
1733 * Cheat and just return a copy of the in ptr.
1734 * Once srvstr_get_path() uses talloc it'll
1735 * be a talloced ptr anyway.
1737 *pp_name_out = CONST_DISCARD(char *,name_in);
1739 return status;