nfs4acls: Use talloc_realloc()
[Samba.git] / source3 / smbd / msdfs.c
blobe895c1f7accf4a83e74dde13705dc52cb948df5e
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
7 Copyright (C) Robin McCorkell 2015
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #define DBGC_CLASS DBGC_MSDFS
25 #include "includes.h"
26 #include "system/filesys.h"
27 #include "smbd/smbd.h"
28 #include "smbd/globals.h"
29 #include "msdfs.h"
30 #include "auth.h"
31 #include "lib/param/loadparm.h"
32 #include "libcli/security/security.h"
33 #include "librpc/gen_ndr/ndr_dfsblobs.h"
35 /**********************************************************************
36 Parse a DFS pathname of the form \hostname\service\reqpath
37 into the dfs_path structure.
38 If POSIX pathnames is true, the pathname may also be of the
39 form /hostname/service/reqpath.
40 We cope with either here.
42 Unfortunately, due to broken clients who might set the
43 SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
44 send a local path, we have to cope with that too....
46 If conn != NULL then ensure the provided service is
47 the one pointed to by the connection.
49 This version does everything using pointers within one copy of the
50 pathname string, talloced on the struct dfs_path pointer (which
51 must be talloced). This may be too clever to live....
52 JRA.
53 **********************************************************************/
55 static NTSTATUS parse_dfs_path(connection_struct *conn,
56 const char *pathname,
57 bool allow_wcards,
58 bool allow_broken_path,
59 struct dfs_path *pdp, /* MUST BE TALLOCED */
60 bool *ppath_contains_wcard)
62 char *pathname_local;
63 char *p,*temp;
64 char *servicename;
65 char *eos_ptr;
66 NTSTATUS status = NT_STATUS_OK;
67 char sepchar;
69 ZERO_STRUCTP(pdp);
72 * This is the only talloc we should need to do
73 * on the struct dfs_path. All the pointers inside
74 * it should point to offsets within this string.
77 pathname_local = talloc_strdup(pdp, pathname);
78 if (!pathname_local) {
79 return NT_STATUS_NO_MEMORY;
81 /* Get a pointer to the terminating '\0' */
82 eos_ptr = &pathname_local[strlen(pathname_local)];
83 p = temp = pathname_local;
85 pdp->posix_path = (lp_posix_pathnames() && *pathname == '/');
87 sepchar = pdp->posix_path ? '/' : '\\';
89 if (allow_broken_path && (*pathname != sepchar)) {
90 DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
91 pathname, sepchar ));
93 * Possibly client sent a local path by mistake.
94 * Try and convert to a local path.
97 pdp->hostname = eos_ptr; /* "" */
98 pdp->servicename = eos_ptr; /* "" */
100 /* We've got no info about separators. */
101 pdp->posix_path = lp_posix_pathnames();
102 p = temp;
103 DEBUG(10,("parse_dfs_path: trying to convert %s to a "
104 "local path\n",
105 temp));
106 goto local_path;
110 * Safe to use on talloc'ed string as it only shrinks.
111 * It also doesn't affect the eos_ptr.
113 trim_char(temp,sepchar,sepchar);
115 DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
116 temp, sepchar));
118 /* Now tokenize. */
119 /* Parse out hostname. */
120 p = strchr_m(temp,sepchar);
121 if(p == NULL) {
122 DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
123 temp));
125 * Possibly client sent a local path by mistake.
126 * Try and convert to a local path.
129 pdp->hostname = eos_ptr; /* "" */
130 pdp->servicename = eos_ptr; /* "" */
132 p = temp;
133 DEBUG(10,("parse_dfs_path: trying to convert %s "
134 "to a local path\n",
135 temp));
136 goto local_path;
138 *p = '\0';
139 pdp->hostname = temp;
141 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
143 /* Parse out servicename. */
144 servicename = p+1;
145 p = strchr_m(servicename,sepchar);
146 if (p) {
147 *p = '\0';
150 /* Is this really our servicename ? */
151 if (conn && !( strequal(servicename, lp_servicename(talloc_tos(), SNUM(conn)))
152 || (strequal(servicename, HOMES_NAME)
153 && strequal(lp_servicename(talloc_tos(), SNUM(conn)),
154 get_current_username()) )) ) {
155 DEBUG(10,("parse_dfs_path: %s is not our servicename\n",
156 servicename));
159 * Possibly client sent a local path by mistake.
160 * Try and convert to a local path.
163 pdp->hostname = eos_ptr; /* "" */
164 pdp->servicename = eos_ptr; /* "" */
166 /* Repair the path - replace the sepchar's
167 we nulled out */
168 servicename--;
169 *servicename = sepchar;
170 if (p) {
171 *p = sepchar;
174 p = temp;
175 DEBUG(10,("parse_dfs_path: trying to convert %s "
176 "to a local path\n",
177 temp));
178 goto local_path;
181 pdp->servicename = servicename;
183 DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
185 if(p == NULL) {
186 /* Client sent self referral \server\share. */
187 pdp->reqpath = eos_ptr; /* "" */
188 return NT_STATUS_OK;
191 p++;
193 local_path:
195 *ppath_contains_wcard = False;
197 pdp->reqpath = p;
199 /* Rest is reqpath. */
200 if (pdp->posix_path) {
201 status = check_path_syntax_posix(pdp->reqpath);
202 } else {
203 if (allow_wcards) {
204 status = check_path_syntax_wcard(pdp->reqpath,
205 ppath_contains_wcard);
206 } else {
207 status = check_path_syntax(pdp->reqpath);
211 if (!NT_STATUS_IS_OK(status)) {
212 DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
213 p, nt_errstr(status) ));
214 return status;
217 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
218 return NT_STATUS_OK;
221 /********************************************************
222 Fake up a connection struct for the VFS layer, for use in
223 applications (such as the python bindings), that do not want the
224 global working directory changed under them.
226 SMB_VFS_CONNECT requires root privileges.
227 *********************************************************/
229 static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx,
230 struct tevent_context *ev,
231 struct messaging_context *msg,
232 connection_struct **pconn,
233 int snum,
234 const char *path,
235 const struct auth_session_info *session_info)
237 connection_struct *conn;
238 char *connpath;
239 const char *vfs_user;
240 struct smbd_server_connection *sconn;
241 const char *servicename = lp_const_servicename(snum);
243 sconn = talloc_zero(ctx, struct smbd_server_connection);
244 if (sconn == NULL) {
245 return NT_STATUS_NO_MEMORY;
248 sconn->ev_ctx = ev;
249 sconn->msg_ctx = msg;
251 conn = conn_new(sconn);
252 if (conn == NULL) {
253 TALLOC_FREE(sconn);
254 return NT_STATUS_NO_MEMORY;
257 /* Now we have conn, we need to make sconn a child of conn,
258 * for a proper talloc tree */
259 talloc_steal(conn, sconn);
261 if (snum == -1 && servicename == NULL) {
262 servicename = "Unknown Service (snum == -1)";
265 connpath = talloc_strdup(conn, path);
266 if (!connpath) {
267 TALLOC_FREE(conn);
268 return NT_STATUS_NO_MEMORY;
270 connpath = talloc_string_sub(conn,
271 connpath,
272 "%S",
273 servicename);
274 if (!connpath) {
275 TALLOC_FREE(conn);
276 return NT_STATUS_NO_MEMORY;
279 /* needed for smbd_vfs_init() */
281 conn->params->service = snum;
282 conn->cnum = TID_FIELD_INVALID;
284 if (session_info != NULL) {
285 conn->session_info = copy_session_info(conn, session_info);
286 if (conn->session_info == NULL) {
287 DEBUG(0, ("copy_serverinfo failed\n"));
288 TALLOC_FREE(conn);
289 return NT_STATUS_NO_MEMORY;
291 vfs_user = conn->session_info->unix_info->unix_name;
292 } else {
293 /* use current authenticated user in absence of session_info */
294 vfs_user = get_current_username();
297 set_conn_connectpath(conn, connpath);
300 * New code to check if there's a share security descriptor
301 * added from NT server manager. This is done after the
302 * smb.conf checks are done as we need a uid and token. JRA.
305 if (conn->session_info) {
306 share_access_check(conn->session_info->security_token,
307 servicename,
308 MAXIMUM_ALLOWED_ACCESS,
309 &conn->share_access);
311 if ((conn->share_access & FILE_WRITE_DATA) == 0) {
312 if ((conn->share_access & FILE_READ_DATA) == 0) {
313 /* No access, read or write. */
314 DEBUG(3,("create_conn_struct: connection to %s "
315 "denied due to security "
316 "descriptor.\n",
317 servicename));
318 conn_free(conn);
319 return NT_STATUS_ACCESS_DENIED;
320 } else {
321 conn->read_only = true;
324 } else {
325 conn->share_access = 0;
326 conn->read_only = true;
329 if (!smbd_vfs_init(conn)) {
330 NTSTATUS status = map_nt_error_from_unix(errno);
331 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
332 conn_free(conn);
333 return status;
336 /* this must be the first filesystem operation that we do */
337 if (SMB_VFS_CONNECT(conn, servicename, vfs_user) < 0) {
338 DEBUG(0,("VFS connect failed!\n"));
339 conn_free(conn);
340 return NT_STATUS_UNSUCCESSFUL;
343 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
344 *pconn = conn;
346 return NT_STATUS_OK;
349 /********************************************************
350 Fake up a connection struct for the VFS layer, for use in
351 applications (such as the python bindings), that do not want the
352 global working directory changed under them.
354 SMB_VFS_CONNECT requires root privileges.
355 *********************************************************/
357 NTSTATUS create_conn_struct(TALLOC_CTX *ctx,
358 struct tevent_context *ev,
359 struct messaging_context *msg,
360 connection_struct **pconn,
361 int snum,
362 const char *path,
363 const struct auth_session_info *session_info)
365 NTSTATUS status;
366 become_root();
367 status = create_conn_struct_as_root(ctx, ev,
368 msg, pconn,
369 snum, path,
370 session_info);
371 unbecome_root();
373 return status;
376 /********************************************************
377 Fake up a connection struct for the VFS layer.
378 Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
380 The old working directory is returned on *poldcwd, allocated on ctx.
381 *********************************************************/
383 NTSTATUS create_conn_struct_cwd(TALLOC_CTX *ctx,
384 struct tevent_context *ev,
385 struct messaging_context *msg,
386 connection_struct **pconn,
387 int snum,
388 const char *path,
389 const struct auth_session_info *session_info,
390 char **poldcwd)
392 connection_struct *conn;
393 char *oldcwd;
395 NTSTATUS status = create_conn_struct(ctx, ev,
396 msg, &conn,
397 snum, path,
398 session_info);
399 if (!NT_STATUS_IS_OK(status)) {
400 return status;
404 * Windows seems to insist on doing trans2getdfsreferral() calls on
405 * the IPC$ share as the anonymous user. If we try to chdir as that
406 * user we will fail.... WTF ? JRA.
409 oldcwd = vfs_GetWd(ctx, conn);
410 if (oldcwd == NULL) {
411 status = map_nt_error_from_unix(errno);
412 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
413 conn_free(conn);
414 return status;
417 if (vfs_ChDir(conn,conn->connectpath) != 0) {
418 status = map_nt_error_from_unix(errno);
419 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
420 "Error was %s\n",
421 conn->connectpath, strerror(errno) ));
422 conn_free(conn);
423 return status;
426 *pconn = conn;
427 *poldcwd = oldcwd;
429 return NT_STATUS_OK;
432 static void shuffle_strlist(char **list, int count)
434 int i;
435 uint32_t r;
436 char *tmp;
438 for (i = count; i > 1; i--) {
439 r = generate_random() % i;
441 tmp = list[i-1];
442 list[i-1] = list[r];
443 list[r] = tmp;
447 /**********************************************************************
448 Parse the contents of a symlink to verify if it is an msdfs referral
449 A valid referral is of the form:
451 msdfs:server1\share1,server2\share2
452 msdfs:server1\share1\pathname,server2\share2\pathname
453 msdfs:server1/share1,server2/share2
454 msdfs:server1/share1/pathname,server2/share2/pathname.
456 Note that the alternate paths returned here must be of the canonicalized
457 form:
459 \server\share or
460 \server\share\path\to\file,
462 even in posix path mode. This is because we have no knowledge if the
463 server we're referring to understands posix paths.
464 **********************************************************************/
466 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
467 int snum,
468 const char *target,
469 struct referral **preflist,
470 int *refcount)
472 char *temp = NULL;
473 char *prot;
474 char **alt_path = NULL;
475 int count = 0, i;
476 struct referral *reflist;
477 char *saveptr;
479 temp = talloc_strdup(ctx, target);
480 if (!temp) {
481 return False;
483 prot = strtok_r(temp, ":", &saveptr);
484 if (!prot) {
485 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
486 return False;
489 alt_path = talloc_array(ctx, char *, MAX_REFERRAL_COUNT);
490 if (!alt_path) {
491 return False;
494 /* parse out the alternate paths */
495 while((count<MAX_REFERRAL_COUNT) &&
496 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
497 count++;
500 /* shuffle alternate paths */
501 if (lp_msdfs_shuffle_referrals(snum)) {
502 shuffle_strlist(alt_path, count);
505 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
507 if (count) {
508 reflist = *preflist = talloc_zero_array(ctx,
509 struct referral, count);
510 if(reflist == NULL) {
511 TALLOC_FREE(alt_path);
512 return False;
514 } else {
515 reflist = *preflist = NULL;
518 for(i=0;i<count;i++) {
519 char *p;
521 /* Canonicalize link target.
522 * Replace all /'s in the path by a \ */
523 string_replace(alt_path[i], '/', '\\');
525 /* Remove leading '\\'s */
526 p = alt_path[i];
527 while (*p && (*p == '\\')) {
528 p++;
531 reflist[i].alternate_path = talloc_asprintf(ctx,
532 "\\%s",
534 if (!reflist[i].alternate_path) {
535 return False;
538 reflist[i].proximity = 0;
539 reflist[i].ttl = REFERRAL_TTL;
540 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
541 reflist[i].alternate_path));
544 *refcount = count;
546 TALLOC_FREE(alt_path);
547 return True;
550 /**********************************************************************
551 Returns true if the unix path is a valid msdfs symlink and also
552 returns the target string from inside the link.
553 **********************************************************************/
555 static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
556 connection_struct *conn,
557 const char *path,
558 char **pp_link_target,
559 SMB_STRUCT_STAT *sbufp)
561 int referral_len = 0;
562 #if defined(HAVE_BROKEN_READLINK)
563 char link_target_buf[PATH_MAX];
564 #else
565 char link_target_buf[7];
566 #endif
567 size_t bufsize = 0;
568 char *link_target = NULL;
569 struct smb_filename smb_fname;
571 if (pp_link_target) {
572 bufsize = 1024;
573 link_target = talloc_array(ctx, char, bufsize);
574 if (!link_target) {
575 return False;
577 *pp_link_target = link_target;
578 } else {
579 bufsize = sizeof(link_target_buf);
580 link_target = link_target_buf;
583 ZERO_STRUCT(smb_fname);
584 smb_fname.base_name = discard_const_p(char, path);
586 if (SMB_VFS_LSTAT(conn, &smb_fname) != 0) {
587 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
588 path));
589 goto err;
591 if (!S_ISLNK(smb_fname.st.st_ex_mode)) {
592 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
593 path));
594 goto err;
596 if (sbufp != NULL) {
597 *sbufp = smb_fname.st;
600 referral_len = SMB_VFS_READLINK(conn, path, link_target, bufsize - 1);
601 if (referral_len == -1) {
602 DEBUG(0,("is_msdfs_link_read_target: Error reading "
603 "msdfs link %s: %s\n",
604 path, strerror(errno)));
605 goto err;
607 link_target[referral_len] = '\0';
609 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path,
610 link_target));
612 if (!strnequal(link_target, "msdfs:", 6)) {
613 goto err;
615 return True;
617 err:
619 if (link_target != link_target_buf) {
620 TALLOC_FREE(link_target);
622 return False;
625 /**********************************************************************
626 Returns true if the unix path is a valid msdfs symlink.
627 **********************************************************************/
629 bool is_msdfs_link(connection_struct *conn,
630 const char *path,
631 SMB_STRUCT_STAT *sbufp)
633 return is_msdfs_link_internal(talloc_tos(),
634 conn,
635 path,
636 NULL,
637 sbufp);
640 /*****************************************************************
641 Used by other functions to decide if a dfs path is remote,
642 and to get the list of referred locations for that remote path.
644 search_flag: For findfirsts, dfs links themselves are not
645 redirected, but paths beyond the links are. For normal smb calls,
646 even dfs links need to be redirected.
648 consumedcntp: how much of the dfs path is being redirected. the client
649 should try the remaining path on the redirected server.
651 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
652 link redirect are in targetpath.
653 *****************************************************************/
655 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
656 connection_struct *conn,
657 const char *dfspath, /* Incoming complete dfs path */
658 const struct dfs_path *pdp, /* Parsed out
659 server+share+extrapath. */
660 bool search_flag, /* Called from a findfirst ? */
661 int *consumedcntp,
662 char **pp_targetpath)
664 char *p = NULL;
665 char *q = NULL;
666 NTSTATUS status;
667 struct smb_filename *smb_fname = NULL;
668 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
669 components). */
671 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
672 conn->connectpath, pdp->reqpath));
675 * Note the unix path conversion here we're doing we
676 * throw away. We're looking for a symlink for a dfs
677 * resolution, if we don't find it we'll do another
678 * unix_convert later in the codepath.
681 status = unix_convert(ctx, conn, pdp->reqpath, &smb_fname,
682 search_flag ? UCF_ALWAYS_ALLOW_WCARD_LCOMP : 0);
684 if (!NT_STATUS_IS_OK(status)) {
685 if (!NT_STATUS_EQUAL(status,
686 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
687 return status;
689 if (smb_fname == NULL || smb_fname->base_name == NULL) {
690 return status;
694 /* Optimization - check if we can redirect the whole path. */
696 if (is_msdfs_link_internal(ctx, conn, smb_fname->base_name,
697 pp_targetpath, NULL)) {
698 if (search_flag) {
699 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
700 "for dfs link %s.\n", dfspath));
701 status = NT_STATUS_OK;
702 goto out;
705 DEBUG(6,("dfs_path_lookup: %s resolves to a "
706 "valid dfs link %s.\n", dfspath,
707 pp_targetpath ? *pp_targetpath : ""));
709 if (consumedcntp) {
710 *consumedcntp = strlen(dfspath);
712 status = NT_STATUS_PATH_NOT_COVERED;
713 goto out;
716 /* Prepare to test only for '/' components in the given path,
717 * so if a Windows path replace all '\\' characters with '/'.
718 * For a POSIX DFS path we know all separators are already '/'. */
720 canon_dfspath = talloc_strdup(ctx, dfspath);
721 if (!canon_dfspath) {
722 status = NT_STATUS_NO_MEMORY;
723 goto out;
725 if (!pdp->posix_path) {
726 string_replace(canon_dfspath, '\\', '/');
730 * localpath comes out of unix_convert, so it has
731 * no trailing backslash. Make sure that canon_dfspath hasn't either.
732 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
735 trim_char(canon_dfspath,0,'/');
738 * Redirect if any component in the path is a link.
739 * We do this by walking backwards through the
740 * local path, chopping off the last component
741 * in both the local path and the canonicalized
742 * DFS path. If we hit a DFS link then we're done.
745 p = strrchr_m(smb_fname->base_name, '/');
746 if (consumedcntp) {
747 q = strrchr_m(canon_dfspath, '/');
750 while (p) {
751 *p = '\0';
752 if (q) {
753 *q = '\0';
756 if (is_msdfs_link_internal(ctx, conn,
757 smb_fname->base_name, pp_targetpath,
758 NULL)) {
759 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
760 "parent %s is dfs link\n", dfspath,
761 smb_fname_str_dbg(smb_fname)));
763 if (consumedcntp) {
764 *consumedcntp = strlen(canon_dfspath);
765 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
766 "(%d)\n",
767 canon_dfspath,
768 *consumedcntp));
771 status = NT_STATUS_PATH_NOT_COVERED;
772 goto out;
775 /* Step back on the filesystem. */
776 p = strrchr_m(smb_fname->base_name, '/');
778 if (consumedcntp) {
779 /* And in the canonicalized dfs path. */
780 q = strrchr_m(canon_dfspath, '/');
784 status = NT_STATUS_OK;
785 out:
786 TALLOC_FREE(smb_fname);
787 return status;
790 /*****************************************************************
791 Decides if a dfs pathname should be redirected or not.
792 If not, the pathname is converted to a tcon-relative local unix path
794 search_wcard_flag: this flag performs 2 functions both related
795 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
796 for details.
798 This function can return NT_STATUS_OK, meaning use the returned path as-is
799 (mapped into a local path).
800 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
801 any other NT_STATUS error which is a genuine error to be
802 returned to the client.
803 *****************************************************************/
805 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
806 connection_struct *conn,
807 const char *path_in,
808 bool search_wcard_flag,
809 bool allow_broken_path,
810 char **pp_path_out,
811 bool *ppath_contains_wcard)
813 NTSTATUS status;
814 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
816 if (!pdp) {
817 return NT_STATUS_NO_MEMORY;
820 status = parse_dfs_path(conn, path_in, search_wcard_flag,
821 allow_broken_path, pdp,
822 ppath_contains_wcard);
823 if (!NT_STATUS_IS_OK(status)) {
824 TALLOC_FREE(pdp);
825 return status;
828 if (pdp->reqpath[0] == '\0') {
829 TALLOC_FREE(pdp);
830 *pp_path_out = talloc_strdup(ctx, "");
831 if (!*pp_path_out) {
832 return NT_STATUS_NO_MEMORY;
834 DEBUG(5,("dfs_redirect: self-referral.\n"));
835 return NT_STATUS_OK;
838 /* If dfs pathname for a non-dfs share, convert to tcon-relative
839 path and return OK */
841 if (!lp_msdfs_root(SNUM(conn))) {
842 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
843 TALLOC_FREE(pdp);
844 if (!*pp_path_out) {
845 return NT_STATUS_NO_MEMORY;
847 return NT_STATUS_OK;
850 /* If it looked like a local path (zero hostname/servicename)
851 * just treat as a tcon-relative path. */
853 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
854 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
855 TALLOC_FREE(pdp);
856 if (!*pp_path_out) {
857 return NT_STATUS_NO_MEMORY;
859 return NT_STATUS_OK;
862 if (!( strequal(pdp->servicename, lp_servicename(talloc_tos(), SNUM(conn)))
863 || (strequal(pdp->servicename, HOMES_NAME)
864 && strequal(lp_servicename(talloc_tos(), SNUM(conn)),
865 conn->session_info->unix_info->sanitized_username) )) ) {
867 /* The given sharename doesn't match this connection. */
868 TALLOC_FREE(pdp);
870 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
873 status = dfs_path_lookup(ctx, conn, path_in, pdp,
874 search_wcard_flag, NULL, NULL);
875 if (!NT_STATUS_IS_OK(status)) {
876 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
877 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
878 } else {
879 DEBUG(10,("dfs_redirect: dfs_path_lookup "
880 "failed for %s with %s\n",
881 path_in, nt_errstr(status) ));
883 return status;
886 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
888 /* Form non-dfs tcon-relative path */
889 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
890 TALLOC_FREE(pdp);
891 if (!*pp_path_out) {
892 return NT_STATUS_NO_MEMORY;
895 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
896 path_in,
897 *pp_path_out));
899 return NT_STATUS_OK;
902 /**********************************************************************
903 Return a self referral.
904 **********************************************************************/
906 static NTSTATUS self_ref(TALLOC_CTX *ctx,
907 const char *dfs_path,
908 struct junction_map *jucn,
909 int *consumedcntp,
910 bool *self_referralp)
912 struct referral *ref;
914 *self_referralp = True;
916 jucn->referral_count = 1;
917 if((ref = talloc_zero(ctx, struct referral)) == NULL) {
918 return NT_STATUS_NO_MEMORY;
921 ref->alternate_path = talloc_strdup(ctx, dfs_path);
922 if (!ref->alternate_path) {
923 TALLOC_FREE(ref);
924 return NT_STATUS_NO_MEMORY;
926 ref->proximity = 0;
927 ref->ttl = REFERRAL_TTL;
928 jucn->referral_list = ref;
929 *consumedcntp = strlen(dfs_path);
930 return NT_STATUS_OK;
933 /**********************************************************************
934 Gets valid referrals for a dfs path and fills up the
935 junction_map structure.
936 **********************************************************************/
938 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
939 const char *dfs_path,
940 bool allow_broken_path,
941 struct junction_map *jucn,
942 int *consumedcntp,
943 bool *self_referralp)
945 struct connection_struct *conn;
946 char *targetpath = NULL;
947 int snum;
948 NTSTATUS status = NT_STATUS_NOT_FOUND;
949 bool dummy;
950 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
951 char *oldpath;
953 if (!pdp) {
954 return NT_STATUS_NO_MEMORY;
957 *self_referralp = False;
959 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
960 pdp, &dummy);
961 if (!NT_STATUS_IS_OK(status)) {
962 return status;
965 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
966 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
967 if (!jucn->service_name || !jucn->volume_name) {
968 TALLOC_FREE(pdp);
969 return NT_STATUS_NO_MEMORY;
972 /* Verify the share is a dfs root */
973 snum = lp_servicenumber(jucn->service_name);
974 if(snum < 0) {
975 char *service_name = NULL;
976 if ((snum = find_service(ctx, jucn->service_name, &service_name)) < 0) {
977 return NT_STATUS_NOT_FOUND;
979 if (!service_name) {
980 return NT_STATUS_NO_MEMORY;
982 TALLOC_FREE(jucn->service_name);
983 jucn->service_name = talloc_strdup(ctx, service_name);
984 if (!jucn->service_name) {
985 TALLOC_FREE(pdp);
986 return NT_STATUS_NO_MEMORY;
990 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(talloc_tos(), snum) == '\0')) {
991 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
992 "a dfs root.\n",
993 pdp->servicename, dfs_path));
994 TALLOC_FREE(pdp);
995 return NT_STATUS_NOT_FOUND;
999 * Self referrals are tested with a anonymous IPC connection and
1000 * a GET_DFS_REFERRAL call to \\server\share. (which means
1001 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
1002 * into the directory and will fail if it cannot (as the anonymous
1003 * user). Cope with this.
1006 if (pdp->reqpath[0] == '\0') {
1007 char *tmp;
1008 struct referral *ref;
1009 int refcount;
1011 if (*lp_msdfs_proxy(talloc_tos(), snum) == '\0') {
1012 TALLOC_FREE(pdp);
1013 return self_ref(ctx,
1014 dfs_path,
1015 jucn,
1016 consumedcntp,
1017 self_referralp);
1021 * It's an msdfs proxy share. Redirect to
1022 * the configured target share.
1025 tmp = talloc_asprintf(talloc_tos(), "msdfs:%s",
1026 lp_msdfs_proxy(talloc_tos(), snum));
1027 if (tmp == NULL) {
1028 TALLOC_FREE(pdp);
1029 return NT_STATUS_NO_MEMORY;
1032 if (!parse_msdfs_symlink(ctx, snum, tmp, &ref, &refcount)) {
1033 TALLOC_FREE(tmp);
1034 TALLOC_FREE(pdp);
1035 return NT_STATUS_INVALID_PARAMETER;
1037 TALLOC_FREE(tmp);
1038 jucn->referral_count = refcount;
1039 jucn->referral_list = ref;
1040 *consumedcntp = strlen(dfs_path);
1041 TALLOC_FREE(pdp);
1042 return NT_STATUS_OK;
1045 status = create_conn_struct_cwd(ctx,
1046 server_event_context(),
1047 server_messaging_context(),
1048 &conn, snum,
1049 lp_path(talloc_tos(), snum), NULL, &oldpath);
1050 if (!NT_STATUS_IS_OK(status)) {
1051 TALLOC_FREE(pdp);
1052 return status;
1055 /* If this is a DFS path dfs_lookup should return
1056 * NT_STATUS_PATH_NOT_COVERED. */
1058 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
1059 False, consumedcntp, &targetpath);
1061 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
1062 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
1063 dfs_path));
1064 if (NT_STATUS_IS_OK(status)) {
1066 * We are in an error path here (we
1067 * know it's not a DFS path), but
1068 * dfs_path_lookup() can return
1069 * NT_STATUS_OK. Ensure we always
1070 * return a valid error code.
1072 * #9588 - ACLs are not inherited to directories
1073 * for DFS shares.
1075 status = NT_STATUS_NOT_FOUND;
1077 goto err_exit;
1080 /* We know this is a valid dfs link. Parse the targetpath. */
1081 if (!parse_msdfs_symlink(ctx, snum, targetpath,
1082 &jucn->referral_list,
1083 &jucn->referral_count)) {
1084 DEBUG(3,("get_referred_path: failed to parse symlink "
1085 "target %s\n", targetpath ));
1086 status = NT_STATUS_NOT_FOUND;
1087 goto err_exit;
1090 status = NT_STATUS_OK;
1091 err_exit:
1092 vfs_ChDir(conn, oldpath);
1093 SMB_VFS_DISCONNECT(conn);
1094 conn_free(conn);
1095 TALLOC_FREE(pdp);
1096 return status;
1099 /******************************************************************
1100 Set up the DFS referral for the dfs pathname. This call returns
1101 the amount of the path covered by this server, and where the
1102 client should be redirected to. This is the meat of the
1103 TRANS2_GET_DFS_REFERRAL call.
1104 ******************************************************************/
1106 int setup_dfs_referral(connection_struct *orig_conn,
1107 const char *dfs_path,
1108 int max_referral_level,
1109 char **ppdata, NTSTATUS *pstatus)
1111 char *pdata = *ppdata;
1112 int reply_size = 0;
1113 struct dfs_GetDFSReferral *r;
1114 DATA_BLOB blob = data_blob_null;
1115 NTSTATUS status;
1116 enum ndr_err_code ndr_err;
1118 r = talloc_zero(talloc_tos(), struct dfs_GetDFSReferral);
1119 if (r == NULL) {
1120 *pstatus = NT_STATUS_NO_MEMORY;
1121 return -1;
1124 r->in.req.max_referral_level = max_referral_level;
1125 r->in.req.servername = talloc_strdup(r, dfs_path);
1126 if (r->in.req.servername == NULL) {
1127 talloc_free(r);
1128 *pstatus = NT_STATUS_NO_MEMORY;
1129 return -1;
1132 status = SMB_VFS_GET_DFS_REFERRALS(orig_conn, r);
1133 if (!NT_STATUS_IS_OK(status)) {
1134 talloc_free(r);
1135 *pstatus = status;
1136 return -1;
1139 ndr_err = ndr_push_struct_blob(&blob, r,
1140 r->out.resp,
1141 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1142 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1143 TALLOC_FREE(r);
1144 *pstatus = NT_STATUS_INVALID_PARAMETER;
1145 return -1;
1148 pdata = (char *)SMB_REALLOC(pdata, blob.length);
1149 if(pdata == NULL) {
1150 TALLOC_FREE(r);
1151 DEBUG(0,("referral setup:"
1152 "malloc failed for Realloc!\n"));
1153 return -1;
1155 *ppdata = pdata;
1156 reply_size = blob.length;
1157 memcpy(pdata, blob.data, blob.length);
1158 TALLOC_FREE(r);
1160 *pstatus = NT_STATUS_OK;
1161 return reply_size;
1164 /**********************************************************************
1165 The following functions are called by the NETDFS RPC pipe functions
1166 **********************************************************************/
1168 /*********************************************************************
1169 Creates a junction structure from a DFS pathname
1170 **********************************************************************/
1172 bool create_junction(TALLOC_CTX *ctx,
1173 const char *dfs_path,
1174 bool allow_broken_path,
1175 struct junction_map *jucn)
1177 int snum;
1178 bool dummy;
1179 struct dfs_path *pdp = talloc(ctx,struct dfs_path);
1180 NTSTATUS status;
1182 if (!pdp) {
1183 return False;
1185 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1186 pdp, &dummy);
1187 if (!NT_STATUS_IS_OK(status)) {
1188 return False;
1191 /* check if path is dfs : validate first token */
1192 if (!is_myname_or_ipaddr(pdp->hostname)) {
1193 DEBUG(4,("create_junction: Invalid hostname %s "
1194 "in dfs path %s\n",
1195 pdp->hostname, dfs_path));
1196 TALLOC_FREE(pdp);
1197 return False;
1200 /* Check for a non-DFS share */
1201 snum = lp_servicenumber(pdp->servicename);
1203 if(snum < 0 || !lp_msdfs_root(snum)) {
1204 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1205 pdp->servicename));
1206 TALLOC_FREE(pdp);
1207 return False;
1210 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1211 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1212 jucn->comment = lp_comment(ctx, snum);
1214 TALLOC_FREE(pdp);
1215 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1216 return False;
1218 return True;
1221 /**********************************************************************
1222 Forms a valid Unix pathname from the junction
1223 **********************************************************************/
1225 static bool junction_to_local_path(const struct junction_map *jucn,
1226 char **pp_path_out,
1227 connection_struct **conn_out,
1228 char **oldpath)
1230 int snum;
1231 NTSTATUS status;
1233 snum = lp_servicenumber(jucn->service_name);
1234 if(snum < 0) {
1235 return False;
1237 status = create_conn_struct_cwd(talloc_tos(),
1238 server_event_context(),
1239 server_messaging_context(),
1240 conn_out,
1241 snum, lp_path(talloc_tos(), snum), NULL, oldpath);
1242 if (!NT_STATUS_IS_OK(status)) {
1243 return False;
1246 *pp_path_out = talloc_asprintf(*conn_out,
1247 "%s/%s",
1248 lp_path(talloc_tos(), snum),
1249 jucn->volume_name);
1250 if (!*pp_path_out) {
1251 vfs_ChDir(*conn_out, *oldpath);
1252 SMB_VFS_DISCONNECT(*conn_out);
1253 conn_free(*conn_out);
1254 return False;
1256 return True;
1259 bool create_msdfs_link(const struct junction_map *jucn)
1261 char *path = NULL;
1262 char *cwd;
1263 char *msdfs_link = NULL;
1264 connection_struct *conn;
1265 int i=0;
1266 bool insert_comma = False;
1267 bool ret = False;
1269 if(!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1270 return False;
1273 /* Form the msdfs_link contents */
1274 msdfs_link = talloc_strdup(conn, "msdfs:");
1275 if (!msdfs_link) {
1276 goto out;
1278 for(i=0; i<jucn->referral_count; i++) {
1279 char *refpath = jucn->referral_list[i].alternate_path;
1281 /* Alternate paths always use Windows separators. */
1282 trim_char(refpath, '\\', '\\');
1283 if(*refpath == '\0') {
1284 if (i == 0) {
1285 insert_comma = False;
1287 continue;
1289 if (i > 0 && insert_comma) {
1290 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1291 ",%s",
1292 refpath);
1293 } else {
1294 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1295 "%s",
1296 refpath);
1299 if (!msdfs_link) {
1300 goto out;
1302 if (!insert_comma) {
1303 insert_comma = True;
1307 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1308 path, msdfs_link));
1310 if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1311 if (errno == EEXIST) {
1312 struct smb_filename *smb_fname;
1314 smb_fname = synthetic_smb_fname(talloc_tos(), path,
1315 NULL, NULL);
1316 if (smb_fname == NULL) {
1317 errno = ENOMEM;
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;
1352 if (!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1353 return false;
1356 smb_fname = synthetic_smb_fname(talloc_tos(), path, NULL, NULL);
1357 if (smb_fname == NULL) {
1358 errno = ENOMEM;
1359 return false;
1362 if( SMB_VFS_UNLINK(conn, smb_fname) == 0 ) {
1363 ret = True;
1366 TALLOC_FREE(smb_fname);
1367 vfs_ChDir(conn, cwd);
1368 SMB_VFS_DISCONNECT(conn);
1369 conn_free(conn);
1370 return ret;
1373 /*********************************************************************
1374 Return the number of DFS links at the root of this share.
1375 *********************************************************************/
1377 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1379 size_t cnt = 0;
1380 DIR *dirp = NULL;
1381 const char *dname = NULL;
1382 char *talloced = NULL;
1383 const char *connect_path = lp_path(talloc_tos(), snum);
1384 const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum);
1385 connection_struct *conn;
1386 NTSTATUS status;
1387 char *cwd;
1389 if(*connect_path == '\0') {
1390 return 0;
1394 * Fake up a connection struct for the VFS layer.
1397 status = create_conn_struct_cwd(talloc_tos(),
1398 server_event_context(),
1399 server_messaging_context(),
1400 &conn,
1401 snum, connect_path, NULL, &cwd);
1402 if (!NT_STATUS_IS_OK(status)) {
1403 DEBUG(3, ("create_conn_struct failed: %s\n",
1404 nt_errstr(status)));
1405 return 0;
1408 /* Count a link for the msdfs root - convention */
1409 cnt = 1;
1411 /* No more links if this is an msdfs proxy. */
1412 if (*msdfs_proxy != '\0') {
1413 goto out;
1416 /* Now enumerate all dfs links */
1417 dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1418 if(!dirp) {
1419 goto out;
1422 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1423 != NULL) {
1424 if (is_msdfs_link(conn,
1425 dname,
1426 NULL)) {
1427 cnt++;
1429 TALLOC_FREE(talloced);
1432 SMB_VFS_CLOSEDIR(conn,dirp);
1434 out:
1435 vfs_ChDir(conn, cwd);
1436 SMB_VFS_DISCONNECT(conn);
1437 conn_free(conn);
1438 return cnt;
1441 /*********************************************************************
1442 *********************************************************************/
1444 static int form_junctions(TALLOC_CTX *ctx,
1445 int snum,
1446 struct junction_map *jucn,
1447 size_t jn_remain)
1449 size_t cnt = 0;
1450 DIR *dirp = NULL;
1451 const char *dname = NULL;
1452 char *talloced = NULL;
1453 const char *connect_path = lp_path(talloc_tos(), snum);
1454 char *service_name = lp_servicename(talloc_tos(), snum);
1455 const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum);
1456 connection_struct *conn;
1457 struct referral *ref = NULL;
1458 char *cwd;
1459 NTSTATUS status;
1461 if (jn_remain == 0) {
1462 return 0;
1465 if(*connect_path == '\0') {
1466 return 0;
1470 * Fake up a connection struct for the VFS layer.
1473 status = create_conn_struct_cwd(ctx,
1474 server_event_context(),
1475 server_messaging_context(),
1476 &conn, snum, connect_path, NULL,
1477 &cwd);
1478 if (!NT_STATUS_IS_OK(status)) {
1479 DEBUG(3, ("create_conn_struct failed: %s\n",
1480 nt_errstr(status)));
1481 return 0;
1484 /* form a junction for the msdfs root - convention
1485 DO NOT REMOVE THIS: NT clients will not work with us
1486 if this is not present
1488 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1489 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1490 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1491 goto out;
1493 jucn[cnt].comment = "";
1494 jucn[cnt].referral_count = 1;
1496 ref = jucn[cnt].referral_list = talloc_zero(ctx, struct referral);
1497 if (jucn[cnt].referral_list == NULL) {
1498 goto out;
1501 ref->proximity = 0;
1502 ref->ttl = REFERRAL_TTL;
1503 if (*msdfs_proxy != '\0') {
1504 ref->alternate_path = talloc_strdup(ctx,
1505 msdfs_proxy);
1506 } else {
1507 ref->alternate_path = talloc_asprintf(ctx,
1508 "\\\\%s\\%s",
1509 get_local_machine_name(),
1510 service_name);
1513 if (!ref->alternate_path) {
1514 goto out;
1516 cnt++;
1518 /* Don't enumerate if we're an msdfs proxy. */
1519 if (*msdfs_proxy != '\0') {
1520 goto out;
1523 /* Now enumerate all dfs links */
1524 dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1525 if(!dirp) {
1526 goto out;
1529 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1530 != NULL) {
1531 char *link_target = NULL;
1532 if (cnt >= jn_remain) {
1533 DEBUG(2, ("form_junctions: ran out of MSDFS "
1534 "junction slots"));
1535 TALLOC_FREE(talloced);
1536 goto out;
1538 if (is_msdfs_link_internal(ctx,
1539 conn,
1540 dname, &link_target,
1541 NULL)) {
1542 if (parse_msdfs_symlink(ctx, snum,
1543 link_target,
1544 &jucn[cnt].referral_list,
1545 &jucn[cnt].referral_count)) {
1547 jucn[cnt].service_name = talloc_strdup(ctx,
1548 service_name);
1549 jucn[cnt].volume_name = talloc_strdup(ctx,
1550 dname);
1551 if (!jucn[cnt].service_name ||
1552 !jucn[cnt].volume_name) {
1553 TALLOC_FREE(talloced);
1554 goto out;
1556 jucn[cnt].comment = "";
1557 cnt++;
1559 TALLOC_FREE(link_target);
1561 TALLOC_FREE(talloced);
1564 out:
1566 if (dirp) {
1567 SMB_VFS_CLOSEDIR(conn,dirp);
1570 vfs_ChDir(conn, cwd);
1571 conn_free(conn);
1572 return cnt;
1575 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1577 struct junction_map *jn = NULL;
1578 int i=0;
1579 size_t jn_count = 0;
1580 int sharecount = 0;
1582 *p_num_jn = 0;
1583 if(!lp_host_msdfs()) {
1584 return NULL;
1587 /* Ensure all the usershares are loaded. */
1588 become_root();
1589 load_registry_shares();
1590 sharecount = load_usershare_shares(NULL, connections_snum_used);
1591 unbecome_root();
1593 for(i=0;i < sharecount;i++) {
1594 if(lp_msdfs_root(i)) {
1595 jn_count += count_dfs_links(ctx, i);
1598 if (jn_count == 0) {
1599 return NULL;
1601 jn = talloc_array(ctx, struct junction_map, jn_count);
1602 if (!jn) {
1603 return NULL;
1605 for(i=0; i < sharecount; i++) {
1606 if (*p_num_jn >= jn_count) {
1607 break;
1609 if(lp_msdfs_root(i)) {
1610 *p_num_jn += form_junctions(ctx, i,
1611 &jn[*p_num_jn],
1612 jn_count - *p_num_jn);
1615 return jn;
1618 /******************************************************************************
1619 Core function to resolve a dfs pathname possibly containing a wildcard. If
1620 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1621 detected during dfs resolution.
1622 ******************************************************************************/
1624 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1625 connection_struct *conn,
1626 bool dfs_pathnames,
1627 const char *name_in,
1628 bool allow_wcards,
1629 bool allow_broken_path,
1630 char **pp_name_out,
1631 bool *ppath_contains_wcard)
1633 bool path_contains_wcard;
1634 NTSTATUS status = NT_STATUS_OK;
1636 if (dfs_pathnames) {
1637 status = dfs_redirect(ctx,
1638 conn,
1639 name_in,
1640 allow_wcards,
1641 allow_broken_path,
1642 pp_name_out,
1643 &path_contains_wcard);
1645 if (NT_STATUS_IS_OK(status) && ppath_contains_wcard != NULL) {
1646 *ppath_contains_wcard = path_contains_wcard;
1648 } else {
1650 * Cheat and just return a copy of the in ptr.
1651 * Once srvstr_get_path() uses talloc it'll
1652 * be a talloced ptr anyway.
1654 *pp_name_out = discard_const_p(char, name_in);
1656 return status;