auth: Make sure that creds_out is initialized with NULL.
[Samba.git] / source3 / smbd / msdfs.c
blob8a886342eaab7bc8ba25df1418ce5a6cbf1754b4
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 "system/filesys.h"
26 #include "smbd/smbd.h"
27 #include "smbd/globals.h"
28 #include "msdfs.h"
29 #include "auth.h"
30 #include "lib/param/loadparm.h"
31 #include "libcli/security/security.h"
32 #include "librpc/gen_ndr/ndr_dfsblobs.h"
34 /**********************************************************************
35 Parse a DFS pathname of the form \hostname\service\reqpath
36 into the dfs_path structure.
37 If POSIX pathnames is true, the pathname may also be of the
38 form /hostname/service/reqpath.
39 We cope with either here.
41 Unfortunately, due to broken clients who might set the
42 SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
43 send a local path, we have to cope with that too....
45 If conn != NULL then ensure the provided service is
46 the one pointed to by the connection.
48 This version does everything using pointers within one copy of the
49 pathname string, talloced on the struct dfs_path pointer (which
50 must be talloced). This may be too clever to live....
51 JRA.
52 **********************************************************************/
54 static NTSTATUS parse_dfs_path(connection_struct *conn,
55 const char *pathname,
56 bool allow_wcards,
57 bool allow_broken_path,
58 struct dfs_path *pdp, /* MUST BE TALLOCED */
59 bool *ppath_contains_wcard)
61 char *pathname_local;
62 char *p,*temp;
63 char *servicename;
64 char *eos_ptr;
65 NTSTATUS status = NT_STATUS_OK;
66 char sepchar;
68 ZERO_STRUCTP(pdp);
71 * This is the only talloc we should need to do
72 * on the struct dfs_path. All the pointers inside
73 * it should point to offsets within this string.
76 pathname_local = talloc_strdup(pdp, pathname);
77 if (!pathname_local) {
78 return NT_STATUS_NO_MEMORY;
80 /* Get a pointer to the terminating '\0' */
81 eos_ptr = &pathname_local[strlen(pathname_local)];
82 p = temp = pathname_local;
84 pdp->posix_path = (lp_posix_pathnames() && *pathname == '/');
86 sepchar = pdp->posix_path ? '/' : '\\';
88 if (allow_broken_path && (*pathname != sepchar)) {
89 DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
90 pathname, sepchar ));
92 * Possibly client sent a local path by mistake.
93 * Try and convert to a local path.
96 pdp->hostname = eos_ptr; /* "" */
97 pdp->servicename = eos_ptr; /* "" */
99 /* We've got no info about separators. */
100 pdp->posix_path = lp_posix_pathnames();
101 p = temp;
102 DEBUG(10,("parse_dfs_path: trying to convert %s to a "
103 "local path\n",
104 temp));
105 goto local_path;
109 * Safe to use on talloc'ed string as it only shrinks.
110 * It also doesn't affect the eos_ptr.
112 trim_char(temp,sepchar,sepchar);
114 DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
115 temp, sepchar));
117 /* Now tokenize. */
118 /* Parse out hostname. */
119 p = strchr_m(temp,sepchar);
120 if(p == NULL) {
121 DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
122 temp));
124 * Possibly client sent a local path by mistake.
125 * Try and convert to a local path.
128 pdp->hostname = eos_ptr; /* "" */
129 pdp->servicename = eos_ptr; /* "" */
131 p = temp;
132 DEBUG(10,("parse_dfs_path: trying to convert %s "
133 "to a local path\n",
134 temp));
135 goto local_path;
137 *p = '\0';
138 pdp->hostname = temp;
140 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
142 /* Parse out servicename. */
143 servicename = p+1;
144 p = strchr_m(servicename,sepchar);
145 if (p) {
146 *p = '\0';
149 /* Is this really our servicename ? */
150 if (conn && !( strequal(servicename, lp_servicename(talloc_tos(), SNUM(conn)))
151 || (strequal(servicename, HOMES_NAME)
152 && strequal(lp_servicename(talloc_tos(), SNUM(conn)),
153 get_current_username()) )) ) {
154 DEBUG(10,("parse_dfs_path: %s is not our servicename\n",
155 servicename));
158 * Possibly client sent a local path by mistake.
159 * Try and convert to a local path.
162 pdp->hostname = eos_ptr; /* "" */
163 pdp->servicename = eos_ptr; /* "" */
165 /* Repair the path - replace the sepchar's
166 we nulled out */
167 servicename--;
168 *servicename = sepchar;
169 if (p) {
170 *p = sepchar;
173 p = temp;
174 DEBUG(10,("parse_dfs_path: trying to convert %s "
175 "to a local path\n",
176 temp));
177 goto local_path;
180 pdp->servicename = servicename;
182 DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
184 if(p == NULL) {
185 /* Client sent self referral \server\share. */
186 pdp->reqpath = eos_ptr; /* "" */
187 return NT_STATUS_OK;
190 p++;
192 local_path:
194 *ppath_contains_wcard = False;
196 pdp->reqpath = p;
198 /* Rest is reqpath. */
199 if (pdp->posix_path) {
200 status = check_path_syntax_posix(pdp->reqpath);
201 } else {
202 if (allow_wcards) {
203 status = check_path_syntax_wcard(pdp->reqpath,
204 ppath_contains_wcard);
205 } else {
206 status = check_path_syntax(pdp->reqpath);
210 if (!NT_STATUS_IS_OK(status)) {
211 DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
212 p, nt_errstr(status) ));
213 return status;
216 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
217 return NT_STATUS_OK;
220 /********************************************************
221 Fake up a connection struct for the VFS layer, for use in
222 applications (such as the python bindings), that do not want the
223 global working directory changed under them.
225 SMB_VFS_CONNECT requires root privileges.
226 *********************************************************/
228 static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx,
229 struct tevent_context *ev,
230 struct messaging_context *msg,
231 connection_struct **pconn,
232 int snum,
233 const char *path,
234 const struct auth_session_info *session_info)
236 connection_struct *conn;
237 char *connpath;
238 const char *vfs_user;
240 conn = talloc_zero(ctx, connection_struct);
241 if (conn == NULL) {
242 return NT_STATUS_NO_MEMORY;
245 connpath = talloc_strdup(conn, path);
246 if (!connpath) {
247 TALLOC_FREE(conn);
248 return NT_STATUS_NO_MEMORY;
250 connpath = talloc_string_sub(conn,
251 connpath,
252 "%S",
253 lp_servicename(talloc_tos(), snum));
254 if (!connpath) {
255 TALLOC_FREE(conn);
256 return NT_STATUS_NO_MEMORY;
259 conn->sconn = talloc_zero(conn, struct smbd_server_connection);
260 if (conn->sconn == NULL) {
261 TALLOC_FREE(conn);
262 return NT_STATUS_NO_MEMORY;
265 conn->sconn->ev_ctx = ev;
266 conn->sconn->msg_ctx = msg;
267 conn->sconn->sock = -1;
268 conn->sconn->smb1.echo_handler.trusted_fd = -1;
269 conn->sconn->smb1.echo_handler.socket_lock_fd = -1;
271 /* needed for smbd_vfs_init() */
273 if (!(conn->params = talloc_zero(conn, struct share_params))) {
274 DEBUG(0, ("TALLOC failed\n"));
275 TALLOC_FREE(conn);
276 return NT_STATUS_NO_MEMORY;
279 conn->params->service = snum;
280 conn->cnum = TID_FIELD_INVALID;
282 DLIST_ADD(conn->sconn->connections, conn);
283 conn->sconn->num_connections++;
285 if (session_info != NULL) {
286 conn->session_info = copy_session_info(conn, session_info);
287 if (conn->session_info == NULL) {
288 DEBUG(0, ("copy_serverinfo failed\n"));
289 TALLOC_FREE(conn);
290 return NT_STATUS_NO_MEMORY;
292 vfs_user = conn->session_info->unix_info->unix_name;
293 } else {
294 /* use current authenticated user in absence of session_info */
295 vfs_user = get_current_username();
298 set_conn_connectpath(conn, connpath);
301 * New code to check if there's a share security descripter
302 * added from NT server manager. This is done after the
303 * smb.conf checks are done as we need a uid and token. JRA.
306 if (conn->session_info) {
307 share_access_check(conn->session_info->security_token,
308 lp_servicename(talloc_tos(), snum),
309 MAXIMUM_ALLOWED_ACCESS,
310 &conn->share_access);
312 if ((conn->share_access & FILE_WRITE_DATA) == 0) {
313 if ((conn->share_access & FILE_READ_DATA) == 0) {
314 /* No access, read or write. */
315 DEBUG(0,("create_conn_struct: connection to %s "
316 "denied due to security "
317 "descriptor.\n",
318 lp_servicename(talloc_tos(), snum)));
319 conn_free(conn);
320 return NT_STATUS_ACCESS_DENIED;
321 } else {
322 conn->read_only = true;
325 } else {
326 conn->share_access = 0;
327 conn->read_only = true;
330 if (!smbd_vfs_init(conn)) {
331 NTSTATUS status = map_nt_error_from_unix(errno);
332 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
333 conn_free(conn);
334 return status;
337 /* this must be the first filesystem operation that we do */
338 if (SMB_VFS_CONNECT(conn, lp_servicename(talloc_tos(), snum), vfs_user) < 0) {
339 DEBUG(0,("VFS connect failed!\n"));
340 conn_free(conn);
341 return NT_STATUS_UNSUCCESSFUL;
344 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
345 *pconn = conn;
347 return NT_STATUS_OK;
350 /********************************************************
351 Fake up a connection struct for the VFS layer, for use in
352 applications (such as the python bindings), that do not want the
353 global working directory changed under them.
355 SMB_VFS_CONNECT requires root privileges.
356 *********************************************************/
358 NTSTATUS create_conn_struct(TALLOC_CTX *ctx,
359 struct tevent_context *ev,
360 struct messaging_context *msg,
361 connection_struct **pconn,
362 int snum,
363 const char *path,
364 const struct auth_session_info *session_info)
366 NTSTATUS status;
367 become_root();
368 status = create_conn_struct_as_root(ctx, ev,
369 msg, pconn,
370 snum, path,
371 session_info);
372 unbecome_root();
374 return status;
377 /********************************************************
378 Fake up a connection struct for the VFS layer.
379 Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
381 The old working directory is returned on *poldcwd, allocated on ctx.
382 *********************************************************/
384 NTSTATUS create_conn_struct_cwd(TALLOC_CTX *ctx,
385 struct tevent_context *ev,
386 struct messaging_context *msg,
387 connection_struct **pconn,
388 int snum,
389 const char *path,
390 const struct auth_session_info *session_info,
391 char **poldcwd)
393 connection_struct *conn;
394 char *oldcwd;
396 NTSTATUS status = create_conn_struct(ctx, ev,
397 msg, &conn,
398 snum, path,
399 session_info);
400 if (!NT_STATUS_IS_OK(status)) {
401 return status;
405 * Windows seems to insist on doing trans2getdfsreferral() calls on
406 * the IPC$ share as the anonymous user. If we try to chdir as that
407 * user we will fail.... WTF ? JRA.
410 oldcwd = vfs_GetWd(ctx, conn);
411 if (oldcwd == NULL) {
412 status = map_nt_error_from_unix(errno);
413 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
414 conn_free(conn);
415 return status;
418 if (vfs_ChDir(conn,conn->connectpath) != 0) {
419 status = map_nt_error_from_unix(errno);
420 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
421 "Error was %s\n",
422 conn->connectpath, strerror(errno) ));
423 conn_free(conn);
424 return status;
427 *pconn = conn;
428 *poldcwd = oldcwd;
430 return NT_STATUS_OK;
433 /**********************************************************************
434 Parse the contents of a symlink to verify if it is an msdfs referral
435 A valid referral is of the form:
437 msdfs:server1\share1,server2\share2
438 msdfs:server1\share1\pathname,server2\share2\pathname
439 msdfs:server1/share1,server2/share2
440 msdfs:server1/share1/pathname,server2/share2/pathname.
442 Note that the alternate paths returned here must be of the canonicalized
443 form:
445 \server\share or
446 \server\share\path\to\file,
448 even in posix path mode. This is because we have no knowledge if the
449 server we're referring to understands posix paths.
450 **********************************************************************/
452 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
453 const char *target,
454 struct referral **preflist,
455 int *refcount)
457 char *temp = NULL;
458 char *prot;
459 char **alt_path = NULL;
460 int count = 0, i;
461 struct referral *reflist;
462 char *saveptr;
464 temp = talloc_strdup(ctx, target);
465 if (!temp) {
466 return False;
468 prot = strtok_r(temp, ":", &saveptr);
469 if (!prot) {
470 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
471 return False;
474 alt_path = talloc_array(ctx, char *, MAX_REFERRAL_COUNT);
475 if (!alt_path) {
476 return False;
479 /* parse out the alternate paths */
480 while((count<MAX_REFERRAL_COUNT) &&
481 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
482 count++;
485 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
487 if (count) {
488 reflist = *preflist = talloc_zero_array(ctx,
489 struct referral, count);
490 if(reflist == NULL) {
491 TALLOC_FREE(alt_path);
492 return False;
494 } else {
495 reflist = *preflist = NULL;
498 for(i=0;i<count;i++) {
499 char *p;
501 /* Canonicalize link target.
502 * Replace all /'s in the path by a \ */
503 string_replace(alt_path[i], '/', '\\');
505 /* Remove leading '\\'s */
506 p = alt_path[i];
507 while (*p && (*p == '\\')) {
508 p++;
511 reflist[i].alternate_path = talloc_asprintf(ctx,
512 "\\%s",
514 if (!reflist[i].alternate_path) {
515 return False;
518 reflist[i].proximity = 0;
519 reflist[i].ttl = REFERRAL_TTL;
520 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
521 reflist[i].alternate_path));
524 *refcount = count;
526 TALLOC_FREE(alt_path);
527 return True;
530 /**********************************************************************
531 Returns true if the unix path is a valid msdfs symlink and also
532 returns the target string from inside the link.
533 **********************************************************************/
535 static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
536 connection_struct *conn,
537 const char *path,
538 char **pp_link_target,
539 SMB_STRUCT_STAT *sbufp)
541 int referral_len = 0;
542 #if defined(HAVE_BROKEN_READLINK)
543 char link_target_buf[PATH_MAX];
544 #else
545 char link_target_buf[7];
546 #endif
547 size_t bufsize = 0;
548 char *link_target = NULL;
549 struct smb_filename smb_fname;
551 if (pp_link_target) {
552 bufsize = 1024;
553 link_target = talloc_array(ctx, char, bufsize);
554 if (!link_target) {
555 return False;
557 *pp_link_target = link_target;
558 } else {
559 bufsize = sizeof(link_target_buf);
560 link_target = link_target_buf;
563 ZERO_STRUCT(smb_fname);
564 smb_fname.base_name = discard_const_p(char, path);
566 if (SMB_VFS_LSTAT(conn, &smb_fname) != 0) {
567 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
568 path));
569 goto err;
571 if (!S_ISLNK(smb_fname.st.st_ex_mode)) {
572 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
573 path));
574 goto err;
576 if (sbufp != NULL) {
577 *sbufp = smb_fname.st;
580 referral_len = SMB_VFS_READLINK(conn, path, link_target, bufsize - 1);
581 if (referral_len == -1) {
582 DEBUG(0,("is_msdfs_link_read_target: Error reading "
583 "msdfs link %s: %s\n",
584 path, strerror(errno)));
585 goto err;
587 link_target[referral_len] = '\0';
589 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path,
590 link_target));
592 if (!strnequal(link_target, "msdfs:", 6)) {
593 goto err;
595 return True;
597 err:
599 if (link_target != link_target_buf) {
600 TALLOC_FREE(link_target);
602 return False;
605 /**********************************************************************
606 Returns true if the unix path is a valid msdfs symlink.
607 **********************************************************************/
609 bool is_msdfs_link(connection_struct *conn,
610 const char *path,
611 SMB_STRUCT_STAT *sbufp)
613 return is_msdfs_link_internal(talloc_tos(),
614 conn,
615 path,
616 NULL,
617 sbufp);
620 /*****************************************************************
621 Used by other functions to decide if a dfs path is remote,
622 and to get the list of referred locations for that remote path.
624 search_flag: For findfirsts, dfs links themselves are not
625 redirected, but paths beyond the links are. For normal smb calls,
626 even dfs links need to be redirected.
628 consumedcntp: how much of the dfs path is being redirected. the client
629 should try the remaining path on the redirected server.
631 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
632 link redirect are in targetpath.
633 *****************************************************************/
635 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
636 connection_struct *conn,
637 const char *dfspath, /* Incoming complete dfs path */
638 const struct dfs_path *pdp, /* Parsed out
639 server+share+extrapath. */
640 bool search_flag, /* Called from a findfirst ? */
641 int *consumedcntp,
642 char **pp_targetpath)
644 char *p = NULL;
645 char *q = NULL;
646 NTSTATUS status;
647 struct smb_filename *smb_fname = NULL;
648 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
649 components). */
651 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
652 conn->connectpath, pdp->reqpath));
655 * Note the unix path conversion here we're doing we
656 * throw away. We're looking for a symlink for a dfs
657 * resolution, if we don't find it we'll do another
658 * unix_convert later in the codepath.
661 status = unix_convert(ctx, conn, pdp->reqpath, &smb_fname,
662 search_flag ? UCF_ALWAYS_ALLOW_WCARD_LCOMP : 0);
664 if (!NT_STATUS_IS_OK(status)) {
665 if (!NT_STATUS_EQUAL(status,
666 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
667 return status;
669 if (smb_fname == NULL || smb_fname->base_name == NULL) {
670 return status;
674 /* Optimization - check if we can redirect the whole path. */
676 if (is_msdfs_link_internal(ctx, conn, smb_fname->base_name,
677 pp_targetpath, NULL)) {
678 if (search_flag) {
679 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
680 "for dfs link %s.\n", dfspath));
681 status = NT_STATUS_OK;
682 goto out;
685 DEBUG(6,("dfs_path_lookup: %s resolves to a "
686 "valid dfs link %s.\n", dfspath,
687 pp_targetpath ? *pp_targetpath : ""));
689 if (consumedcntp) {
690 *consumedcntp = strlen(dfspath);
692 status = NT_STATUS_PATH_NOT_COVERED;
693 goto out;
696 /* Prepare to test only for '/' components in the given path,
697 * so if a Windows path replace all '\\' characters with '/'.
698 * For a POSIX DFS path we know all separators are already '/'. */
700 canon_dfspath = talloc_strdup(ctx, dfspath);
701 if (!canon_dfspath) {
702 status = NT_STATUS_NO_MEMORY;
703 goto out;
705 if (!pdp->posix_path) {
706 string_replace(canon_dfspath, '\\', '/');
710 * localpath comes out of unix_convert, so it has
711 * no trailing backslash. Make sure that canon_dfspath hasn't either.
712 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
715 trim_char(canon_dfspath,0,'/');
718 * Redirect if any component in the path is a link.
719 * We do this by walking backwards through the
720 * local path, chopping off the last component
721 * in both the local path and the canonicalized
722 * DFS path. If we hit a DFS link then we're done.
725 p = strrchr_m(smb_fname->base_name, '/');
726 if (consumedcntp) {
727 q = strrchr_m(canon_dfspath, '/');
730 while (p) {
731 *p = '\0';
732 if (q) {
733 *q = '\0';
736 if (is_msdfs_link_internal(ctx, conn,
737 smb_fname->base_name, pp_targetpath,
738 NULL)) {
739 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
740 "parent %s is dfs link\n", dfspath,
741 smb_fname_str_dbg(smb_fname)));
743 if (consumedcntp) {
744 *consumedcntp = strlen(canon_dfspath);
745 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
746 "(%d)\n",
747 canon_dfspath,
748 *consumedcntp));
751 status = NT_STATUS_PATH_NOT_COVERED;
752 goto out;
755 /* Step back on the filesystem. */
756 p = strrchr_m(smb_fname->base_name, '/');
758 if (consumedcntp) {
759 /* And in the canonicalized dfs path. */
760 q = strrchr_m(canon_dfspath, '/');
764 status = NT_STATUS_OK;
765 out:
766 TALLOC_FREE(smb_fname);
767 return status;
770 /*****************************************************************
771 Decides if a dfs pathname should be redirected or not.
772 If not, the pathname is converted to a tcon-relative local unix path
774 search_wcard_flag: this flag performs 2 functions both related
775 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
776 for details.
778 This function can return NT_STATUS_OK, meaning use the returned path as-is
779 (mapped into a local path).
780 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
781 any other NT_STATUS error which is a genuine error to be
782 returned to the client.
783 *****************************************************************/
785 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
786 connection_struct *conn,
787 const char *path_in,
788 bool search_wcard_flag,
789 bool allow_broken_path,
790 char **pp_path_out,
791 bool *ppath_contains_wcard)
793 NTSTATUS status;
794 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
796 if (!pdp) {
797 return NT_STATUS_NO_MEMORY;
800 status = parse_dfs_path(conn, path_in, search_wcard_flag,
801 allow_broken_path, pdp,
802 ppath_contains_wcard);
803 if (!NT_STATUS_IS_OK(status)) {
804 TALLOC_FREE(pdp);
805 return status;
808 if (pdp->reqpath[0] == '\0') {
809 TALLOC_FREE(pdp);
810 *pp_path_out = talloc_strdup(ctx, "");
811 if (!*pp_path_out) {
812 return NT_STATUS_NO_MEMORY;
814 DEBUG(5,("dfs_redirect: self-referral.\n"));
815 return NT_STATUS_OK;
818 /* If dfs pathname for a non-dfs share, convert to tcon-relative
819 path and return OK */
821 if (!lp_msdfs_root(SNUM(conn))) {
822 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
823 TALLOC_FREE(pdp);
824 if (!*pp_path_out) {
825 return NT_STATUS_NO_MEMORY;
827 return NT_STATUS_OK;
830 /* If it looked like a local path (zero hostname/servicename)
831 * just treat as a tcon-relative path. */
833 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
834 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
835 TALLOC_FREE(pdp);
836 if (!*pp_path_out) {
837 return NT_STATUS_NO_MEMORY;
839 return NT_STATUS_OK;
842 if (!( strequal(pdp->servicename, lp_servicename(talloc_tos(), SNUM(conn)))
843 || (strequal(pdp->servicename, HOMES_NAME)
844 && strequal(lp_servicename(talloc_tos(), SNUM(conn)),
845 conn->session_info->unix_info->sanitized_username) )) ) {
847 /* The given sharename doesn't match this connection. */
848 TALLOC_FREE(pdp);
850 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
853 status = dfs_path_lookup(ctx, conn, path_in, pdp,
854 search_wcard_flag, NULL, NULL);
855 if (!NT_STATUS_IS_OK(status)) {
856 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
857 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
858 } else {
859 DEBUG(10,("dfs_redirect: dfs_path_lookup "
860 "failed for %s with %s\n",
861 path_in, nt_errstr(status) ));
863 return status;
866 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
868 /* Form non-dfs tcon-relative path */
869 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
870 TALLOC_FREE(pdp);
871 if (!*pp_path_out) {
872 return NT_STATUS_NO_MEMORY;
875 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
876 path_in,
877 *pp_path_out));
879 return NT_STATUS_OK;
882 /**********************************************************************
883 Return a self referral.
884 **********************************************************************/
886 static NTSTATUS self_ref(TALLOC_CTX *ctx,
887 const char *dfs_path,
888 struct junction_map *jucn,
889 int *consumedcntp,
890 bool *self_referralp)
892 struct referral *ref;
894 *self_referralp = True;
896 jucn->referral_count = 1;
897 if((ref = talloc_zero(ctx, struct referral)) == NULL) {
898 return NT_STATUS_NO_MEMORY;
901 ref->alternate_path = talloc_strdup(ctx, dfs_path);
902 if (!ref->alternate_path) {
903 TALLOC_FREE(ref);
904 return NT_STATUS_NO_MEMORY;
906 ref->proximity = 0;
907 ref->ttl = REFERRAL_TTL;
908 jucn->referral_list = ref;
909 *consumedcntp = strlen(dfs_path);
910 return NT_STATUS_OK;
913 /**********************************************************************
914 Gets valid referrals for a dfs path and fills up the
915 junction_map structure.
916 **********************************************************************/
918 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
919 const char *dfs_path,
920 bool allow_broken_path,
921 struct junction_map *jucn,
922 int *consumedcntp,
923 bool *self_referralp)
925 struct connection_struct *conn;
926 char *targetpath = NULL;
927 int snum;
928 NTSTATUS status = NT_STATUS_NOT_FOUND;
929 bool dummy;
930 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
931 char *oldpath;
933 if (!pdp) {
934 return NT_STATUS_NO_MEMORY;
937 *self_referralp = False;
939 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
940 pdp, &dummy);
941 if (!NT_STATUS_IS_OK(status)) {
942 return status;
945 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
946 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
947 if (!jucn->service_name || !jucn->volume_name) {
948 TALLOC_FREE(pdp);
949 return NT_STATUS_NO_MEMORY;
952 /* Verify the share is a dfs root */
953 snum = lp_servicenumber(jucn->service_name);
954 if(snum < 0) {
955 char *service_name = NULL;
956 if ((snum = find_service(ctx, jucn->service_name, &service_name)) < 0) {
957 return NT_STATUS_NOT_FOUND;
959 if (!service_name) {
960 return NT_STATUS_NO_MEMORY;
962 TALLOC_FREE(jucn->service_name);
963 jucn->service_name = talloc_strdup(ctx, service_name);
964 if (!jucn->service_name) {
965 TALLOC_FREE(pdp);
966 return NT_STATUS_NO_MEMORY;
970 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(talloc_tos(), snum) == '\0')) {
971 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
972 "a dfs root.\n",
973 pdp->servicename, dfs_path));
974 TALLOC_FREE(pdp);
975 return NT_STATUS_NOT_FOUND;
979 * Self referrals are tested with a anonymous IPC connection and
980 * a GET_DFS_REFERRAL call to \\server\share. (which means
981 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
982 * into the directory and will fail if it cannot (as the anonymous
983 * user). Cope with this.
986 if (pdp->reqpath[0] == '\0') {
987 char *tmp;
988 struct referral *ref;
990 if (*lp_msdfs_proxy(talloc_tos(), snum) == '\0') {
991 TALLOC_FREE(pdp);
992 return self_ref(ctx,
993 dfs_path,
994 jucn,
995 consumedcntp,
996 self_referralp);
1000 * It's an msdfs proxy share. Redirect to
1001 * the configured target share.
1004 jucn->referral_count = 1;
1005 if ((ref = talloc_zero(ctx, struct referral)) == NULL) {
1006 TALLOC_FREE(pdp);
1007 return NT_STATUS_NO_MEMORY;
1010 if (!(tmp = talloc_strdup(ctx, lp_msdfs_proxy(talloc_tos(), snum)))) {
1011 TALLOC_FREE(pdp);
1012 return NT_STATUS_NO_MEMORY;
1015 trim_string(tmp, "\\", 0);
1017 ref->alternate_path = talloc_asprintf(ctx, "\\%s", tmp);
1018 TALLOC_FREE(tmp);
1020 if (!ref->alternate_path) {
1021 TALLOC_FREE(pdp);
1022 return NT_STATUS_NO_MEMORY;
1025 if (pdp->reqpath[0] != '\0') {
1026 ref->alternate_path = talloc_asprintf_append(
1027 ref->alternate_path,
1028 "%s",
1029 pdp->reqpath);
1030 if (!ref->alternate_path) {
1031 TALLOC_FREE(pdp);
1032 return NT_STATUS_NO_MEMORY;
1035 ref->proximity = 0;
1036 ref->ttl = REFERRAL_TTL;
1037 jucn->referral_list = ref;
1038 *consumedcntp = strlen(dfs_path);
1039 TALLOC_FREE(pdp);
1040 return NT_STATUS_OK;
1043 status = create_conn_struct_cwd(ctx,
1044 server_event_context(),
1045 server_messaging_context(),
1046 &conn, snum,
1047 lp_pathname(talloc_tos(), snum), NULL, &oldpath);
1048 if (!NT_STATUS_IS_OK(status)) {
1049 TALLOC_FREE(pdp);
1050 return status;
1053 /* If this is a DFS path dfs_lookup should return
1054 * NT_STATUS_PATH_NOT_COVERED. */
1056 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
1057 False, consumedcntp, &targetpath);
1059 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
1060 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
1061 dfs_path));
1062 if (NT_STATUS_IS_OK(status)) {
1064 * We are in an error path here (we
1065 * know it's not a DFS path), but
1066 * dfs_path_lookup() can return
1067 * NT_STATUS_OK. Ensure we always
1068 * return a valid error code.
1070 * #9588 - ACLs are not inherited to directories
1071 * for DFS shares.
1073 status = NT_STATUS_NOT_FOUND;
1075 goto err_exit;
1078 /* We know this is a valid dfs link. Parse the targetpath. */
1079 if (!parse_msdfs_symlink(ctx, targetpath,
1080 &jucn->referral_list,
1081 &jucn->referral_count)) {
1082 DEBUG(3,("get_referred_path: failed to parse symlink "
1083 "target %s\n", targetpath ));
1084 status = NT_STATUS_NOT_FOUND;
1085 goto err_exit;
1088 status = NT_STATUS_OK;
1089 err_exit:
1090 vfs_ChDir(conn, oldpath);
1091 SMB_VFS_DISCONNECT(conn);
1092 conn_free(conn);
1093 TALLOC_FREE(pdp);
1094 return status;
1097 /******************************************************************
1098 Set up the DFS referral for the dfs pathname. This call returns
1099 the amount of the path covered by this server, and where the
1100 client should be redirected to. This is the meat of the
1101 TRANS2_GET_DFS_REFERRAL call.
1102 ******************************************************************/
1104 int setup_dfs_referral(connection_struct *orig_conn,
1105 const char *dfs_path,
1106 int max_referral_level,
1107 char **ppdata, NTSTATUS *pstatus)
1109 char *pdata = *ppdata;
1110 int reply_size = 0;
1111 struct dfs_GetDFSReferral *r;
1112 DATA_BLOB blob = data_blob_null;
1113 NTSTATUS status;
1114 enum ndr_err_code ndr_err;
1116 r = talloc_zero(talloc_tos(), struct dfs_GetDFSReferral);
1117 if (r == NULL) {
1118 *pstatus = NT_STATUS_NO_MEMORY;
1119 return -1;
1122 r->in.req.max_referral_level = max_referral_level;
1123 r->in.req.servername = talloc_strdup(r, dfs_path);
1124 if (r->in.req.servername == NULL) {
1125 talloc_free(r);
1126 *pstatus = NT_STATUS_NO_MEMORY;
1127 return -1;
1130 status = SMB_VFS_GET_DFS_REFERRALS(orig_conn, r);
1131 if (!NT_STATUS_IS_OK(status)) {
1132 talloc_free(r);
1133 *pstatus = status;
1134 return -1;
1137 ndr_err = ndr_push_struct_blob(&blob, r,
1138 r->out.resp,
1139 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1140 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1141 TALLOC_FREE(r);
1142 *pstatus = NT_STATUS_INVALID_PARAMETER;
1143 return -1;
1146 pdata = (char *)SMB_REALLOC(pdata, blob.length);
1147 if(pdata == NULL) {
1148 TALLOC_FREE(r);
1149 DEBUG(0,("referral setup:"
1150 "malloc failed for Realloc!\n"));
1151 return -1;
1153 *ppdata = pdata;
1154 reply_size = blob.length;
1155 memcpy(pdata, blob.data, blob.length);
1156 TALLOC_FREE(r);
1158 *pstatus = NT_STATUS_OK;
1159 return reply_size;
1162 /**********************************************************************
1163 The following functions are called by the NETDFS RPC pipe functions
1164 **********************************************************************/
1166 /*********************************************************************
1167 Creates a junction structure from a DFS pathname
1168 **********************************************************************/
1170 bool create_junction(TALLOC_CTX *ctx,
1171 const char *dfs_path,
1172 bool allow_broken_path,
1173 struct junction_map *jucn)
1175 int snum;
1176 bool dummy;
1177 struct dfs_path *pdp = talloc(ctx,struct dfs_path);
1178 NTSTATUS status;
1180 if (!pdp) {
1181 return False;
1183 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1184 pdp, &dummy);
1185 if (!NT_STATUS_IS_OK(status)) {
1186 return False;
1189 /* check if path is dfs : validate first token */
1190 if (!is_myname_or_ipaddr(pdp->hostname)) {
1191 DEBUG(4,("create_junction: Invalid hostname %s "
1192 "in dfs path %s\n",
1193 pdp->hostname, dfs_path));
1194 TALLOC_FREE(pdp);
1195 return False;
1198 /* Check for a non-DFS share */
1199 snum = lp_servicenumber(pdp->servicename);
1201 if(snum < 0 || !lp_msdfs_root(snum)) {
1202 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1203 pdp->servicename));
1204 TALLOC_FREE(pdp);
1205 return False;
1208 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1209 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1210 jucn->comment = lp_comment(ctx, snum);
1212 TALLOC_FREE(pdp);
1213 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1214 return False;
1216 return True;
1219 /**********************************************************************
1220 Forms a valid Unix pathname from the junction
1221 **********************************************************************/
1223 static bool junction_to_local_path(const struct junction_map *jucn,
1224 char **pp_path_out,
1225 connection_struct **conn_out,
1226 char **oldpath)
1228 int snum;
1229 NTSTATUS status;
1231 snum = lp_servicenumber(jucn->service_name);
1232 if(snum < 0) {
1233 return False;
1235 status = create_conn_struct_cwd(talloc_tos(),
1236 server_event_context(),
1237 server_messaging_context(),
1238 conn_out,
1239 snum, lp_pathname(talloc_tos(), snum), NULL, oldpath);
1240 if (!NT_STATUS_IS_OK(status)) {
1241 return False;
1244 *pp_path_out = talloc_asprintf(*conn_out,
1245 "%s/%s",
1246 lp_pathname(talloc_tos(), snum),
1247 jucn->volume_name);
1248 if (!*pp_path_out) {
1249 vfs_ChDir(*conn_out, *oldpath);
1250 SMB_VFS_DISCONNECT(*conn_out);
1251 conn_free(*conn_out);
1252 return False;
1254 return True;
1257 bool create_msdfs_link(const struct junction_map *jucn)
1259 char *path = NULL;
1260 char *cwd;
1261 char *msdfs_link = NULL;
1262 connection_struct *conn;
1263 int i=0;
1264 bool insert_comma = False;
1265 bool ret = False;
1267 if(!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1268 return False;
1271 /* Form the msdfs_link contents */
1272 msdfs_link = talloc_strdup(conn, "msdfs:");
1273 if (!msdfs_link) {
1274 goto out;
1276 for(i=0; i<jucn->referral_count; i++) {
1277 char *refpath = jucn->referral_list[i].alternate_path;
1279 /* Alternate paths always use Windows separators. */
1280 trim_char(refpath, '\\', '\\');
1281 if(*refpath == '\0') {
1282 if (i == 0) {
1283 insert_comma = False;
1285 continue;
1287 if (i > 0 && insert_comma) {
1288 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1289 ",%s",
1290 refpath);
1291 } else {
1292 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1293 "%s",
1294 refpath);
1297 if (!msdfs_link) {
1298 goto out;
1300 if (!insert_comma) {
1301 insert_comma = True;
1305 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1306 path, msdfs_link));
1308 if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1309 if (errno == EEXIST) {
1310 struct smb_filename *smb_fname = NULL;
1311 NTSTATUS status;
1313 status = create_synthetic_smb_fname(talloc_tos(), path,
1314 NULL, NULL,
1315 &smb_fname);
1316 if (!NT_STATUS_IS_OK(status)) {
1317 errno = map_errno_from_nt_status(status);
1318 goto out;
1321 if(SMB_VFS_UNLINK(conn, smb_fname)!=0) {
1322 TALLOC_FREE(smb_fname);
1323 goto out;
1325 TALLOC_FREE(smb_fname);
1327 if (SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1328 DEBUG(1,("create_msdfs_link: symlink failed "
1329 "%s -> %s\nError: %s\n",
1330 path, msdfs_link, strerror(errno)));
1331 goto out;
1335 ret = True;
1337 out:
1338 vfs_ChDir(conn, cwd);
1339 SMB_VFS_DISCONNECT(conn);
1340 conn_free(conn);
1341 return ret;
1344 bool remove_msdfs_link(const struct junction_map *jucn)
1346 char *path = NULL;
1347 char *cwd;
1348 connection_struct *conn;
1349 bool ret = False;
1350 struct smb_filename *smb_fname = NULL;
1351 NTSTATUS status;
1353 if (!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1354 return false;
1357 status = create_synthetic_smb_fname(talloc_tos(), path,
1358 NULL, NULL,
1359 &smb_fname);
1360 if (!NT_STATUS_IS_OK(status)) {
1361 errno = map_errno_from_nt_status(status);
1362 return false;
1365 if( SMB_VFS_UNLINK(conn, smb_fname) == 0 ) {
1366 ret = True;
1369 TALLOC_FREE(smb_fname);
1370 vfs_ChDir(conn, cwd);
1371 SMB_VFS_DISCONNECT(conn);
1372 conn_free(conn);
1373 return ret;
1376 /*********************************************************************
1377 Return the number of DFS links at the root of this share.
1378 *********************************************************************/
1380 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1382 size_t cnt = 0;
1383 DIR *dirp = NULL;
1384 const char *dname = NULL;
1385 char *talloced = NULL;
1386 const char *connect_path = lp_pathname(talloc_tos(), snum);
1387 const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum);
1388 connection_struct *conn;
1389 NTSTATUS status;
1390 char *cwd;
1392 if(*connect_path == '\0') {
1393 return 0;
1397 * Fake up a connection struct for the VFS layer.
1400 status = create_conn_struct_cwd(talloc_tos(),
1401 server_event_context(),
1402 server_messaging_context(),
1403 &conn,
1404 snum, connect_path, NULL, &cwd);
1405 if (!NT_STATUS_IS_OK(status)) {
1406 DEBUG(3, ("create_conn_struct failed: %s\n",
1407 nt_errstr(status)));
1408 return 0;
1411 /* Count a link for the msdfs root - convention */
1412 cnt = 1;
1414 /* No more links if this is an msdfs proxy. */
1415 if (*msdfs_proxy != '\0') {
1416 goto out;
1419 /* Now enumerate all dfs links */
1420 dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1421 if(!dirp) {
1422 goto out;
1425 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1426 != NULL) {
1427 if (is_msdfs_link(conn,
1428 dname,
1429 NULL)) {
1430 cnt++;
1432 TALLOC_FREE(talloced);
1435 SMB_VFS_CLOSEDIR(conn,dirp);
1437 out:
1438 vfs_ChDir(conn, cwd);
1439 SMB_VFS_DISCONNECT(conn);
1440 conn_free(conn);
1441 return cnt;
1444 /*********************************************************************
1445 *********************************************************************/
1447 static int form_junctions(TALLOC_CTX *ctx,
1448 int snum,
1449 struct junction_map *jucn,
1450 size_t jn_remain)
1452 size_t cnt = 0;
1453 DIR *dirp = NULL;
1454 const char *dname = NULL;
1455 char *talloced = NULL;
1456 const char *connect_path = lp_pathname(talloc_tos(), snum);
1457 char *service_name = lp_servicename(talloc_tos(), snum);
1458 const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum);
1459 connection_struct *conn;
1460 struct referral *ref = NULL;
1461 char *cwd;
1462 NTSTATUS status;
1464 if (jn_remain == 0) {
1465 return 0;
1468 if(*connect_path == '\0') {
1469 return 0;
1473 * Fake up a connection struct for the VFS layer.
1476 status = create_conn_struct_cwd(ctx,
1477 server_event_context(),
1478 server_messaging_context(),
1479 &conn, snum, connect_path, NULL,
1480 &cwd);
1481 if (!NT_STATUS_IS_OK(status)) {
1482 DEBUG(3, ("create_conn_struct failed: %s\n",
1483 nt_errstr(status)));
1484 return 0;
1487 /* form a junction for the msdfs root - convention
1488 DO NOT REMOVE THIS: NT clients will not work with us
1489 if this is not present
1491 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1492 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1493 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1494 goto out;
1496 jucn[cnt].comment = "";
1497 jucn[cnt].referral_count = 1;
1499 ref = jucn[cnt].referral_list = talloc_zero(ctx, struct referral);
1500 if (jucn[cnt].referral_list == NULL) {
1501 goto out;
1504 ref->proximity = 0;
1505 ref->ttl = REFERRAL_TTL;
1506 if (*msdfs_proxy != '\0') {
1507 ref->alternate_path = talloc_strdup(ctx,
1508 msdfs_proxy);
1509 } else {
1510 ref->alternate_path = talloc_asprintf(ctx,
1511 "\\\\%s\\%s",
1512 get_local_machine_name(),
1513 service_name);
1516 if (!ref->alternate_path) {
1517 goto out;
1519 cnt++;
1521 /* Don't enumerate if we're an msdfs proxy. */
1522 if (*msdfs_proxy != '\0') {
1523 goto out;
1526 /* Now enumerate all dfs links */
1527 dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1528 if(!dirp) {
1529 goto out;
1532 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1533 != NULL) {
1534 char *link_target = NULL;
1535 if (cnt >= jn_remain) {
1536 DEBUG(2, ("form_junctions: ran out of MSDFS "
1537 "junction slots"));
1538 TALLOC_FREE(talloced);
1539 goto out;
1541 if (is_msdfs_link_internal(ctx,
1542 conn,
1543 dname, &link_target,
1544 NULL)) {
1545 if (parse_msdfs_symlink(ctx,
1546 link_target,
1547 &jucn[cnt].referral_list,
1548 &jucn[cnt].referral_count)) {
1550 jucn[cnt].service_name = talloc_strdup(ctx,
1551 service_name);
1552 jucn[cnt].volume_name = talloc_strdup(ctx,
1553 dname);
1554 if (!jucn[cnt].service_name ||
1555 !jucn[cnt].volume_name) {
1556 TALLOC_FREE(talloced);
1557 goto out;
1559 jucn[cnt].comment = "";
1560 cnt++;
1562 TALLOC_FREE(link_target);
1564 TALLOC_FREE(talloced);
1567 out:
1569 if (dirp) {
1570 SMB_VFS_CLOSEDIR(conn,dirp);
1573 vfs_ChDir(conn, cwd);
1574 conn_free(conn);
1575 return cnt;
1578 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1580 struct junction_map *jn = NULL;
1581 int i=0;
1582 size_t jn_count = 0;
1583 int sharecount = 0;
1585 *p_num_jn = 0;
1586 if(!lp_host_msdfs()) {
1587 return NULL;
1590 /* Ensure all the usershares are loaded. */
1591 become_root();
1592 load_registry_shares();
1593 sharecount = load_usershare_shares(NULL, connections_snum_used);
1594 unbecome_root();
1596 for(i=0;i < sharecount;i++) {
1597 if(lp_msdfs_root(i)) {
1598 jn_count += count_dfs_links(ctx, i);
1601 if (jn_count == 0) {
1602 return NULL;
1604 jn = talloc_array(ctx, struct junction_map, jn_count);
1605 if (!jn) {
1606 return NULL;
1608 for(i=0; i < sharecount; i++) {
1609 if (*p_num_jn >= jn_count) {
1610 break;
1612 if(lp_msdfs_root(i)) {
1613 *p_num_jn += form_junctions(ctx, i,
1614 &jn[*p_num_jn],
1615 jn_count - *p_num_jn);
1618 return jn;
1621 /******************************************************************************
1622 Core function to resolve a dfs pathname possibly containing a wildcard. If
1623 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1624 detected during dfs resolution.
1625 ******************************************************************************/
1627 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1628 connection_struct *conn,
1629 bool dfs_pathnames,
1630 const char *name_in,
1631 bool allow_wcards,
1632 bool allow_broken_path,
1633 char **pp_name_out,
1634 bool *ppath_contains_wcard)
1636 bool path_contains_wcard;
1637 NTSTATUS status = NT_STATUS_OK;
1639 if (dfs_pathnames) {
1640 status = dfs_redirect(ctx,
1641 conn,
1642 name_in,
1643 allow_wcards,
1644 allow_broken_path,
1645 pp_name_out,
1646 &path_contains_wcard);
1648 if (NT_STATUS_IS_OK(status) && ppath_contains_wcard != NULL) {
1649 *ppath_contains_wcard = path_contains_wcard;
1651 } else {
1653 * Cheat and just return a copy of the in ptr.
1654 * Once srvstr_get_path() uses talloc it'll
1655 * be a talloced ptr anyway.
1657 *pp_name_out = discard_const_p(char, name_in);
1659 return status;