ctdb-logging: Move variable debug_extra from debug.*
[Samba.git] / source3 / smbd / msdfs.c
blobbbf353d615c81a255796afc590e4471e37bf237c
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;
239 struct smbd_server_connection *sconn;
240 const char *servicename = lp_const_servicename(snum);
242 sconn = talloc_zero(ctx, struct smbd_server_connection);
243 if (sconn == NULL) {
244 return NT_STATUS_NO_MEMORY;
247 sconn->ev_ctx = ev;
248 sconn->msg_ctx = msg;
250 conn = conn_new(sconn);
251 if (conn == NULL) {
252 TALLOC_FREE(sconn);
253 return NT_STATUS_NO_MEMORY;
256 /* Now we have conn, we need to make sconn a child of conn,
257 * for a proper talloc tree */
258 talloc_steal(conn, sconn);
260 if (snum == -1 && servicename == NULL) {
261 servicename = "Unknown Service (snum == -1)";
264 connpath = talloc_strdup(conn, path);
265 if (!connpath) {
266 TALLOC_FREE(conn);
267 return NT_STATUS_NO_MEMORY;
269 connpath = talloc_string_sub(conn,
270 connpath,
271 "%S",
272 servicename);
273 if (!connpath) {
274 TALLOC_FREE(conn);
275 return NT_STATUS_NO_MEMORY;
278 /* needed for smbd_vfs_init() */
280 conn->params->service = snum;
281 conn->cnum = TID_FIELD_INVALID;
283 if (session_info != NULL) {
284 conn->session_info = copy_session_info(conn, session_info);
285 if (conn->session_info == NULL) {
286 DEBUG(0, ("copy_serverinfo failed\n"));
287 TALLOC_FREE(conn);
288 return NT_STATUS_NO_MEMORY;
290 vfs_user = conn->session_info->unix_info->unix_name;
291 } else {
292 /* use current authenticated user in absence of session_info */
293 vfs_user = get_current_username();
296 set_conn_connectpath(conn, connpath);
299 * New code to check if there's a share security descripter
300 * added from NT server manager. This is done after the
301 * smb.conf checks are done as we need a uid and token. JRA.
304 if (conn->session_info) {
305 share_access_check(conn->session_info->security_token,
306 servicename,
307 MAXIMUM_ALLOWED_ACCESS,
308 &conn->share_access);
310 if ((conn->share_access & FILE_WRITE_DATA) == 0) {
311 if ((conn->share_access & FILE_READ_DATA) == 0) {
312 /* No access, read or write. */
313 DEBUG(3,("create_conn_struct: connection to %s "
314 "denied due to security "
315 "descriptor.\n",
316 servicename));
317 conn_free(conn);
318 return NT_STATUS_ACCESS_DENIED;
319 } else {
320 conn->read_only = true;
323 } else {
324 conn->share_access = 0;
325 conn->read_only = true;
328 if (!smbd_vfs_init(conn)) {
329 NTSTATUS status = map_nt_error_from_unix(errno);
330 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
331 conn_free(conn);
332 return status;
335 /* this must be the first filesystem operation that we do */
336 if (SMB_VFS_CONNECT(conn, servicename, vfs_user) < 0) {
337 DEBUG(0,("VFS connect failed!\n"));
338 conn_free(conn);
339 return NT_STATUS_UNSUCCESSFUL;
342 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
343 *pconn = conn;
345 return NT_STATUS_OK;
348 /********************************************************
349 Fake up a connection struct for the VFS layer, for use in
350 applications (such as the python bindings), that do not want the
351 global working directory changed under them.
353 SMB_VFS_CONNECT requires root privileges.
354 *********************************************************/
356 NTSTATUS create_conn_struct(TALLOC_CTX *ctx,
357 struct tevent_context *ev,
358 struct messaging_context *msg,
359 connection_struct **pconn,
360 int snum,
361 const char *path,
362 const struct auth_session_info *session_info)
364 NTSTATUS status;
365 become_root();
366 status = create_conn_struct_as_root(ctx, ev,
367 msg, pconn,
368 snum, path,
369 session_info);
370 unbecome_root();
372 return status;
375 /********************************************************
376 Fake up a connection struct for the VFS layer.
377 Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
379 The old working directory is returned on *poldcwd, allocated on ctx.
380 *********************************************************/
382 NTSTATUS create_conn_struct_cwd(TALLOC_CTX *ctx,
383 struct tevent_context *ev,
384 struct messaging_context *msg,
385 connection_struct **pconn,
386 int snum,
387 const char *path,
388 const struct auth_session_info *session_info,
389 char **poldcwd)
391 connection_struct *conn;
392 char *oldcwd;
394 NTSTATUS status = create_conn_struct(ctx, ev,
395 msg, &conn,
396 snum, path,
397 session_info);
398 if (!NT_STATUS_IS_OK(status)) {
399 return status;
403 * Windows seems to insist on doing trans2getdfsreferral() calls on
404 * the IPC$ share as the anonymous user. If we try to chdir as that
405 * user we will fail.... WTF ? JRA.
408 oldcwd = vfs_GetWd(ctx, conn);
409 if (oldcwd == NULL) {
410 status = map_nt_error_from_unix(errno);
411 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
412 conn_free(conn);
413 return status;
416 if (vfs_ChDir(conn,conn->connectpath) != 0) {
417 status = map_nt_error_from_unix(errno);
418 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
419 "Error was %s\n",
420 conn->connectpath, strerror(errno) ));
421 conn_free(conn);
422 return status;
425 *pconn = conn;
426 *poldcwd = oldcwd;
428 return NT_STATUS_OK;
431 /**********************************************************************
432 Parse the contents of a symlink to verify if it is an msdfs referral
433 A valid referral is of the form:
435 msdfs:server1\share1,server2\share2
436 msdfs:server1\share1\pathname,server2\share2\pathname
437 msdfs:server1/share1,server2/share2
438 msdfs:server1/share1/pathname,server2/share2/pathname.
440 Note that the alternate paths returned here must be of the canonicalized
441 form:
443 \server\share or
444 \server\share\path\to\file,
446 even in posix path mode. This is because we have no knowledge if the
447 server we're referring to understands posix paths.
448 **********************************************************************/
450 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
451 const char *target,
452 struct referral **preflist,
453 int *refcount)
455 char *temp = NULL;
456 char *prot;
457 char **alt_path = NULL;
458 int count = 0, i;
459 struct referral *reflist;
460 char *saveptr;
462 temp = talloc_strdup(ctx, target);
463 if (!temp) {
464 return False;
466 prot = strtok_r(temp, ":", &saveptr);
467 if (!prot) {
468 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
469 return False;
472 alt_path = talloc_array(ctx, char *, MAX_REFERRAL_COUNT);
473 if (!alt_path) {
474 return False;
477 /* parse out the alternate paths */
478 while((count<MAX_REFERRAL_COUNT) &&
479 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
480 count++;
483 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
485 if (count) {
486 reflist = *preflist = talloc_zero_array(ctx,
487 struct referral, count);
488 if(reflist == NULL) {
489 TALLOC_FREE(alt_path);
490 return False;
492 } else {
493 reflist = *preflist = NULL;
496 for(i=0;i<count;i++) {
497 char *p;
499 /* Canonicalize link target.
500 * Replace all /'s in the path by a \ */
501 string_replace(alt_path[i], '/', '\\');
503 /* Remove leading '\\'s */
504 p = alt_path[i];
505 while (*p && (*p == '\\')) {
506 p++;
509 reflist[i].alternate_path = talloc_asprintf(ctx,
510 "\\%s",
512 if (!reflist[i].alternate_path) {
513 return False;
516 reflist[i].proximity = 0;
517 reflist[i].ttl = REFERRAL_TTL;
518 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
519 reflist[i].alternate_path));
522 *refcount = count;
524 TALLOC_FREE(alt_path);
525 return True;
528 /**********************************************************************
529 Returns true if the unix path is a valid msdfs symlink and also
530 returns the target string from inside the link.
531 **********************************************************************/
533 static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
534 connection_struct *conn,
535 const char *path,
536 char **pp_link_target,
537 SMB_STRUCT_STAT *sbufp)
539 int referral_len = 0;
540 #if defined(HAVE_BROKEN_READLINK)
541 char link_target_buf[PATH_MAX];
542 #else
543 char link_target_buf[7];
544 #endif
545 size_t bufsize = 0;
546 char *link_target = NULL;
547 struct smb_filename smb_fname;
549 if (pp_link_target) {
550 bufsize = 1024;
551 link_target = talloc_array(ctx, char, bufsize);
552 if (!link_target) {
553 return False;
555 *pp_link_target = link_target;
556 } else {
557 bufsize = sizeof(link_target_buf);
558 link_target = link_target_buf;
561 ZERO_STRUCT(smb_fname);
562 smb_fname.base_name = discard_const_p(char, path);
564 if (SMB_VFS_LSTAT(conn, &smb_fname) != 0) {
565 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
566 path));
567 goto err;
569 if (!S_ISLNK(smb_fname.st.st_ex_mode)) {
570 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
571 path));
572 goto err;
574 if (sbufp != NULL) {
575 *sbufp = smb_fname.st;
578 referral_len = SMB_VFS_READLINK(conn, path, link_target, bufsize - 1);
579 if (referral_len == -1) {
580 DEBUG(0,("is_msdfs_link_read_target: Error reading "
581 "msdfs link %s: %s\n",
582 path, strerror(errno)));
583 goto err;
585 link_target[referral_len] = '\0';
587 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path,
588 link_target));
590 if (!strnequal(link_target, "msdfs:", 6)) {
591 goto err;
593 return True;
595 err:
597 if (link_target != link_target_buf) {
598 TALLOC_FREE(link_target);
600 return False;
603 /**********************************************************************
604 Returns true if the unix path is a valid msdfs symlink.
605 **********************************************************************/
607 bool is_msdfs_link(connection_struct *conn,
608 const char *path,
609 SMB_STRUCT_STAT *sbufp)
611 return is_msdfs_link_internal(talloc_tos(),
612 conn,
613 path,
614 NULL,
615 sbufp);
618 /*****************************************************************
619 Used by other functions to decide if a dfs path is remote,
620 and to get the list of referred locations for that remote path.
622 search_flag: For findfirsts, dfs links themselves are not
623 redirected, but paths beyond the links are. For normal smb calls,
624 even dfs links need to be redirected.
626 consumedcntp: how much of the dfs path is being redirected. the client
627 should try the remaining path on the redirected server.
629 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
630 link redirect are in targetpath.
631 *****************************************************************/
633 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
634 connection_struct *conn,
635 const char *dfspath, /* Incoming complete dfs path */
636 const struct dfs_path *pdp, /* Parsed out
637 server+share+extrapath. */
638 bool search_flag, /* Called from a findfirst ? */
639 int *consumedcntp,
640 char **pp_targetpath)
642 char *p = NULL;
643 char *q = NULL;
644 NTSTATUS status;
645 struct smb_filename *smb_fname = NULL;
646 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
647 components). */
649 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
650 conn->connectpath, pdp->reqpath));
653 * Note the unix path conversion here we're doing we
654 * throw away. We're looking for a symlink for a dfs
655 * resolution, if we don't find it we'll do another
656 * unix_convert later in the codepath.
659 status = unix_convert(ctx, conn, pdp->reqpath, &smb_fname,
660 search_flag ? UCF_ALWAYS_ALLOW_WCARD_LCOMP : 0);
662 if (!NT_STATUS_IS_OK(status)) {
663 if (!NT_STATUS_EQUAL(status,
664 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
665 return status;
667 if (smb_fname == NULL || smb_fname->base_name == NULL) {
668 return status;
672 /* Optimization - check if we can redirect the whole path. */
674 if (is_msdfs_link_internal(ctx, conn, smb_fname->base_name,
675 pp_targetpath, NULL)) {
676 if (search_flag) {
677 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
678 "for dfs link %s.\n", dfspath));
679 status = NT_STATUS_OK;
680 goto out;
683 DEBUG(6,("dfs_path_lookup: %s resolves to a "
684 "valid dfs link %s.\n", dfspath,
685 pp_targetpath ? *pp_targetpath : ""));
687 if (consumedcntp) {
688 *consumedcntp = strlen(dfspath);
690 status = NT_STATUS_PATH_NOT_COVERED;
691 goto out;
694 /* Prepare to test only for '/' components in the given path,
695 * so if a Windows path replace all '\\' characters with '/'.
696 * For a POSIX DFS path we know all separators are already '/'. */
698 canon_dfspath = talloc_strdup(ctx, dfspath);
699 if (!canon_dfspath) {
700 status = NT_STATUS_NO_MEMORY;
701 goto out;
703 if (!pdp->posix_path) {
704 string_replace(canon_dfspath, '\\', '/');
708 * localpath comes out of unix_convert, so it has
709 * no trailing backslash. Make sure that canon_dfspath hasn't either.
710 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
713 trim_char(canon_dfspath,0,'/');
716 * Redirect if any component in the path is a link.
717 * We do this by walking backwards through the
718 * local path, chopping off the last component
719 * in both the local path and the canonicalized
720 * DFS path. If we hit a DFS link then we're done.
723 p = strrchr_m(smb_fname->base_name, '/');
724 if (consumedcntp) {
725 q = strrchr_m(canon_dfspath, '/');
728 while (p) {
729 *p = '\0';
730 if (q) {
731 *q = '\0';
734 if (is_msdfs_link_internal(ctx, conn,
735 smb_fname->base_name, pp_targetpath,
736 NULL)) {
737 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
738 "parent %s is dfs link\n", dfspath,
739 smb_fname_str_dbg(smb_fname)));
741 if (consumedcntp) {
742 *consumedcntp = strlen(canon_dfspath);
743 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
744 "(%d)\n",
745 canon_dfspath,
746 *consumedcntp));
749 status = NT_STATUS_PATH_NOT_COVERED;
750 goto out;
753 /* Step back on the filesystem. */
754 p = strrchr_m(smb_fname->base_name, '/');
756 if (consumedcntp) {
757 /* And in the canonicalized dfs path. */
758 q = strrchr_m(canon_dfspath, '/');
762 status = NT_STATUS_OK;
763 out:
764 TALLOC_FREE(smb_fname);
765 return status;
768 /*****************************************************************
769 Decides if a dfs pathname should be redirected or not.
770 If not, the pathname is converted to a tcon-relative local unix path
772 search_wcard_flag: this flag performs 2 functions both related
773 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
774 for details.
776 This function can return NT_STATUS_OK, meaning use the returned path as-is
777 (mapped into a local path).
778 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
779 any other NT_STATUS error which is a genuine error to be
780 returned to the client.
781 *****************************************************************/
783 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
784 connection_struct *conn,
785 const char *path_in,
786 bool search_wcard_flag,
787 bool allow_broken_path,
788 char **pp_path_out,
789 bool *ppath_contains_wcard)
791 NTSTATUS status;
792 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
794 if (!pdp) {
795 return NT_STATUS_NO_MEMORY;
798 status = parse_dfs_path(conn, path_in, search_wcard_flag,
799 allow_broken_path, pdp,
800 ppath_contains_wcard);
801 if (!NT_STATUS_IS_OK(status)) {
802 TALLOC_FREE(pdp);
803 return status;
806 if (pdp->reqpath[0] == '\0') {
807 TALLOC_FREE(pdp);
808 *pp_path_out = talloc_strdup(ctx, "");
809 if (!*pp_path_out) {
810 return NT_STATUS_NO_MEMORY;
812 DEBUG(5,("dfs_redirect: self-referral.\n"));
813 return NT_STATUS_OK;
816 /* If dfs pathname for a non-dfs share, convert to tcon-relative
817 path and return OK */
819 if (!lp_msdfs_root(SNUM(conn))) {
820 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
821 TALLOC_FREE(pdp);
822 if (!*pp_path_out) {
823 return NT_STATUS_NO_MEMORY;
825 return NT_STATUS_OK;
828 /* If it looked like a local path (zero hostname/servicename)
829 * just treat as a tcon-relative path. */
831 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
832 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
833 TALLOC_FREE(pdp);
834 if (!*pp_path_out) {
835 return NT_STATUS_NO_MEMORY;
837 return NT_STATUS_OK;
840 if (!( strequal(pdp->servicename, lp_servicename(talloc_tos(), SNUM(conn)))
841 || (strequal(pdp->servicename, HOMES_NAME)
842 && strequal(lp_servicename(talloc_tos(), SNUM(conn)),
843 conn->session_info->unix_info->sanitized_username) )) ) {
845 /* The given sharename doesn't match this connection. */
846 TALLOC_FREE(pdp);
848 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
851 status = dfs_path_lookup(ctx, conn, path_in, pdp,
852 search_wcard_flag, NULL, NULL);
853 if (!NT_STATUS_IS_OK(status)) {
854 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
855 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
856 } else {
857 DEBUG(10,("dfs_redirect: dfs_path_lookup "
858 "failed for %s with %s\n",
859 path_in, nt_errstr(status) ));
861 return status;
864 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
866 /* Form non-dfs tcon-relative path */
867 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
868 TALLOC_FREE(pdp);
869 if (!*pp_path_out) {
870 return NT_STATUS_NO_MEMORY;
873 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
874 path_in,
875 *pp_path_out));
877 return NT_STATUS_OK;
880 /**********************************************************************
881 Return a self referral.
882 **********************************************************************/
884 static NTSTATUS self_ref(TALLOC_CTX *ctx,
885 const char *dfs_path,
886 struct junction_map *jucn,
887 int *consumedcntp,
888 bool *self_referralp)
890 struct referral *ref;
892 *self_referralp = True;
894 jucn->referral_count = 1;
895 if((ref = talloc_zero(ctx, struct referral)) == NULL) {
896 return NT_STATUS_NO_MEMORY;
899 ref->alternate_path = talloc_strdup(ctx, dfs_path);
900 if (!ref->alternate_path) {
901 TALLOC_FREE(ref);
902 return NT_STATUS_NO_MEMORY;
904 ref->proximity = 0;
905 ref->ttl = REFERRAL_TTL;
906 jucn->referral_list = ref;
907 *consumedcntp = strlen(dfs_path);
908 return NT_STATUS_OK;
911 /**********************************************************************
912 Gets valid referrals for a dfs path and fills up the
913 junction_map structure.
914 **********************************************************************/
916 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
917 const char *dfs_path,
918 bool allow_broken_path,
919 struct junction_map *jucn,
920 int *consumedcntp,
921 bool *self_referralp)
923 struct connection_struct *conn;
924 char *targetpath = NULL;
925 int snum;
926 NTSTATUS status = NT_STATUS_NOT_FOUND;
927 bool dummy;
928 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
929 char *oldpath;
931 if (!pdp) {
932 return NT_STATUS_NO_MEMORY;
935 *self_referralp = False;
937 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
938 pdp, &dummy);
939 if (!NT_STATUS_IS_OK(status)) {
940 return status;
943 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
944 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
945 if (!jucn->service_name || !jucn->volume_name) {
946 TALLOC_FREE(pdp);
947 return NT_STATUS_NO_MEMORY;
950 /* Verify the share is a dfs root */
951 snum = lp_servicenumber(jucn->service_name);
952 if(snum < 0) {
953 char *service_name = NULL;
954 if ((snum = find_service(ctx, jucn->service_name, &service_name)) < 0) {
955 return NT_STATUS_NOT_FOUND;
957 if (!service_name) {
958 return NT_STATUS_NO_MEMORY;
960 TALLOC_FREE(jucn->service_name);
961 jucn->service_name = talloc_strdup(ctx, service_name);
962 if (!jucn->service_name) {
963 TALLOC_FREE(pdp);
964 return NT_STATUS_NO_MEMORY;
968 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(talloc_tos(), snum) == '\0')) {
969 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
970 "a dfs root.\n",
971 pdp->servicename, dfs_path));
972 TALLOC_FREE(pdp);
973 return NT_STATUS_NOT_FOUND;
977 * Self referrals are tested with a anonymous IPC connection and
978 * a GET_DFS_REFERRAL call to \\server\share. (which means
979 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
980 * into the directory and will fail if it cannot (as the anonymous
981 * user). Cope with this.
984 if (pdp->reqpath[0] == '\0') {
985 char *tmp;
986 struct referral *ref;
987 int refcount;
989 if (*lp_msdfs_proxy(talloc_tos(), snum) == '\0') {
990 TALLOC_FREE(pdp);
991 return self_ref(ctx,
992 dfs_path,
993 jucn,
994 consumedcntp,
995 self_referralp);
999 * It's an msdfs proxy share. Redirect to
1000 * the configured target share.
1003 tmp = talloc_asprintf(talloc_tos(), "msdfs:%s",
1004 lp_msdfs_proxy(talloc_tos(), snum));
1005 if (tmp == NULL) {
1006 TALLOC_FREE(pdp);
1007 return NT_STATUS_NO_MEMORY;
1010 if (!parse_msdfs_symlink(ctx, tmp, &ref, &refcount)) {
1011 TALLOC_FREE(tmp);
1012 TALLOC_FREE(pdp);
1013 return NT_STATUS_INVALID_PARAMETER;
1015 TALLOC_FREE(tmp);
1016 jucn->referral_count = refcount;
1017 jucn->referral_list = ref;
1018 *consumedcntp = strlen(dfs_path);
1019 TALLOC_FREE(pdp);
1020 return NT_STATUS_OK;
1023 status = create_conn_struct_cwd(ctx,
1024 server_event_context(),
1025 server_messaging_context(),
1026 &conn, snum,
1027 lp_path(talloc_tos(), snum), NULL, &oldpath);
1028 if (!NT_STATUS_IS_OK(status)) {
1029 TALLOC_FREE(pdp);
1030 return status;
1033 /* If this is a DFS path dfs_lookup should return
1034 * NT_STATUS_PATH_NOT_COVERED. */
1036 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
1037 False, consumedcntp, &targetpath);
1039 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
1040 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
1041 dfs_path));
1042 if (NT_STATUS_IS_OK(status)) {
1044 * We are in an error path here (we
1045 * know it's not a DFS path), but
1046 * dfs_path_lookup() can return
1047 * NT_STATUS_OK. Ensure we always
1048 * return a valid error code.
1050 * #9588 - ACLs are not inherited to directories
1051 * for DFS shares.
1053 status = NT_STATUS_NOT_FOUND;
1055 goto err_exit;
1058 /* We know this is a valid dfs link. Parse the targetpath. */
1059 if (!parse_msdfs_symlink(ctx, targetpath,
1060 &jucn->referral_list,
1061 &jucn->referral_count)) {
1062 DEBUG(3,("get_referred_path: failed to parse symlink "
1063 "target %s\n", targetpath ));
1064 status = NT_STATUS_NOT_FOUND;
1065 goto err_exit;
1068 status = NT_STATUS_OK;
1069 err_exit:
1070 vfs_ChDir(conn, oldpath);
1071 SMB_VFS_DISCONNECT(conn);
1072 conn_free(conn);
1073 TALLOC_FREE(pdp);
1074 return status;
1077 /******************************************************************
1078 Set up the DFS referral for the dfs pathname. This call returns
1079 the amount of the path covered by this server, and where the
1080 client should be redirected to. This is the meat of the
1081 TRANS2_GET_DFS_REFERRAL call.
1082 ******************************************************************/
1084 int setup_dfs_referral(connection_struct *orig_conn,
1085 const char *dfs_path,
1086 int max_referral_level,
1087 char **ppdata, NTSTATUS *pstatus)
1089 char *pdata = *ppdata;
1090 int reply_size = 0;
1091 struct dfs_GetDFSReferral *r;
1092 DATA_BLOB blob = data_blob_null;
1093 NTSTATUS status;
1094 enum ndr_err_code ndr_err;
1096 r = talloc_zero(talloc_tos(), struct dfs_GetDFSReferral);
1097 if (r == NULL) {
1098 *pstatus = NT_STATUS_NO_MEMORY;
1099 return -1;
1102 r->in.req.max_referral_level = max_referral_level;
1103 r->in.req.servername = talloc_strdup(r, dfs_path);
1104 if (r->in.req.servername == NULL) {
1105 talloc_free(r);
1106 *pstatus = NT_STATUS_NO_MEMORY;
1107 return -1;
1110 status = SMB_VFS_GET_DFS_REFERRALS(orig_conn, r);
1111 if (!NT_STATUS_IS_OK(status)) {
1112 talloc_free(r);
1113 *pstatus = status;
1114 return -1;
1117 ndr_err = ndr_push_struct_blob(&blob, r,
1118 r->out.resp,
1119 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1120 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1121 TALLOC_FREE(r);
1122 *pstatus = NT_STATUS_INVALID_PARAMETER;
1123 return -1;
1126 pdata = (char *)SMB_REALLOC(pdata, blob.length);
1127 if(pdata == NULL) {
1128 TALLOC_FREE(r);
1129 DEBUG(0,("referral setup:"
1130 "malloc failed for Realloc!\n"));
1131 return -1;
1133 *ppdata = pdata;
1134 reply_size = blob.length;
1135 memcpy(pdata, blob.data, blob.length);
1136 TALLOC_FREE(r);
1138 *pstatus = NT_STATUS_OK;
1139 return reply_size;
1142 /**********************************************************************
1143 The following functions are called by the NETDFS RPC pipe functions
1144 **********************************************************************/
1146 /*********************************************************************
1147 Creates a junction structure from a DFS pathname
1148 **********************************************************************/
1150 bool create_junction(TALLOC_CTX *ctx,
1151 const char *dfs_path,
1152 bool allow_broken_path,
1153 struct junction_map *jucn)
1155 int snum;
1156 bool dummy;
1157 struct dfs_path *pdp = talloc(ctx,struct dfs_path);
1158 NTSTATUS status;
1160 if (!pdp) {
1161 return False;
1163 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1164 pdp, &dummy);
1165 if (!NT_STATUS_IS_OK(status)) {
1166 return False;
1169 /* check if path is dfs : validate first token */
1170 if (!is_myname_or_ipaddr(pdp->hostname)) {
1171 DEBUG(4,("create_junction: Invalid hostname %s "
1172 "in dfs path %s\n",
1173 pdp->hostname, dfs_path));
1174 TALLOC_FREE(pdp);
1175 return False;
1178 /* Check for a non-DFS share */
1179 snum = lp_servicenumber(pdp->servicename);
1181 if(snum < 0 || !lp_msdfs_root(snum)) {
1182 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1183 pdp->servicename));
1184 TALLOC_FREE(pdp);
1185 return False;
1188 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1189 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1190 jucn->comment = lp_comment(ctx, snum);
1192 TALLOC_FREE(pdp);
1193 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1194 return False;
1196 return True;
1199 /**********************************************************************
1200 Forms a valid Unix pathname from the junction
1201 **********************************************************************/
1203 static bool junction_to_local_path(const struct junction_map *jucn,
1204 char **pp_path_out,
1205 connection_struct **conn_out,
1206 char **oldpath)
1208 int snum;
1209 NTSTATUS status;
1211 snum = lp_servicenumber(jucn->service_name);
1212 if(snum < 0) {
1213 return False;
1215 status = create_conn_struct_cwd(talloc_tos(),
1216 server_event_context(),
1217 server_messaging_context(),
1218 conn_out,
1219 snum, lp_path(talloc_tos(), snum), NULL, oldpath);
1220 if (!NT_STATUS_IS_OK(status)) {
1221 return False;
1224 *pp_path_out = talloc_asprintf(*conn_out,
1225 "%s/%s",
1226 lp_path(talloc_tos(), snum),
1227 jucn->volume_name);
1228 if (!*pp_path_out) {
1229 vfs_ChDir(*conn_out, *oldpath);
1230 SMB_VFS_DISCONNECT(*conn_out);
1231 conn_free(*conn_out);
1232 return False;
1234 return True;
1237 bool create_msdfs_link(const struct junction_map *jucn)
1239 char *path = NULL;
1240 char *cwd;
1241 char *msdfs_link = NULL;
1242 connection_struct *conn;
1243 int i=0;
1244 bool insert_comma = False;
1245 bool ret = False;
1247 if(!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1248 return False;
1251 /* Form the msdfs_link contents */
1252 msdfs_link = talloc_strdup(conn, "msdfs:");
1253 if (!msdfs_link) {
1254 goto out;
1256 for(i=0; i<jucn->referral_count; i++) {
1257 char *refpath = jucn->referral_list[i].alternate_path;
1259 /* Alternate paths always use Windows separators. */
1260 trim_char(refpath, '\\', '\\');
1261 if(*refpath == '\0') {
1262 if (i == 0) {
1263 insert_comma = False;
1265 continue;
1267 if (i > 0 && insert_comma) {
1268 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1269 ",%s",
1270 refpath);
1271 } else {
1272 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1273 "%s",
1274 refpath);
1277 if (!msdfs_link) {
1278 goto out;
1280 if (!insert_comma) {
1281 insert_comma = True;
1285 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1286 path, msdfs_link));
1288 if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1289 if (errno == EEXIST) {
1290 struct smb_filename *smb_fname;
1292 smb_fname = synthetic_smb_fname(talloc_tos(), path,
1293 NULL, NULL);
1294 if (smb_fname == NULL) {
1295 errno = ENOMEM;
1296 goto out;
1299 if(SMB_VFS_UNLINK(conn, smb_fname)!=0) {
1300 TALLOC_FREE(smb_fname);
1301 goto out;
1303 TALLOC_FREE(smb_fname);
1305 if (SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1306 DEBUG(1,("create_msdfs_link: symlink failed "
1307 "%s -> %s\nError: %s\n",
1308 path, msdfs_link, strerror(errno)));
1309 goto out;
1313 ret = True;
1315 out:
1316 vfs_ChDir(conn, cwd);
1317 SMB_VFS_DISCONNECT(conn);
1318 conn_free(conn);
1319 return ret;
1322 bool remove_msdfs_link(const struct junction_map *jucn)
1324 char *path = NULL;
1325 char *cwd;
1326 connection_struct *conn;
1327 bool ret = False;
1328 struct smb_filename *smb_fname;
1330 if (!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1331 return false;
1334 smb_fname = synthetic_smb_fname(talloc_tos(), path, NULL, NULL);
1335 if (smb_fname == NULL) {
1336 errno = ENOMEM;
1337 return false;
1340 if( SMB_VFS_UNLINK(conn, smb_fname) == 0 ) {
1341 ret = True;
1344 TALLOC_FREE(smb_fname);
1345 vfs_ChDir(conn, cwd);
1346 SMB_VFS_DISCONNECT(conn);
1347 conn_free(conn);
1348 return ret;
1351 /*********************************************************************
1352 Return the number of DFS links at the root of this share.
1353 *********************************************************************/
1355 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1357 size_t cnt = 0;
1358 DIR *dirp = NULL;
1359 const char *dname = NULL;
1360 char *talloced = NULL;
1361 const char *connect_path = lp_path(talloc_tos(), snum);
1362 const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum);
1363 connection_struct *conn;
1364 NTSTATUS status;
1365 char *cwd;
1367 if(*connect_path == '\0') {
1368 return 0;
1372 * Fake up a connection struct for the VFS layer.
1375 status = create_conn_struct_cwd(talloc_tos(),
1376 server_event_context(),
1377 server_messaging_context(),
1378 &conn,
1379 snum, connect_path, NULL, &cwd);
1380 if (!NT_STATUS_IS_OK(status)) {
1381 DEBUG(3, ("create_conn_struct failed: %s\n",
1382 nt_errstr(status)));
1383 return 0;
1386 /* Count a link for the msdfs root - convention */
1387 cnt = 1;
1389 /* No more links if this is an msdfs proxy. */
1390 if (*msdfs_proxy != '\0') {
1391 goto out;
1394 /* Now enumerate all dfs links */
1395 dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1396 if(!dirp) {
1397 goto out;
1400 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1401 != NULL) {
1402 if (is_msdfs_link(conn,
1403 dname,
1404 NULL)) {
1405 cnt++;
1407 TALLOC_FREE(talloced);
1410 SMB_VFS_CLOSEDIR(conn,dirp);
1412 out:
1413 vfs_ChDir(conn, cwd);
1414 SMB_VFS_DISCONNECT(conn);
1415 conn_free(conn);
1416 return cnt;
1419 /*********************************************************************
1420 *********************************************************************/
1422 static int form_junctions(TALLOC_CTX *ctx,
1423 int snum,
1424 struct junction_map *jucn,
1425 size_t jn_remain)
1427 size_t cnt = 0;
1428 DIR *dirp = NULL;
1429 const char *dname = NULL;
1430 char *talloced = NULL;
1431 const char *connect_path = lp_path(talloc_tos(), snum);
1432 char *service_name = lp_servicename(talloc_tos(), snum);
1433 const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum);
1434 connection_struct *conn;
1435 struct referral *ref = NULL;
1436 char *cwd;
1437 NTSTATUS status;
1439 if (jn_remain == 0) {
1440 return 0;
1443 if(*connect_path == '\0') {
1444 return 0;
1448 * Fake up a connection struct for the VFS layer.
1451 status = create_conn_struct_cwd(ctx,
1452 server_event_context(),
1453 server_messaging_context(),
1454 &conn, snum, connect_path, NULL,
1455 &cwd);
1456 if (!NT_STATUS_IS_OK(status)) {
1457 DEBUG(3, ("create_conn_struct failed: %s\n",
1458 nt_errstr(status)));
1459 return 0;
1462 /* form a junction for the msdfs root - convention
1463 DO NOT REMOVE THIS: NT clients will not work with us
1464 if this is not present
1466 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1467 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1468 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1469 goto out;
1471 jucn[cnt].comment = "";
1472 jucn[cnt].referral_count = 1;
1474 ref = jucn[cnt].referral_list = talloc_zero(ctx, struct referral);
1475 if (jucn[cnt].referral_list == NULL) {
1476 goto out;
1479 ref->proximity = 0;
1480 ref->ttl = REFERRAL_TTL;
1481 if (*msdfs_proxy != '\0') {
1482 ref->alternate_path = talloc_strdup(ctx,
1483 msdfs_proxy);
1484 } else {
1485 ref->alternate_path = talloc_asprintf(ctx,
1486 "\\\\%s\\%s",
1487 get_local_machine_name(),
1488 service_name);
1491 if (!ref->alternate_path) {
1492 goto out;
1494 cnt++;
1496 /* Don't enumerate if we're an msdfs proxy. */
1497 if (*msdfs_proxy != '\0') {
1498 goto out;
1501 /* Now enumerate all dfs links */
1502 dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1503 if(!dirp) {
1504 goto out;
1507 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1508 != NULL) {
1509 char *link_target = NULL;
1510 if (cnt >= jn_remain) {
1511 DEBUG(2, ("form_junctions: ran out of MSDFS "
1512 "junction slots"));
1513 TALLOC_FREE(talloced);
1514 goto out;
1516 if (is_msdfs_link_internal(ctx,
1517 conn,
1518 dname, &link_target,
1519 NULL)) {
1520 if (parse_msdfs_symlink(ctx,
1521 link_target,
1522 &jucn[cnt].referral_list,
1523 &jucn[cnt].referral_count)) {
1525 jucn[cnt].service_name = talloc_strdup(ctx,
1526 service_name);
1527 jucn[cnt].volume_name = talloc_strdup(ctx,
1528 dname);
1529 if (!jucn[cnt].service_name ||
1530 !jucn[cnt].volume_name) {
1531 TALLOC_FREE(talloced);
1532 goto out;
1534 jucn[cnt].comment = "";
1535 cnt++;
1537 TALLOC_FREE(link_target);
1539 TALLOC_FREE(talloced);
1542 out:
1544 if (dirp) {
1545 SMB_VFS_CLOSEDIR(conn,dirp);
1548 vfs_ChDir(conn, cwd);
1549 conn_free(conn);
1550 return cnt;
1553 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1555 struct junction_map *jn = NULL;
1556 int i=0;
1557 size_t jn_count = 0;
1558 int sharecount = 0;
1560 *p_num_jn = 0;
1561 if(!lp_host_msdfs()) {
1562 return NULL;
1565 /* Ensure all the usershares are loaded. */
1566 become_root();
1567 load_registry_shares();
1568 sharecount = load_usershare_shares(NULL, connections_snum_used);
1569 unbecome_root();
1571 for(i=0;i < sharecount;i++) {
1572 if(lp_msdfs_root(i)) {
1573 jn_count += count_dfs_links(ctx, i);
1576 if (jn_count == 0) {
1577 return NULL;
1579 jn = talloc_array(ctx, struct junction_map, jn_count);
1580 if (!jn) {
1581 return NULL;
1583 for(i=0; i < sharecount; i++) {
1584 if (*p_num_jn >= jn_count) {
1585 break;
1587 if(lp_msdfs_root(i)) {
1588 *p_num_jn += form_junctions(ctx, i,
1589 &jn[*p_num_jn],
1590 jn_count - *p_num_jn);
1593 return jn;
1596 /******************************************************************************
1597 Core function to resolve a dfs pathname possibly containing a wildcard. If
1598 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1599 detected during dfs resolution.
1600 ******************************************************************************/
1602 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1603 connection_struct *conn,
1604 bool dfs_pathnames,
1605 const char *name_in,
1606 bool allow_wcards,
1607 bool allow_broken_path,
1608 char **pp_name_out,
1609 bool *ppath_contains_wcard)
1611 bool path_contains_wcard;
1612 NTSTATUS status = NT_STATUS_OK;
1614 if (dfs_pathnames) {
1615 status = dfs_redirect(ctx,
1616 conn,
1617 name_in,
1618 allow_wcards,
1619 allow_broken_path,
1620 pp_name_out,
1621 &path_contains_wcard);
1623 if (NT_STATUS_IS_OK(status) && ppath_contains_wcard != NULL) {
1624 *ppath_contains_wcard = path_contains_wcard;
1626 } else {
1628 * Cheat and just return a copy of the in ptr.
1629 * Once srvstr_get_path() uses talloc it'll
1630 * be a talloced ptr anyway.
1632 *pp_name_out = discard_const_p(char, name_in);
1634 return status;