smbd: Fix calls to create_conn_struct_cwd to be correctly indented.
[Samba/gebeck_regimport.git] / source3 / smbd / msdfs.c
blobe8a0610d74f71e777d38558218a215d72ffb2375
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.
224 *********************************************************/
226 NTSTATUS create_conn_struct(TALLOC_CTX *ctx,
227 struct tevent_context *ev,
228 struct messaging_context *msg,
229 connection_struct **pconn,
230 int snum,
231 const char *path,
232 const struct auth_session_info *session_info)
234 connection_struct *conn;
235 char *connpath;
236 const char *vfs_user;
238 conn = talloc_zero(ctx, connection_struct);
239 if (conn == NULL) {
240 return NT_STATUS_NO_MEMORY;
243 connpath = talloc_strdup(conn, path);
244 if (!connpath) {
245 TALLOC_FREE(conn);
246 return NT_STATUS_NO_MEMORY;
248 connpath = talloc_string_sub(conn,
249 connpath,
250 "%S",
251 lp_servicename(talloc_tos(), snum));
252 if (!connpath) {
253 TALLOC_FREE(conn);
254 return NT_STATUS_NO_MEMORY;
257 conn->sconn = talloc_zero(conn, struct smbd_server_connection);
258 if (conn->sconn == NULL) {
259 TALLOC_FREE(conn);
260 return NT_STATUS_NO_MEMORY;
263 conn->sconn->ev_ctx = ev;
264 conn->sconn->msg_ctx = msg;
265 conn->sconn->sock = -1;
266 conn->sconn->smb1.echo_handler.trusted_fd = -1;
267 conn->sconn->smb1.echo_handler.socket_lock_fd = -1;
269 /* needed for smbd_vfs_init() */
271 if (!(conn->params = talloc_zero(conn, struct share_params))) {
272 DEBUG(0, ("TALLOC failed\n"));
273 TALLOC_FREE(conn);
274 return NT_STATUS_NO_MEMORY;
277 conn->params->service = snum;
278 conn->cnum = TID_FIELD_INVALID;
280 DLIST_ADD(conn->sconn->connections, conn);
281 conn->sconn->num_connections++;
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 lp_servicename(talloc_tos(), snum),
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(0,("create_conn_struct: connection to %s "
314 "denied due to security "
315 "descriptor.\n",
316 lp_servicename(talloc_tos(), snum)));
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, lp_servicename(talloc_tos(), snum), 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.
350 Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
352 The old working directory is returned on *poldcwd, allocated on ctx.
353 *********************************************************/
355 NTSTATUS create_conn_struct_cwd(TALLOC_CTX *ctx,
356 struct tevent_context *ev,
357 struct messaging_context *msg,
358 connection_struct **pconn,
359 int snum,
360 const char *path,
361 const struct auth_session_info *session_info,
362 char **poldcwd)
364 connection_struct *conn;
365 char *oldcwd;
367 NTSTATUS status = create_conn_struct(ctx, ev,
368 msg, &conn,
369 snum, path,
370 session_info);
371 if (!NT_STATUS_IS_OK(status)) {
372 return status;
376 * Windows seems to insist on doing trans2getdfsreferral() calls on
377 * the IPC$ share as the anonymous user. If we try to chdir as that
378 * user we will fail.... WTF ? JRA.
381 oldcwd = vfs_GetWd(ctx, conn);
382 if (oldcwd == NULL) {
383 status = map_nt_error_from_unix(errno);
384 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
385 conn_free(conn);
386 return status;
389 if (vfs_ChDir(conn,conn->connectpath) != 0) {
390 status = map_nt_error_from_unix(errno);
391 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
392 "Error was %s\n",
393 conn->connectpath, strerror(errno) ));
394 conn_free(conn);
395 return status;
398 *pconn = conn;
399 *poldcwd = oldcwd;
401 return NT_STATUS_OK;
404 /**********************************************************************
405 Parse the contents of a symlink to verify if it is an msdfs referral
406 A valid referral is of the form:
408 msdfs:server1\share1,server2\share2
409 msdfs:server1\share1\pathname,server2\share2\pathname
410 msdfs:server1/share1,server2/share2
411 msdfs:server1/share1/pathname,server2/share2/pathname.
413 Note that the alternate paths returned here must be of the canonicalized
414 form:
416 \server\share or
417 \server\share\path\to\file,
419 even in posix path mode. This is because we have no knowledge if the
420 server we're referring to understands posix paths.
421 **********************************************************************/
423 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
424 const char *target,
425 struct referral **preflist,
426 int *refcount)
428 char *temp = NULL;
429 char *prot;
430 char **alt_path = NULL;
431 int count = 0, i;
432 struct referral *reflist;
433 char *saveptr;
435 temp = talloc_strdup(ctx, target);
436 if (!temp) {
437 return False;
439 prot = strtok_r(temp, ":", &saveptr);
440 if (!prot) {
441 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
442 return False;
445 alt_path = talloc_array(ctx, char *, MAX_REFERRAL_COUNT);
446 if (!alt_path) {
447 return False;
450 /* parse out the alternate paths */
451 while((count<MAX_REFERRAL_COUNT) &&
452 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
453 count++;
456 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
458 if (count) {
459 reflist = *preflist = talloc_zero_array(ctx,
460 struct referral, count);
461 if(reflist == NULL) {
462 TALLOC_FREE(alt_path);
463 return False;
465 } else {
466 reflist = *preflist = NULL;
469 for(i=0;i<count;i++) {
470 char *p;
472 /* Canonicalize link target.
473 * Replace all /'s in the path by a \ */
474 string_replace(alt_path[i], '/', '\\');
476 /* Remove leading '\\'s */
477 p = alt_path[i];
478 while (*p && (*p == '\\')) {
479 p++;
482 reflist[i].alternate_path = talloc_asprintf(ctx,
483 "\\%s",
485 if (!reflist[i].alternate_path) {
486 return False;
489 reflist[i].proximity = 0;
490 reflist[i].ttl = REFERRAL_TTL;
491 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
492 reflist[i].alternate_path));
495 *refcount = count;
497 TALLOC_FREE(alt_path);
498 return True;
501 /**********************************************************************
502 Returns true if the unix path is a valid msdfs symlink and also
503 returns the target string from inside the link.
504 **********************************************************************/
506 static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
507 connection_struct *conn,
508 const char *path,
509 char **pp_link_target,
510 SMB_STRUCT_STAT *sbufp)
512 int referral_len = 0;
513 #if defined(HAVE_BROKEN_READLINK)
514 char link_target_buf[PATH_MAX];
515 #else
516 char link_target_buf[7];
517 #endif
518 size_t bufsize = 0;
519 char *link_target = NULL;
520 struct smb_filename smb_fname;
522 if (pp_link_target) {
523 bufsize = 1024;
524 link_target = talloc_array(ctx, char, bufsize);
525 if (!link_target) {
526 return False;
528 *pp_link_target = link_target;
529 } else {
530 bufsize = sizeof(link_target_buf);
531 link_target = link_target_buf;
534 ZERO_STRUCT(smb_fname);
535 smb_fname.base_name = discard_const_p(char, path);
537 if (SMB_VFS_LSTAT(conn, &smb_fname) != 0) {
538 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
539 path));
540 goto err;
542 if (!S_ISLNK(smb_fname.st.st_ex_mode)) {
543 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
544 path));
545 goto err;
547 if (sbufp != NULL) {
548 *sbufp = smb_fname.st;
551 referral_len = SMB_VFS_READLINK(conn, path, link_target, bufsize - 1);
552 if (referral_len == -1) {
553 DEBUG(0,("is_msdfs_link_read_target: Error reading "
554 "msdfs link %s: %s\n",
555 path, strerror(errno)));
556 goto err;
558 link_target[referral_len] = '\0';
560 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path,
561 link_target));
563 if (!strnequal(link_target, "msdfs:", 6)) {
564 goto err;
566 return True;
568 err:
570 if (link_target != link_target_buf) {
571 TALLOC_FREE(link_target);
573 return False;
576 /**********************************************************************
577 Returns true if the unix path is a valid msdfs symlink.
578 **********************************************************************/
580 bool is_msdfs_link(connection_struct *conn,
581 const char *path,
582 SMB_STRUCT_STAT *sbufp)
584 return is_msdfs_link_internal(talloc_tos(),
585 conn,
586 path,
587 NULL,
588 sbufp);
591 /*****************************************************************
592 Used by other functions to decide if a dfs path is remote,
593 and to get the list of referred locations for that remote path.
595 search_flag: For findfirsts, dfs links themselves are not
596 redirected, but paths beyond the links are. For normal smb calls,
597 even dfs links need to be redirected.
599 consumedcntp: how much of the dfs path is being redirected. the client
600 should try the remaining path on the redirected server.
602 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
603 link redirect are in targetpath.
604 *****************************************************************/
606 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
607 connection_struct *conn,
608 const char *dfspath, /* Incoming complete dfs path */
609 const struct dfs_path *pdp, /* Parsed out
610 server+share+extrapath. */
611 bool search_flag, /* Called from a findfirst ? */
612 int *consumedcntp,
613 char **pp_targetpath)
615 char *p = NULL;
616 char *q = NULL;
617 NTSTATUS status;
618 struct smb_filename *smb_fname = NULL;
619 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
620 components). */
622 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
623 conn->connectpath, pdp->reqpath));
626 * Note the unix path conversion here we're doing we
627 * throw away. We're looking for a symlink for a dfs
628 * resolution, if we don't find it we'll do another
629 * unix_convert later in the codepath.
632 status = unix_convert(ctx, conn, pdp->reqpath, &smb_fname,
633 search_flag ? UCF_ALWAYS_ALLOW_WCARD_LCOMP : 0);
635 if (!NT_STATUS_IS_OK(status)) {
636 if (!NT_STATUS_EQUAL(status,
637 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
638 return status;
640 if (smb_fname == NULL || smb_fname->base_name == NULL) {
641 return status;
645 /* Optimization - check if we can redirect the whole path. */
647 if (is_msdfs_link_internal(ctx, conn, smb_fname->base_name,
648 pp_targetpath, NULL)) {
649 if (search_flag) {
650 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
651 "for dfs link %s.\n", dfspath));
652 status = NT_STATUS_OK;
653 goto out;
656 DEBUG(6,("dfs_path_lookup: %s resolves to a "
657 "valid dfs link %s.\n", dfspath,
658 pp_targetpath ? *pp_targetpath : ""));
660 if (consumedcntp) {
661 *consumedcntp = strlen(dfspath);
663 status = NT_STATUS_PATH_NOT_COVERED;
664 goto out;
667 /* Prepare to test only for '/' components in the given path,
668 * so if a Windows path replace all '\\' characters with '/'.
669 * For a POSIX DFS path we know all separators are already '/'. */
671 canon_dfspath = talloc_strdup(ctx, dfspath);
672 if (!canon_dfspath) {
673 status = NT_STATUS_NO_MEMORY;
674 goto out;
676 if (!pdp->posix_path) {
677 string_replace(canon_dfspath, '\\', '/');
681 * localpath comes out of unix_convert, so it has
682 * no trailing backslash. Make sure that canon_dfspath hasn't either.
683 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
686 trim_char(canon_dfspath,0,'/');
689 * Redirect if any component in the path is a link.
690 * We do this by walking backwards through the
691 * local path, chopping off the last component
692 * in both the local path and the canonicalized
693 * DFS path. If we hit a DFS link then we're done.
696 p = strrchr_m(smb_fname->base_name, '/');
697 if (consumedcntp) {
698 q = strrchr_m(canon_dfspath, '/');
701 while (p) {
702 *p = '\0';
703 if (q) {
704 *q = '\0';
707 if (is_msdfs_link_internal(ctx, conn,
708 smb_fname->base_name, pp_targetpath,
709 NULL)) {
710 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
711 "parent %s is dfs link\n", dfspath,
712 smb_fname_str_dbg(smb_fname)));
714 if (consumedcntp) {
715 *consumedcntp = strlen(canon_dfspath);
716 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
717 "(%d)\n",
718 canon_dfspath,
719 *consumedcntp));
722 status = NT_STATUS_PATH_NOT_COVERED;
723 goto out;
726 /* Step back on the filesystem. */
727 p = strrchr_m(smb_fname->base_name, '/');
729 if (consumedcntp) {
730 /* And in the canonicalized dfs path. */
731 q = strrchr_m(canon_dfspath, '/');
735 status = NT_STATUS_OK;
736 out:
737 TALLOC_FREE(smb_fname);
738 return status;
741 /*****************************************************************
742 Decides if a dfs pathname should be redirected or not.
743 If not, the pathname is converted to a tcon-relative local unix path
745 search_wcard_flag: this flag performs 2 functions both related
746 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
747 for details.
749 This function can return NT_STATUS_OK, meaning use the returned path as-is
750 (mapped into a local path).
751 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
752 any other NT_STATUS error which is a genuine error to be
753 returned to the client.
754 *****************************************************************/
756 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
757 connection_struct *conn,
758 const char *path_in,
759 bool search_wcard_flag,
760 bool allow_broken_path,
761 char **pp_path_out,
762 bool *ppath_contains_wcard)
764 NTSTATUS status;
765 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
767 if (!pdp) {
768 return NT_STATUS_NO_MEMORY;
771 status = parse_dfs_path(conn, path_in, search_wcard_flag,
772 allow_broken_path, pdp,
773 ppath_contains_wcard);
774 if (!NT_STATUS_IS_OK(status)) {
775 TALLOC_FREE(pdp);
776 return status;
779 if (pdp->reqpath[0] == '\0') {
780 TALLOC_FREE(pdp);
781 *pp_path_out = talloc_strdup(ctx, "");
782 if (!*pp_path_out) {
783 return NT_STATUS_NO_MEMORY;
785 DEBUG(5,("dfs_redirect: self-referral.\n"));
786 return NT_STATUS_OK;
789 /* If dfs pathname for a non-dfs share, convert to tcon-relative
790 path and return OK */
792 if (!lp_msdfs_root(SNUM(conn))) {
793 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
794 TALLOC_FREE(pdp);
795 if (!*pp_path_out) {
796 return NT_STATUS_NO_MEMORY;
798 return NT_STATUS_OK;
801 /* If it looked like a local path (zero hostname/servicename)
802 * just treat as a tcon-relative path. */
804 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
805 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
806 TALLOC_FREE(pdp);
807 if (!*pp_path_out) {
808 return NT_STATUS_NO_MEMORY;
810 return NT_STATUS_OK;
813 if (!( strequal(pdp->servicename, lp_servicename(talloc_tos(), SNUM(conn)))
814 || (strequal(pdp->servicename, HOMES_NAME)
815 && strequal(lp_servicename(talloc_tos(), SNUM(conn)),
816 conn->session_info->unix_info->sanitized_username) )) ) {
818 /* The given sharename doesn't match this connection. */
819 TALLOC_FREE(pdp);
821 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
824 status = dfs_path_lookup(ctx, conn, path_in, pdp,
825 search_wcard_flag, NULL, NULL);
826 if (!NT_STATUS_IS_OK(status)) {
827 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
828 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
829 } else {
830 DEBUG(10,("dfs_redirect: dfs_path_lookup "
831 "failed for %s with %s\n",
832 path_in, nt_errstr(status) ));
834 return status;
837 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
839 /* Form non-dfs tcon-relative path */
840 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
841 TALLOC_FREE(pdp);
842 if (!*pp_path_out) {
843 return NT_STATUS_NO_MEMORY;
846 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
847 path_in,
848 *pp_path_out));
850 return NT_STATUS_OK;
853 /**********************************************************************
854 Return a self referral.
855 **********************************************************************/
857 static NTSTATUS self_ref(TALLOC_CTX *ctx,
858 const char *dfs_path,
859 struct junction_map *jucn,
860 int *consumedcntp,
861 bool *self_referralp)
863 struct referral *ref;
865 *self_referralp = True;
867 jucn->referral_count = 1;
868 if((ref = talloc_zero(ctx, struct referral)) == NULL) {
869 return NT_STATUS_NO_MEMORY;
872 ref->alternate_path = talloc_strdup(ctx, dfs_path);
873 if (!ref->alternate_path) {
874 TALLOC_FREE(ref);
875 return NT_STATUS_NO_MEMORY;
877 ref->proximity = 0;
878 ref->ttl = REFERRAL_TTL;
879 jucn->referral_list = ref;
880 *consumedcntp = strlen(dfs_path);
881 return NT_STATUS_OK;
884 /**********************************************************************
885 Gets valid referrals for a dfs path and fills up the
886 junction_map structure.
887 **********************************************************************/
889 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
890 const char *dfs_path,
891 bool allow_broken_path,
892 struct junction_map *jucn,
893 int *consumedcntp,
894 bool *self_referralp)
896 struct connection_struct *conn;
897 char *targetpath = NULL;
898 int snum;
899 NTSTATUS status = NT_STATUS_NOT_FOUND;
900 bool dummy;
901 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
902 char *oldpath;
904 if (!pdp) {
905 return NT_STATUS_NO_MEMORY;
908 *self_referralp = False;
910 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
911 pdp, &dummy);
912 if (!NT_STATUS_IS_OK(status)) {
913 return status;
916 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
917 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
918 if (!jucn->service_name || !jucn->volume_name) {
919 TALLOC_FREE(pdp);
920 return NT_STATUS_NO_MEMORY;
923 /* Verify the share is a dfs root */
924 snum = lp_servicenumber(jucn->service_name);
925 if(snum < 0) {
926 char *service_name = NULL;
927 if ((snum = find_service(ctx, jucn->service_name, &service_name)) < 0) {
928 return NT_STATUS_NOT_FOUND;
930 if (!service_name) {
931 return NT_STATUS_NO_MEMORY;
933 TALLOC_FREE(jucn->service_name);
934 jucn->service_name = talloc_strdup(ctx, service_name);
935 if (!jucn->service_name) {
936 TALLOC_FREE(pdp);
937 return NT_STATUS_NO_MEMORY;
941 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(talloc_tos(), snum) == '\0')) {
942 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
943 "a dfs root.\n",
944 pdp->servicename, dfs_path));
945 TALLOC_FREE(pdp);
946 return NT_STATUS_NOT_FOUND;
950 * Self referrals are tested with a anonymous IPC connection and
951 * a GET_DFS_REFERRAL call to \\server\share. (which means
952 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
953 * into the directory and will fail if it cannot (as the anonymous
954 * user). Cope with this.
957 if (pdp->reqpath[0] == '\0') {
958 char *tmp;
959 struct referral *ref;
961 if (*lp_msdfs_proxy(talloc_tos(), snum) == '\0') {
962 TALLOC_FREE(pdp);
963 return self_ref(ctx,
964 dfs_path,
965 jucn,
966 consumedcntp,
967 self_referralp);
971 * It's an msdfs proxy share. Redirect to
972 * the configured target share.
975 jucn->referral_count = 1;
976 if ((ref = talloc_zero(ctx, struct referral)) == NULL) {
977 TALLOC_FREE(pdp);
978 return NT_STATUS_NO_MEMORY;
981 if (!(tmp = talloc_strdup(ctx, lp_msdfs_proxy(talloc_tos(), snum)))) {
982 TALLOC_FREE(pdp);
983 return NT_STATUS_NO_MEMORY;
986 trim_string(tmp, "\\", 0);
988 ref->alternate_path = talloc_asprintf(ctx, "\\%s", tmp);
989 TALLOC_FREE(tmp);
991 if (!ref->alternate_path) {
992 TALLOC_FREE(pdp);
993 return NT_STATUS_NO_MEMORY;
996 if (pdp->reqpath[0] != '\0') {
997 ref->alternate_path = talloc_asprintf_append(
998 ref->alternate_path,
999 "%s",
1000 pdp->reqpath);
1001 if (!ref->alternate_path) {
1002 TALLOC_FREE(pdp);
1003 return NT_STATUS_NO_MEMORY;
1006 ref->proximity = 0;
1007 ref->ttl = REFERRAL_TTL;
1008 jucn->referral_list = ref;
1009 *consumedcntp = strlen(dfs_path);
1010 TALLOC_FREE(pdp);
1011 return NT_STATUS_OK;
1014 status = create_conn_struct_cwd(ctx,
1015 server_event_context(),
1016 server_messaging_context(),
1017 &conn, snum,
1018 lp_pathname(talloc_tos(), snum), NULL, &oldpath);
1019 if (!NT_STATUS_IS_OK(status)) {
1020 TALLOC_FREE(pdp);
1021 return status;
1024 /* If this is a DFS path dfs_lookup should return
1025 * NT_STATUS_PATH_NOT_COVERED. */
1027 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
1028 False, consumedcntp, &targetpath);
1030 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
1031 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
1032 dfs_path));
1033 goto err_exit;
1036 /* We know this is a valid dfs link. Parse the targetpath. */
1037 if (!parse_msdfs_symlink(ctx, targetpath,
1038 &jucn->referral_list,
1039 &jucn->referral_count)) {
1040 DEBUG(3,("get_referred_path: failed to parse symlink "
1041 "target %s\n", targetpath ));
1042 status = NT_STATUS_NOT_FOUND;
1043 goto err_exit;
1046 status = NT_STATUS_OK;
1047 err_exit:
1048 vfs_ChDir(conn, oldpath);
1049 SMB_VFS_DISCONNECT(conn);
1050 conn_free(conn);
1051 TALLOC_FREE(pdp);
1052 return status;
1055 /******************************************************************
1056 Set up the DFS referral for the dfs pathname. This call returns
1057 the amount of the path covered by this server, and where the
1058 client should be redirected to. This is the meat of the
1059 TRANS2_GET_DFS_REFERRAL call.
1060 ******************************************************************/
1062 int setup_dfs_referral(connection_struct *orig_conn,
1063 const char *dfs_path,
1064 int max_referral_level,
1065 char **ppdata, NTSTATUS *pstatus)
1067 char *pdata = *ppdata;
1068 int reply_size = 0;
1069 struct dfs_GetDFSReferral *r;
1070 DATA_BLOB blob = data_blob_null;
1071 NTSTATUS status;
1072 enum ndr_err_code ndr_err;
1074 r = talloc_zero(talloc_tos(), struct dfs_GetDFSReferral);
1075 if (r == NULL) {
1076 *pstatus = NT_STATUS_NO_MEMORY;
1077 return -1;
1080 r->in.req.max_referral_level = max_referral_level;
1081 r->in.req.servername = talloc_strdup(r, dfs_path);
1082 if (r->in.req.servername == NULL) {
1083 talloc_free(r);
1084 *pstatus = NT_STATUS_NO_MEMORY;
1085 return -1;
1088 status = SMB_VFS_GET_DFS_REFERRALS(orig_conn, r);
1089 if (!NT_STATUS_IS_OK(status)) {
1090 talloc_free(r);
1091 *pstatus = status;
1092 return -1;
1095 ndr_err = ndr_push_struct_blob(&blob, r,
1096 r->out.resp,
1097 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1098 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1099 TALLOC_FREE(r);
1100 *pstatus = NT_STATUS_INVALID_PARAMETER;
1101 return -1;
1104 pdata = (char *)SMB_REALLOC(pdata, blob.length);
1105 if(pdata == NULL) {
1106 TALLOC_FREE(r);
1107 DEBUG(0,("referral setup:"
1108 "malloc failed for Realloc!\n"));
1109 return -1;
1111 *ppdata = pdata;
1112 reply_size = blob.length;
1113 memcpy(pdata, blob.data, blob.length);
1114 TALLOC_FREE(r);
1116 *pstatus = NT_STATUS_OK;
1117 return reply_size;
1120 /**********************************************************************
1121 The following functions are called by the NETDFS RPC pipe functions
1122 **********************************************************************/
1124 /*********************************************************************
1125 Creates a junction structure from a DFS pathname
1126 **********************************************************************/
1128 bool create_junction(TALLOC_CTX *ctx,
1129 const char *dfs_path,
1130 bool allow_broken_path,
1131 struct junction_map *jucn)
1133 int snum;
1134 bool dummy;
1135 struct dfs_path *pdp = talloc(ctx,struct dfs_path);
1136 NTSTATUS status;
1138 if (!pdp) {
1139 return False;
1141 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1142 pdp, &dummy);
1143 if (!NT_STATUS_IS_OK(status)) {
1144 return False;
1147 /* check if path is dfs : validate first token */
1148 if (!is_myname_or_ipaddr(pdp->hostname)) {
1149 DEBUG(4,("create_junction: Invalid hostname %s "
1150 "in dfs path %s\n",
1151 pdp->hostname, dfs_path));
1152 TALLOC_FREE(pdp);
1153 return False;
1156 /* Check for a non-DFS share */
1157 snum = lp_servicenumber(pdp->servicename);
1159 if(snum < 0 || !lp_msdfs_root(snum)) {
1160 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1161 pdp->servicename));
1162 TALLOC_FREE(pdp);
1163 return False;
1166 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1167 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1168 jucn->comment = lp_comment(ctx, snum);
1170 TALLOC_FREE(pdp);
1171 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1172 return False;
1174 return True;
1177 /**********************************************************************
1178 Forms a valid Unix pathname from the junction
1179 **********************************************************************/
1181 static bool junction_to_local_path(const struct junction_map *jucn,
1182 char **pp_path_out,
1183 connection_struct **conn_out,
1184 char **oldpath)
1186 int snum;
1187 NTSTATUS status;
1189 snum = lp_servicenumber(jucn->service_name);
1190 if(snum < 0) {
1191 return False;
1193 status = create_conn_struct_cwd(talloc_tos(),
1194 server_event_context(),
1195 server_messaging_context(),
1196 conn_out,
1197 snum, lp_pathname(talloc_tos(), snum), NULL, oldpath);
1198 if (!NT_STATUS_IS_OK(status)) {
1199 return False;
1202 *pp_path_out = talloc_asprintf(*conn_out,
1203 "%s/%s",
1204 lp_pathname(talloc_tos(), snum),
1205 jucn->volume_name);
1206 if (!*pp_path_out) {
1207 vfs_ChDir(*conn_out, *oldpath);
1208 SMB_VFS_DISCONNECT(*conn_out);
1209 conn_free(*conn_out);
1210 return False;
1212 return True;
1215 bool create_msdfs_link(const struct junction_map *jucn)
1217 char *path = NULL;
1218 char *cwd;
1219 char *msdfs_link = NULL;
1220 connection_struct *conn;
1221 int i=0;
1222 bool insert_comma = False;
1223 bool ret = False;
1225 if(!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1226 return False;
1229 /* Form the msdfs_link contents */
1230 msdfs_link = talloc_strdup(conn, "msdfs:");
1231 if (!msdfs_link) {
1232 goto out;
1234 for(i=0; i<jucn->referral_count; i++) {
1235 char *refpath = jucn->referral_list[i].alternate_path;
1237 /* Alternate paths always use Windows separators. */
1238 trim_char(refpath, '\\', '\\');
1239 if(*refpath == '\0') {
1240 if (i == 0) {
1241 insert_comma = False;
1243 continue;
1245 if (i > 0 && insert_comma) {
1246 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1247 ",%s",
1248 refpath);
1249 } else {
1250 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1251 "%s",
1252 refpath);
1255 if (!msdfs_link) {
1256 goto out;
1258 if (!insert_comma) {
1259 insert_comma = True;
1263 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1264 path, msdfs_link));
1266 if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1267 if (errno == EEXIST) {
1268 struct smb_filename *smb_fname = NULL;
1269 NTSTATUS status;
1271 status = create_synthetic_smb_fname(talloc_tos(), path,
1272 NULL, NULL,
1273 &smb_fname);
1274 if (!NT_STATUS_IS_OK(status)) {
1275 errno = map_errno_from_nt_status(status);
1276 goto out;
1279 if(SMB_VFS_UNLINK(conn, smb_fname)!=0) {
1280 TALLOC_FREE(smb_fname);
1281 goto out;
1283 TALLOC_FREE(smb_fname);
1285 if (SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1286 DEBUG(1,("create_msdfs_link: symlink failed "
1287 "%s -> %s\nError: %s\n",
1288 path, msdfs_link, strerror(errno)));
1289 goto out;
1293 ret = True;
1295 out:
1296 vfs_ChDir(conn, cwd);
1297 SMB_VFS_DISCONNECT(conn);
1298 conn_free(conn);
1299 return ret;
1302 bool remove_msdfs_link(const struct junction_map *jucn)
1304 char *path = NULL;
1305 char *cwd;
1306 connection_struct *conn;
1307 bool ret = False;
1308 struct smb_filename *smb_fname = NULL;
1309 NTSTATUS status;
1311 if (!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1312 return false;
1315 status = create_synthetic_smb_fname(talloc_tos(), path,
1316 NULL, NULL,
1317 &smb_fname);
1318 if (!NT_STATUS_IS_OK(status)) {
1319 errno = map_errno_from_nt_status(status);
1320 return false;
1323 if( SMB_VFS_UNLINK(conn, smb_fname) == 0 ) {
1324 ret = True;
1327 TALLOC_FREE(smb_fname);
1328 vfs_ChDir(conn, cwd);
1329 SMB_VFS_DISCONNECT(conn);
1330 conn_free(conn);
1331 return ret;
1334 /*********************************************************************
1335 Return the number of DFS links at the root of this share.
1336 *********************************************************************/
1338 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1340 size_t cnt = 0;
1341 DIR *dirp = NULL;
1342 const char *dname = NULL;
1343 char *talloced = NULL;
1344 const char *connect_path = lp_pathname(talloc_tos(), snum);
1345 const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum);
1346 connection_struct *conn;
1347 NTSTATUS status;
1348 char *cwd;
1350 if(*connect_path == '\0') {
1351 return 0;
1355 * Fake up a connection struct for the VFS layer.
1358 status = create_conn_struct_cwd(talloc_tos(),
1359 server_event_context(),
1360 server_messaging_context(),
1361 &conn,
1362 snum, connect_path, NULL, &cwd);
1363 if (!NT_STATUS_IS_OK(status)) {
1364 DEBUG(3, ("create_conn_struct failed: %s\n",
1365 nt_errstr(status)));
1366 return 0;
1369 /* Count a link for the msdfs root - convention */
1370 cnt = 1;
1372 /* No more links if this is an msdfs proxy. */
1373 if (*msdfs_proxy != '\0') {
1374 goto out;
1377 /* Now enumerate all dfs links */
1378 dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1379 if(!dirp) {
1380 goto out;
1383 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1384 != NULL) {
1385 if (is_msdfs_link(conn,
1386 dname,
1387 NULL)) {
1388 cnt++;
1390 TALLOC_FREE(talloced);
1393 SMB_VFS_CLOSEDIR(conn,dirp);
1395 out:
1396 vfs_ChDir(conn, cwd);
1397 SMB_VFS_DISCONNECT(conn);
1398 conn_free(conn);
1399 return cnt;
1402 /*********************************************************************
1403 *********************************************************************/
1405 static int form_junctions(TALLOC_CTX *ctx,
1406 int snum,
1407 struct junction_map *jucn,
1408 size_t jn_remain)
1410 size_t cnt = 0;
1411 DIR *dirp = NULL;
1412 const char *dname = NULL;
1413 char *talloced = NULL;
1414 const char *connect_path = lp_pathname(talloc_tos(), snum);
1415 char *service_name = lp_servicename(talloc_tos(), snum);
1416 const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum);
1417 connection_struct *conn;
1418 struct referral *ref = NULL;
1419 char *cwd;
1420 NTSTATUS status;
1422 if (jn_remain == 0) {
1423 return 0;
1426 if(*connect_path == '\0') {
1427 return 0;
1431 * Fake up a connection struct for the VFS layer.
1434 status = create_conn_struct_cwd(ctx,
1435 server_event_context(),
1436 server_messaging_context(),
1437 &conn, snum, connect_path, NULL,
1438 &cwd);
1439 if (!NT_STATUS_IS_OK(status)) {
1440 DEBUG(3, ("create_conn_struct failed: %s\n",
1441 nt_errstr(status)));
1442 return 0;
1445 /* form a junction for the msdfs root - convention
1446 DO NOT REMOVE THIS: NT clients will not work with us
1447 if this is not present
1449 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1450 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1451 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1452 goto out;
1454 jucn[cnt].comment = "";
1455 jucn[cnt].referral_count = 1;
1457 ref = jucn[cnt].referral_list = talloc_zero(ctx, struct referral);
1458 if (jucn[cnt].referral_list == NULL) {
1459 goto out;
1462 ref->proximity = 0;
1463 ref->ttl = REFERRAL_TTL;
1464 if (*msdfs_proxy != '\0') {
1465 ref->alternate_path = talloc_strdup(ctx,
1466 msdfs_proxy);
1467 } else {
1468 ref->alternate_path = talloc_asprintf(ctx,
1469 "\\\\%s\\%s",
1470 get_local_machine_name(),
1471 service_name);
1474 if (!ref->alternate_path) {
1475 goto out;
1477 cnt++;
1479 /* Don't enumerate if we're an msdfs proxy. */
1480 if (*msdfs_proxy != '\0') {
1481 goto out;
1484 /* Now enumerate all dfs links */
1485 dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1486 if(!dirp) {
1487 goto out;
1490 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1491 != NULL) {
1492 char *link_target = NULL;
1493 if (cnt >= jn_remain) {
1494 DEBUG(2, ("form_junctions: ran out of MSDFS "
1495 "junction slots"));
1496 TALLOC_FREE(talloced);
1497 goto out;
1499 if (is_msdfs_link_internal(ctx,
1500 conn,
1501 dname, &link_target,
1502 NULL)) {
1503 if (parse_msdfs_symlink(ctx,
1504 link_target,
1505 &jucn[cnt].referral_list,
1506 &jucn[cnt].referral_count)) {
1508 jucn[cnt].service_name = talloc_strdup(ctx,
1509 service_name);
1510 jucn[cnt].volume_name = talloc_strdup(ctx,
1511 dname);
1512 if (!jucn[cnt].service_name ||
1513 !jucn[cnt].volume_name) {
1514 TALLOC_FREE(talloced);
1515 goto out;
1517 jucn[cnt].comment = "";
1518 cnt++;
1520 TALLOC_FREE(link_target);
1522 TALLOC_FREE(talloced);
1525 out:
1527 if (dirp) {
1528 SMB_VFS_CLOSEDIR(conn,dirp);
1531 vfs_ChDir(conn, cwd);
1532 conn_free(conn);
1533 return cnt;
1536 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1538 struct junction_map *jn = NULL;
1539 int i=0;
1540 size_t jn_count = 0;
1541 int sharecount = 0;
1543 *p_num_jn = 0;
1544 if(!lp_host_msdfs()) {
1545 return NULL;
1548 /* Ensure all the usershares are loaded. */
1549 become_root();
1550 load_registry_shares();
1551 sharecount = load_usershare_shares(NULL, connections_snum_used);
1552 unbecome_root();
1554 for(i=0;i < sharecount;i++) {
1555 if(lp_msdfs_root(i)) {
1556 jn_count += count_dfs_links(ctx, i);
1559 if (jn_count == 0) {
1560 return NULL;
1562 jn = talloc_array(ctx, struct junction_map, jn_count);
1563 if (!jn) {
1564 return NULL;
1566 for(i=0; i < sharecount; i++) {
1567 if (*p_num_jn >= jn_count) {
1568 break;
1570 if(lp_msdfs_root(i)) {
1571 *p_num_jn += form_junctions(ctx, i,
1572 &jn[*p_num_jn],
1573 jn_count - *p_num_jn);
1576 return jn;
1579 /******************************************************************************
1580 Core function to resolve a dfs pathname possibly containing a wildcard. If
1581 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1582 detected during dfs resolution.
1583 ******************************************************************************/
1585 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1586 connection_struct *conn,
1587 bool dfs_pathnames,
1588 const char *name_in,
1589 bool allow_wcards,
1590 bool allow_broken_path,
1591 char **pp_name_out,
1592 bool *ppath_contains_wcard)
1594 bool path_contains_wcard;
1595 NTSTATUS status = NT_STATUS_OK;
1597 if (dfs_pathnames) {
1598 status = dfs_redirect(ctx,
1599 conn,
1600 name_in,
1601 allow_wcards,
1602 allow_broken_path,
1603 pp_name_out,
1604 &path_contains_wcard);
1606 if (NT_STATUS_IS_OK(status) && ppath_contains_wcard != NULL) {
1607 *ppath_contains_wcard = path_contains_wcard;
1609 } else {
1611 * Cheat and just return a copy of the in ptr.
1612 * Once srvstr_get_path() uses talloc it'll
1613 * be a talloced ptr anyway.
1615 *pp_name_out = discard_const_p(char, name_in);
1617 return status;