smbd: Rework create_conn_struct to use conn_new()
[Samba/gebeck_regimport.git] / source3 / smbd / msdfs.c
blob8e80cbb764d140c8b00394c6801e48353d82dfdd
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;
237 struct smbd_server_connection *sconn;
239 sconn = talloc_zero(ctx, struct smbd_server_connection);
240 if (sconn == NULL) {
241 return NT_STATUS_NO_MEMORY;
244 sconn->ev_ctx = ev;
245 sconn->msg_ctx = msg;
246 sconn->sock = -1;
247 sconn->smb1.echo_handler.trusted_fd = -1;
248 sconn->smb1.echo_handler.socket_lock_fd = -1;
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 connpath = talloc_strdup(conn, path);
261 if (!connpath) {
262 TALLOC_FREE(conn);
263 return NT_STATUS_NO_MEMORY;
265 connpath = talloc_string_sub(conn,
266 connpath,
267 "%S",
268 lp_servicename(talloc_tos(), snum));
269 if (!connpath) {
270 TALLOC_FREE(conn);
271 return NT_STATUS_NO_MEMORY;
274 /* needed for smbd_vfs_init() */
276 conn->params->service = snum;
277 conn->cnum = TID_FIELD_INVALID;
279 if (session_info != NULL) {
280 conn->session_info = copy_session_info(conn, session_info);
281 if (conn->session_info == NULL) {
282 DEBUG(0, ("copy_serverinfo failed\n"));
283 TALLOC_FREE(conn);
284 return NT_STATUS_NO_MEMORY;
286 vfs_user = conn->session_info->unix_info->unix_name;
287 } else {
288 /* use current authenticated user in absence of session_info */
289 vfs_user = get_current_username();
292 set_conn_connectpath(conn, connpath);
295 * New code to check if there's a share security descripter
296 * added from NT server manager. This is done after the
297 * smb.conf checks are done as we need a uid and token. JRA.
300 if (conn->session_info) {
301 share_access_check(conn->session_info->security_token,
302 lp_servicename(talloc_tos(), snum),
303 MAXIMUM_ALLOWED_ACCESS,
304 &conn->share_access);
306 if ((conn->share_access & FILE_WRITE_DATA) == 0) {
307 if ((conn->share_access & FILE_READ_DATA) == 0) {
308 /* No access, read or write. */
309 DEBUG(0,("create_conn_struct: connection to %s "
310 "denied due to security "
311 "descriptor.\n",
312 lp_servicename(talloc_tos(), snum)));
313 conn_free(conn);
314 return NT_STATUS_ACCESS_DENIED;
315 } else {
316 conn->read_only = true;
319 } else {
320 conn->share_access = 0;
321 conn->read_only = true;
324 if (!smbd_vfs_init(conn)) {
325 NTSTATUS status = map_nt_error_from_unix(errno);
326 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
327 conn_free(conn);
328 return status;
331 /* this must be the first filesystem operation that we do */
332 if (SMB_VFS_CONNECT(conn, lp_servicename(talloc_tos(), snum), vfs_user) < 0) {
333 DEBUG(0,("VFS connect failed!\n"));
334 conn_free(conn);
335 return NT_STATUS_UNSUCCESSFUL;
338 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
339 *pconn = conn;
341 return NT_STATUS_OK;
344 /********************************************************
345 Fake up a connection struct for the VFS layer.
346 Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
348 The old working directory is returned on *poldcwd, allocated on ctx.
349 *********************************************************/
351 NTSTATUS create_conn_struct_cwd(TALLOC_CTX *ctx,
352 struct tevent_context *ev,
353 struct messaging_context *msg,
354 connection_struct **pconn,
355 int snum,
356 const char *path,
357 const struct auth_session_info *session_info,
358 char **poldcwd)
360 connection_struct *conn;
361 char *oldcwd;
363 NTSTATUS status = create_conn_struct(ctx, ev,
364 msg, &conn,
365 snum, path,
366 session_info);
367 if (!NT_STATUS_IS_OK(status)) {
368 return status;
372 * Windows seems to insist on doing trans2getdfsreferral() calls on
373 * the IPC$ share as the anonymous user. If we try to chdir as that
374 * user we will fail.... WTF ? JRA.
377 oldcwd = vfs_GetWd(ctx, conn);
378 if (oldcwd == NULL) {
379 status = map_nt_error_from_unix(errno);
380 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
381 conn_free(conn);
382 return status;
385 if (vfs_ChDir(conn,conn->connectpath) != 0) {
386 status = map_nt_error_from_unix(errno);
387 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
388 "Error was %s\n",
389 conn->connectpath, strerror(errno) ));
390 conn_free(conn);
391 return status;
394 *pconn = conn;
395 *poldcwd = oldcwd;
397 return NT_STATUS_OK;
400 /**********************************************************************
401 Parse the contents of a symlink to verify if it is an msdfs referral
402 A valid referral is of the form:
404 msdfs:server1\share1,server2\share2
405 msdfs:server1\share1\pathname,server2\share2\pathname
406 msdfs:server1/share1,server2/share2
407 msdfs:server1/share1/pathname,server2/share2/pathname.
409 Note that the alternate paths returned here must be of the canonicalized
410 form:
412 \server\share or
413 \server\share\path\to\file,
415 even in posix path mode. This is because we have no knowledge if the
416 server we're referring to understands posix paths.
417 **********************************************************************/
419 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
420 const char *target,
421 struct referral **preflist,
422 int *refcount)
424 char *temp = NULL;
425 char *prot;
426 char **alt_path = NULL;
427 int count = 0, i;
428 struct referral *reflist;
429 char *saveptr;
431 temp = talloc_strdup(ctx, target);
432 if (!temp) {
433 return False;
435 prot = strtok_r(temp, ":", &saveptr);
436 if (!prot) {
437 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
438 return False;
441 alt_path = talloc_array(ctx, char *, MAX_REFERRAL_COUNT);
442 if (!alt_path) {
443 return False;
446 /* parse out the alternate paths */
447 while((count<MAX_REFERRAL_COUNT) &&
448 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
449 count++;
452 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
454 if (count) {
455 reflist = *preflist = talloc_zero_array(ctx,
456 struct referral, count);
457 if(reflist == NULL) {
458 TALLOC_FREE(alt_path);
459 return False;
461 } else {
462 reflist = *preflist = NULL;
465 for(i=0;i<count;i++) {
466 char *p;
468 /* Canonicalize link target.
469 * Replace all /'s in the path by a \ */
470 string_replace(alt_path[i], '/', '\\');
472 /* Remove leading '\\'s */
473 p = alt_path[i];
474 while (*p && (*p == '\\')) {
475 p++;
478 reflist[i].alternate_path = talloc_asprintf(ctx,
479 "\\%s",
481 if (!reflist[i].alternate_path) {
482 return False;
485 reflist[i].proximity = 0;
486 reflist[i].ttl = REFERRAL_TTL;
487 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
488 reflist[i].alternate_path));
491 *refcount = count;
493 TALLOC_FREE(alt_path);
494 return True;
497 /**********************************************************************
498 Returns true if the unix path is a valid msdfs symlink and also
499 returns the target string from inside the link.
500 **********************************************************************/
502 static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
503 connection_struct *conn,
504 const char *path,
505 char **pp_link_target,
506 SMB_STRUCT_STAT *sbufp)
508 int referral_len = 0;
509 #if defined(HAVE_BROKEN_READLINK)
510 char link_target_buf[PATH_MAX];
511 #else
512 char link_target_buf[7];
513 #endif
514 size_t bufsize = 0;
515 char *link_target = NULL;
516 struct smb_filename smb_fname;
518 if (pp_link_target) {
519 bufsize = 1024;
520 link_target = talloc_array(ctx, char, bufsize);
521 if (!link_target) {
522 return False;
524 *pp_link_target = link_target;
525 } else {
526 bufsize = sizeof(link_target_buf);
527 link_target = link_target_buf;
530 ZERO_STRUCT(smb_fname);
531 smb_fname.base_name = discard_const_p(char, path);
533 if (SMB_VFS_LSTAT(conn, &smb_fname) != 0) {
534 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
535 path));
536 goto err;
538 if (!S_ISLNK(smb_fname.st.st_ex_mode)) {
539 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
540 path));
541 goto err;
543 if (sbufp != NULL) {
544 *sbufp = smb_fname.st;
547 referral_len = SMB_VFS_READLINK(conn, path, link_target, bufsize - 1);
548 if (referral_len == -1) {
549 DEBUG(0,("is_msdfs_link_read_target: Error reading "
550 "msdfs link %s: %s\n",
551 path, strerror(errno)));
552 goto err;
554 link_target[referral_len] = '\0';
556 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path,
557 link_target));
559 if (!strnequal(link_target, "msdfs:", 6)) {
560 goto err;
562 return True;
564 err:
566 if (link_target != link_target_buf) {
567 TALLOC_FREE(link_target);
569 return False;
572 /**********************************************************************
573 Returns true if the unix path is a valid msdfs symlink.
574 **********************************************************************/
576 bool is_msdfs_link(connection_struct *conn,
577 const char *path,
578 SMB_STRUCT_STAT *sbufp)
580 return is_msdfs_link_internal(talloc_tos(),
581 conn,
582 path,
583 NULL,
584 sbufp);
587 /*****************************************************************
588 Used by other functions to decide if a dfs path is remote,
589 and to get the list of referred locations for that remote path.
591 search_flag: For findfirsts, dfs links themselves are not
592 redirected, but paths beyond the links are. For normal smb calls,
593 even dfs links need to be redirected.
595 consumedcntp: how much of the dfs path is being redirected. the client
596 should try the remaining path on the redirected server.
598 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
599 link redirect are in targetpath.
600 *****************************************************************/
602 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
603 connection_struct *conn,
604 const char *dfspath, /* Incoming complete dfs path */
605 const struct dfs_path *pdp, /* Parsed out
606 server+share+extrapath. */
607 bool search_flag, /* Called from a findfirst ? */
608 int *consumedcntp,
609 char **pp_targetpath)
611 char *p = NULL;
612 char *q = NULL;
613 NTSTATUS status;
614 struct smb_filename *smb_fname = NULL;
615 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
616 components). */
618 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
619 conn->connectpath, pdp->reqpath));
622 * Note the unix path conversion here we're doing we
623 * throw away. We're looking for a symlink for a dfs
624 * resolution, if we don't find it we'll do another
625 * unix_convert later in the codepath.
628 status = unix_convert(ctx, conn, pdp->reqpath, &smb_fname,
629 search_flag ? UCF_ALWAYS_ALLOW_WCARD_LCOMP : 0);
631 if (!NT_STATUS_IS_OK(status)) {
632 if (!NT_STATUS_EQUAL(status,
633 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
634 return status;
636 if (smb_fname == NULL || smb_fname->base_name == NULL) {
637 return status;
641 /* Optimization - check if we can redirect the whole path. */
643 if (is_msdfs_link_internal(ctx, conn, smb_fname->base_name,
644 pp_targetpath, NULL)) {
645 if (search_flag) {
646 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
647 "for dfs link %s.\n", dfspath));
648 status = NT_STATUS_OK;
649 goto out;
652 DEBUG(6,("dfs_path_lookup: %s resolves to a "
653 "valid dfs link %s.\n", dfspath,
654 pp_targetpath ? *pp_targetpath : ""));
656 if (consumedcntp) {
657 *consumedcntp = strlen(dfspath);
659 status = NT_STATUS_PATH_NOT_COVERED;
660 goto out;
663 /* Prepare to test only for '/' components in the given path,
664 * so if a Windows path replace all '\\' characters with '/'.
665 * For a POSIX DFS path we know all separators are already '/'. */
667 canon_dfspath = talloc_strdup(ctx, dfspath);
668 if (!canon_dfspath) {
669 status = NT_STATUS_NO_MEMORY;
670 goto out;
672 if (!pdp->posix_path) {
673 string_replace(canon_dfspath, '\\', '/');
677 * localpath comes out of unix_convert, so it has
678 * no trailing backslash. Make sure that canon_dfspath hasn't either.
679 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
682 trim_char(canon_dfspath,0,'/');
685 * Redirect if any component in the path is a link.
686 * We do this by walking backwards through the
687 * local path, chopping off the last component
688 * in both the local path and the canonicalized
689 * DFS path. If we hit a DFS link then we're done.
692 p = strrchr_m(smb_fname->base_name, '/');
693 if (consumedcntp) {
694 q = strrchr_m(canon_dfspath, '/');
697 while (p) {
698 *p = '\0';
699 if (q) {
700 *q = '\0';
703 if (is_msdfs_link_internal(ctx, conn,
704 smb_fname->base_name, pp_targetpath,
705 NULL)) {
706 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
707 "parent %s is dfs link\n", dfspath,
708 smb_fname_str_dbg(smb_fname)));
710 if (consumedcntp) {
711 *consumedcntp = strlen(canon_dfspath);
712 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
713 "(%d)\n",
714 canon_dfspath,
715 *consumedcntp));
718 status = NT_STATUS_PATH_NOT_COVERED;
719 goto out;
722 /* Step back on the filesystem. */
723 p = strrchr_m(smb_fname->base_name, '/');
725 if (consumedcntp) {
726 /* And in the canonicalized dfs path. */
727 q = strrchr_m(canon_dfspath, '/');
731 status = NT_STATUS_OK;
732 out:
733 TALLOC_FREE(smb_fname);
734 return status;
737 /*****************************************************************
738 Decides if a dfs pathname should be redirected or not.
739 If not, the pathname is converted to a tcon-relative local unix path
741 search_wcard_flag: this flag performs 2 functions both related
742 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
743 for details.
745 This function can return NT_STATUS_OK, meaning use the returned path as-is
746 (mapped into a local path).
747 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
748 any other NT_STATUS error which is a genuine error to be
749 returned to the client.
750 *****************************************************************/
752 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
753 connection_struct *conn,
754 const char *path_in,
755 bool search_wcard_flag,
756 bool allow_broken_path,
757 char **pp_path_out,
758 bool *ppath_contains_wcard)
760 NTSTATUS status;
761 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
763 if (!pdp) {
764 return NT_STATUS_NO_MEMORY;
767 status = parse_dfs_path(conn, path_in, search_wcard_flag,
768 allow_broken_path, pdp,
769 ppath_contains_wcard);
770 if (!NT_STATUS_IS_OK(status)) {
771 TALLOC_FREE(pdp);
772 return status;
775 if (pdp->reqpath[0] == '\0') {
776 TALLOC_FREE(pdp);
777 *pp_path_out = talloc_strdup(ctx, "");
778 if (!*pp_path_out) {
779 return NT_STATUS_NO_MEMORY;
781 DEBUG(5,("dfs_redirect: self-referral.\n"));
782 return NT_STATUS_OK;
785 /* If dfs pathname for a non-dfs share, convert to tcon-relative
786 path and return OK */
788 if (!lp_msdfs_root(SNUM(conn))) {
789 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
790 TALLOC_FREE(pdp);
791 if (!*pp_path_out) {
792 return NT_STATUS_NO_MEMORY;
794 return NT_STATUS_OK;
797 /* If it looked like a local path (zero hostname/servicename)
798 * just treat as a tcon-relative path. */
800 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
801 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
802 TALLOC_FREE(pdp);
803 if (!*pp_path_out) {
804 return NT_STATUS_NO_MEMORY;
806 return NT_STATUS_OK;
809 if (!( strequal(pdp->servicename, lp_servicename(talloc_tos(), SNUM(conn)))
810 || (strequal(pdp->servicename, HOMES_NAME)
811 && strequal(lp_servicename(talloc_tos(), SNUM(conn)),
812 conn->session_info->unix_info->sanitized_username) )) ) {
814 /* The given sharename doesn't match this connection. */
815 TALLOC_FREE(pdp);
817 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
820 status = dfs_path_lookup(ctx, conn, path_in, pdp,
821 search_wcard_flag, NULL, NULL);
822 if (!NT_STATUS_IS_OK(status)) {
823 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
824 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
825 } else {
826 DEBUG(10,("dfs_redirect: dfs_path_lookup "
827 "failed for %s with %s\n",
828 path_in, nt_errstr(status) ));
830 return status;
833 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
835 /* Form non-dfs tcon-relative path */
836 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
837 TALLOC_FREE(pdp);
838 if (!*pp_path_out) {
839 return NT_STATUS_NO_MEMORY;
842 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
843 path_in,
844 *pp_path_out));
846 return NT_STATUS_OK;
849 /**********************************************************************
850 Return a self referral.
851 **********************************************************************/
853 static NTSTATUS self_ref(TALLOC_CTX *ctx,
854 const char *dfs_path,
855 struct junction_map *jucn,
856 int *consumedcntp,
857 bool *self_referralp)
859 struct referral *ref;
861 *self_referralp = True;
863 jucn->referral_count = 1;
864 if((ref = talloc_zero(ctx, struct referral)) == NULL) {
865 return NT_STATUS_NO_MEMORY;
868 ref->alternate_path = talloc_strdup(ctx, dfs_path);
869 if (!ref->alternate_path) {
870 TALLOC_FREE(ref);
871 return NT_STATUS_NO_MEMORY;
873 ref->proximity = 0;
874 ref->ttl = REFERRAL_TTL;
875 jucn->referral_list = ref;
876 *consumedcntp = strlen(dfs_path);
877 return NT_STATUS_OK;
880 /**********************************************************************
881 Gets valid referrals for a dfs path and fills up the
882 junction_map structure.
883 **********************************************************************/
885 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
886 const char *dfs_path,
887 bool allow_broken_path,
888 struct junction_map *jucn,
889 int *consumedcntp,
890 bool *self_referralp)
892 struct connection_struct *conn;
893 char *targetpath = NULL;
894 int snum;
895 NTSTATUS status = NT_STATUS_NOT_FOUND;
896 bool dummy;
897 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
898 char *oldpath;
900 if (!pdp) {
901 return NT_STATUS_NO_MEMORY;
904 *self_referralp = False;
906 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
907 pdp, &dummy);
908 if (!NT_STATUS_IS_OK(status)) {
909 return status;
912 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
913 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
914 if (!jucn->service_name || !jucn->volume_name) {
915 TALLOC_FREE(pdp);
916 return NT_STATUS_NO_MEMORY;
919 /* Verify the share is a dfs root */
920 snum = lp_servicenumber(jucn->service_name);
921 if(snum < 0) {
922 char *service_name = NULL;
923 if ((snum = find_service(ctx, jucn->service_name, &service_name)) < 0) {
924 return NT_STATUS_NOT_FOUND;
926 if (!service_name) {
927 return NT_STATUS_NO_MEMORY;
929 TALLOC_FREE(jucn->service_name);
930 jucn->service_name = talloc_strdup(ctx, service_name);
931 if (!jucn->service_name) {
932 TALLOC_FREE(pdp);
933 return NT_STATUS_NO_MEMORY;
937 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(talloc_tos(), snum) == '\0')) {
938 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
939 "a dfs root.\n",
940 pdp->servicename, dfs_path));
941 TALLOC_FREE(pdp);
942 return NT_STATUS_NOT_FOUND;
946 * Self referrals are tested with a anonymous IPC connection and
947 * a GET_DFS_REFERRAL call to \\server\share. (which means
948 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
949 * into the directory and will fail if it cannot (as the anonymous
950 * user). Cope with this.
953 if (pdp->reqpath[0] == '\0') {
954 char *tmp;
955 struct referral *ref;
957 if (*lp_msdfs_proxy(talloc_tos(), snum) == '\0') {
958 TALLOC_FREE(pdp);
959 return self_ref(ctx,
960 dfs_path,
961 jucn,
962 consumedcntp,
963 self_referralp);
967 * It's an msdfs proxy share. Redirect to
968 * the configured target share.
971 jucn->referral_count = 1;
972 if ((ref = talloc_zero(ctx, struct referral)) == NULL) {
973 TALLOC_FREE(pdp);
974 return NT_STATUS_NO_MEMORY;
977 if (!(tmp = talloc_strdup(ctx, lp_msdfs_proxy(talloc_tos(), snum)))) {
978 TALLOC_FREE(pdp);
979 return NT_STATUS_NO_MEMORY;
982 trim_string(tmp, "\\", 0);
984 ref->alternate_path = talloc_asprintf(ctx, "\\%s", tmp);
985 TALLOC_FREE(tmp);
987 if (!ref->alternate_path) {
988 TALLOC_FREE(pdp);
989 return NT_STATUS_NO_MEMORY;
992 if (pdp->reqpath[0] != '\0') {
993 ref->alternate_path = talloc_asprintf_append(
994 ref->alternate_path,
995 "%s",
996 pdp->reqpath);
997 if (!ref->alternate_path) {
998 TALLOC_FREE(pdp);
999 return NT_STATUS_NO_MEMORY;
1002 ref->proximity = 0;
1003 ref->ttl = REFERRAL_TTL;
1004 jucn->referral_list = ref;
1005 *consumedcntp = strlen(dfs_path);
1006 TALLOC_FREE(pdp);
1007 return NT_STATUS_OK;
1010 status = create_conn_struct_cwd(ctx,
1011 server_event_context(),
1012 server_messaging_context(),
1013 &conn, snum,
1014 lp_pathname(talloc_tos(), snum), NULL, &oldpath);
1015 if (!NT_STATUS_IS_OK(status)) {
1016 TALLOC_FREE(pdp);
1017 return status;
1020 /* If this is a DFS path dfs_lookup should return
1021 * NT_STATUS_PATH_NOT_COVERED. */
1023 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
1024 False, consumedcntp, &targetpath);
1026 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
1027 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
1028 dfs_path));
1029 goto err_exit;
1032 /* We know this is a valid dfs link. Parse the targetpath. */
1033 if (!parse_msdfs_symlink(ctx, targetpath,
1034 &jucn->referral_list,
1035 &jucn->referral_count)) {
1036 DEBUG(3,("get_referred_path: failed to parse symlink "
1037 "target %s\n", targetpath ));
1038 status = NT_STATUS_NOT_FOUND;
1039 goto err_exit;
1042 status = NT_STATUS_OK;
1043 err_exit:
1044 vfs_ChDir(conn, oldpath);
1045 SMB_VFS_DISCONNECT(conn);
1046 conn_free(conn);
1047 TALLOC_FREE(pdp);
1048 return status;
1051 /******************************************************************
1052 Set up the DFS referral for the dfs pathname. This call returns
1053 the amount of the path covered by this server, and where the
1054 client should be redirected to. This is the meat of the
1055 TRANS2_GET_DFS_REFERRAL call.
1056 ******************************************************************/
1058 int setup_dfs_referral(connection_struct *orig_conn,
1059 const char *dfs_path,
1060 int max_referral_level,
1061 char **ppdata, NTSTATUS *pstatus)
1063 char *pdata = *ppdata;
1064 int reply_size = 0;
1065 struct dfs_GetDFSReferral *r;
1066 DATA_BLOB blob = data_blob_null;
1067 NTSTATUS status;
1068 enum ndr_err_code ndr_err;
1070 r = talloc_zero(talloc_tos(), struct dfs_GetDFSReferral);
1071 if (r == NULL) {
1072 *pstatus = NT_STATUS_NO_MEMORY;
1073 return -1;
1076 r->in.req.max_referral_level = max_referral_level;
1077 r->in.req.servername = talloc_strdup(r, dfs_path);
1078 if (r->in.req.servername == NULL) {
1079 talloc_free(r);
1080 *pstatus = NT_STATUS_NO_MEMORY;
1081 return -1;
1084 status = SMB_VFS_GET_DFS_REFERRALS(orig_conn, r);
1085 if (!NT_STATUS_IS_OK(status)) {
1086 talloc_free(r);
1087 *pstatus = status;
1088 return -1;
1091 ndr_err = ndr_push_struct_blob(&blob, r,
1092 r->out.resp,
1093 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1094 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1095 TALLOC_FREE(r);
1096 *pstatus = NT_STATUS_INVALID_PARAMETER;
1097 return -1;
1100 pdata = (char *)SMB_REALLOC(pdata, blob.length);
1101 if(pdata == NULL) {
1102 TALLOC_FREE(r);
1103 DEBUG(0,("referral setup:"
1104 "malloc failed for Realloc!\n"));
1105 return -1;
1107 *ppdata = pdata;
1108 reply_size = blob.length;
1109 memcpy(pdata, blob.data, blob.length);
1110 TALLOC_FREE(r);
1112 *pstatus = NT_STATUS_OK;
1113 return reply_size;
1116 /**********************************************************************
1117 The following functions are called by the NETDFS RPC pipe functions
1118 **********************************************************************/
1120 /*********************************************************************
1121 Creates a junction structure from a DFS pathname
1122 **********************************************************************/
1124 bool create_junction(TALLOC_CTX *ctx,
1125 const char *dfs_path,
1126 bool allow_broken_path,
1127 struct junction_map *jucn)
1129 int snum;
1130 bool dummy;
1131 struct dfs_path *pdp = talloc(ctx,struct dfs_path);
1132 NTSTATUS status;
1134 if (!pdp) {
1135 return False;
1137 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1138 pdp, &dummy);
1139 if (!NT_STATUS_IS_OK(status)) {
1140 return False;
1143 /* check if path is dfs : validate first token */
1144 if (!is_myname_or_ipaddr(pdp->hostname)) {
1145 DEBUG(4,("create_junction: Invalid hostname %s "
1146 "in dfs path %s\n",
1147 pdp->hostname, dfs_path));
1148 TALLOC_FREE(pdp);
1149 return False;
1152 /* Check for a non-DFS share */
1153 snum = lp_servicenumber(pdp->servicename);
1155 if(snum < 0 || !lp_msdfs_root(snum)) {
1156 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1157 pdp->servicename));
1158 TALLOC_FREE(pdp);
1159 return False;
1162 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1163 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1164 jucn->comment = lp_comment(ctx, snum);
1166 TALLOC_FREE(pdp);
1167 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1168 return False;
1170 return True;
1173 /**********************************************************************
1174 Forms a valid Unix pathname from the junction
1175 **********************************************************************/
1177 static bool junction_to_local_path(const struct junction_map *jucn,
1178 char **pp_path_out,
1179 connection_struct **conn_out,
1180 char **oldpath)
1182 int snum;
1183 NTSTATUS status;
1185 snum = lp_servicenumber(jucn->service_name);
1186 if(snum < 0) {
1187 return False;
1189 status = create_conn_struct_cwd(talloc_tos(),
1190 server_event_context(),
1191 server_messaging_context(),
1192 conn_out,
1193 snum, lp_pathname(talloc_tos(), snum), NULL, oldpath);
1194 if (!NT_STATUS_IS_OK(status)) {
1195 return False;
1198 *pp_path_out = talloc_asprintf(*conn_out,
1199 "%s/%s",
1200 lp_pathname(talloc_tos(), snum),
1201 jucn->volume_name);
1202 if (!*pp_path_out) {
1203 vfs_ChDir(*conn_out, *oldpath);
1204 SMB_VFS_DISCONNECT(*conn_out);
1205 conn_free(*conn_out);
1206 return False;
1208 return True;
1211 bool create_msdfs_link(const struct junction_map *jucn)
1213 char *path = NULL;
1214 char *cwd;
1215 char *msdfs_link = NULL;
1216 connection_struct *conn;
1217 int i=0;
1218 bool insert_comma = False;
1219 bool ret = False;
1221 if(!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1222 return False;
1225 /* Form the msdfs_link contents */
1226 msdfs_link = talloc_strdup(conn, "msdfs:");
1227 if (!msdfs_link) {
1228 goto out;
1230 for(i=0; i<jucn->referral_count; i++) {
1231 char *refpath = jucn->referral_list[i].alternate_path;
1233 /* Alternate paths always use Windows separators. */
1234 trim_char(refpath, '\\', '\\');
1235 if(*refpath == '\0') {
1236 if (i == 0) {
1237 insert_comma = False;
1239 continue;
1241 if (i > 0 && insert_comma) {
1242 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1243 ",%s",
1244 refpath);
1245 } else {
1246 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1247 "%s",
1248 refpath);
1251 if (!msdfs_link) {
1252 goto out;
1254 if (!insert_comma) {
1255 insert_comma = True;
1259 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1260 path, msdfs_link));
1262 if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1263 if (errno == EEXIST) {
1264 struct smb_filename *smb_fname = NULL;
1265 NTSTATUS status;
1267 status = create_synthetic_smb_fname(talloc_tos(), path,
1268 NULL, NULL,
1269 &smb_fname);
1270 if (!NT_STATUS_IS_OK(status)) {
1271 errno = map_errno_from_nt_status(status);
1272 goto out;
1275 if(SMB_VFS_UNLINK(conn, smb_fname)!=0) {
1276 TALLOC_FREE(smb_fname);
1277 goto out;
1279 TALLOC_FREE(smb_fname);
1281 if (SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1282 DEBUG(1,("create_msdfs_link: symlink failed "
1283 "%s -> %s\nError: %s\n",
1284 path, msdfs_link, strerror(errno)));
1285 goto out;
1289 ret = True;
1291 out:
1292 vfs_ChDir(conn, cwd);
1293 SMB_VFS_DISCONNECT(conn);
1294 conn_free(conn);
1295 return ret;
1298 bool remove_msdfs_link(const struct junction_map *jucn)
1300 char *path = NULL;
1301 char *cwd;
1302 connection_struct *conn;
1303 bool ret = False;
1304 struct smb_filename *smb_fname = NULL;
1305 NTSTATUS status;
1307 if (!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1308 return false;
1311 status = create_synthetic_smb_fname(talloc_tos(), path,
1312 NULL, NULL,
1313 &smb_fname);
1314 if (!NT_STATUS_IS_OK(status)) {
1315 errno = map_errno_from_nt_status(status);
1316 return false;
1319 if( SMB_VFS_UNLINK(conn, smb_fname) == 0 ) {
1320 ret = True;
1323 TALLOC_FREE(smb_fname);
1324 vfs_ChDir(conn, cwd);
1325 SMB_VFS_DISCONNECT(conn);
1326 conn_free(conn);
1327 return ret;
1330 /*********************************************************************
1331 Return the number of DFS links at the root of this share.
1332 *********************************************************************/
1334 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1336 size_t cnt = 0;
1337 DIR *dirp = NULL;
1338 const char *dname = NULL;
1339 char *talloced = NULL;
1340 const char *connect_path = lp_pathname(talloc_tos(), snum);
1341 const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum);
1342 connection_struct *conn;
1343 NTSTATUS status;
1344 char *cwd;
1346 if(*connect_path == '\0') {
1347 return 0;
1351 * Fake up a connection struct for the VFS layer.
1354 status = create_conn_struct_cwd(talloc_tos(),
1355 server_event_context(),
1356 server_messaging_context(),
1357 &conn,
1358 snum, connect_path, NULL, &cwd);
1359 if (!NT_STATUS_IS_OK(status)) {
1360 DEBUG(3, ("create_conn_struct failed: %s\n",
1361 nt_errstr(status)));
1362 return 0;
1365 /* Count a link for the msdfs root - convention */
1366 cnt = 1;
1368 /* No more links if this is an msdfs proxy. */
1369 if (*msdfs_proxy != '\0') {
1370 goto out;
1373 /* Now enumerate all dfs links */
1374 dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1375 if(!dirp) {
1376 goto out;
1379 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1380 != NULL) {
1381 if (is_msdfs_link(conn,
1382 dname,
1383 NULL)) {
1384 cnt++;
1386 TALLOC_FREE(talloced);
1389 SMB_VFS_CLOSEDIR(conn,dirp);
1391 out:
1392 vfs_ChDir(conn, cwd);
1393 SMB_VFS_DISCONNECT(conn);
1394 conn_free(conn);
1395 return cnt;
1398 /*********************************************************************
1399 *********************************************************************/
1401 static int form_junctions(TALLOC_CTX *ctx,
1402 int snum,
1403 struct junction_map *jucn,
1404 size_t jn_remain)
1406 size_t cnt = 0;
1407 DIR *dirp = NULL;
1408 const char *dname = NULL;
1409 char *talloced = NULL;
1410 const char *connect_path = lp_pathname(talloc_tos(), snum);
1411 char *service_name = lp_servicename(talloc_tos(), snum);
1412 const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum);
1413 connection_struct *conn;
1414 struct referral *ref = NULL;
1415 char *cwd;
1416 NTSTATUS status;
1418 if (jn_remain == 0) {
1419 return 0;
1422 if(*connect_path == '\0') {
1423 return 0;
1427 * Fake up a connection struct for the VFS layer.
1430 status = create_conn_struct_cwd(ctx,
1431 server_event_context(),
1432 server_messaging_context(),
1433 &conn, snum, connect_path, NULL,
1434 &cwd);
1435 if (!NT_STATUS_IS_OK(status)) {
1436 DEBUG(3, ("create_conn_struct failed: %s\n",
1437 nt_errstr(status)));
1438 return 0;
1441 /* form a junction for the msdfs root - convention
1442 DO NOT REMOVE THIS: NT clients will not work with us
1443 if this is not present
1445 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1446 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1447 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1448 goto out;
1450 jucn[cnt].comment = "";
1451 jucn[cnt].referral_count = 1;
1453 ref = jucn[cnt].referral_list = talloc_zero(ctx, struct referral);
1454 if (jucn[cnt].referral_list == NULL) {
1455 goto out;
1458 ref->proximity = 0;
1459 ref->ttl = REFERRAL_TTL;
1460 if (*msdfs_proxy != '\0') {
1461 ref->alternate_path = talloc_strdup(ctx,
1462 msdfs_proxy);
1463 } else {
1464 ref->alternate_path = talloc_asprintf(ctx,
1465 "\\\\%s\\%s",
1466 get_local_machine_name(),
1467 service_name);
1470 if (!ref->alternate_path) {
1471 goto out;
1473 cnt++;
1475 /* Don't enumerate if we're an msdfs proxy. */
1476 if (*msdfs_proxy != '\0') {
1477 goto out;
1480 /* Now enumerate all dfs links */
1481 dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1482 if(!dirp) {
1483 goto out;
1486 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1487 != NULL) {
1488 char *link_target = NULL;
1489 if (cnt >= jn_remain) {
1490 DEBUG(2, ("form_junctions: ran out of MSDFS "
1491 "junction slots"));
1492 TALLOC_FREE(talloced);
1493 goto out;
1495 if (is_msdfs_link_internal(ctx,
1496 conn,
1497 dname, &link_target,
1498 NULL)) {
1499 if (parse_msdfs_symlink(ctx,
1500 link_target,
1501 &jucn[cnt].referral_list,
1502 &jucn[cnt].referral_count)) {
1504 jucn[cnt].service_name = talloc_strdup(ctx,
1505 service_name);
1506 jucn[cnt].volume_name = talloc_strdup(ctx,
1507 dname);
1508 if (!jucn[cnt].service_name ||
1509 !jucn[cnt].volume_name) {
1510 TALLOC_FREE(talloced);
1511 goto out;
1513 jucn[cnt].comment = "";
1514 cnt++;
1516 TALLOC_FREE(link_target);
1518 TALLOC_FREE(talloced);
1521 out:
1523 if (dirp) {
1524 SMB_VFS_CLOSEDIR(conn,dirp);
1527 vfs_ChDir(conn, cwd);
1528 conn_free(conn);
1529 return cnt;
1532 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1534 struct junction_map *jn = NULL;
1535 int i=0;
1536 size_t jn_count = 0;
1537 int sharecount = 0;
1539 *p_num_jn = 0;
1540 if(!lp_host_msdfs()) {
1541 return NULL;
1544 /* Ensure all the usershares are loaded. */
1545 become_root();
1546 load_registry_shares();
1547 sharecount = load_usershare_shares(NULL, connections_snum_used);
1548 unbecome_root();
1550 for(i=0;i < sharecount;i++) {
1551 if(lp_msdfs_root(i)) {
1552 jn_count += count_dfs_links(ctx, i);
1555 if (jn_count == 0) {
1556 return NULL;
1558 jn = talloc_array(ctx, struct junction_map, jn_count);
1559 if (!jn) {
1560 return NULL;
1562 for(i=0; i < sharecount; i++) {
1563 if (*p_num_jn >= jn_count) {
1564 break;
1566 if(lp_msdfs_root(i)) {
1567 *p_num_jn += form_junctions(ctx, i,
1568 &jn[*p_num_jn],
1569 jn_count - *p_num_jn);
1572 return jn;
1575 /******************************************************************************
1576 Core function to resolve a dfs pathname possibly containing a wildcard. If
1577 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1578 detected during dfs resolution.
1579 ******************************************************************************/
1581 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1582 connection_struct *conn,
1583 bool dfs_pathnames,
1584 const char *name_in,
1585 bool allow_wcards,
1586 bool allow_broken_path,
1587 char **pp_name_out,
1588 bool *ppath_contains_wcard)
1590 bool path_contains_wcard;
1591 NTSTATUS status = NT_STATUS_OK;
1593 if (dfs_pathnames) {
1594 status = dfs_redirect(ctx,
1595 conn,
1596 name_in,
1597 allow_wcards,
1598 allow_broken_path,
1599 pp_name_out,
1600 &path_contains_wcard);
1602 if (NT_STATUS_IS_OK(status) && ppath_contains_wcard != NULL) {
1603 *ppath_contains_wcard = path_contains_wcard;
1605 } else {
1607 * Cheat and just return a copy of the in ptr.
1608 * Once srvstr_get_path() uses talloc it'll
1609 * be a talloced ptr anyway.
1611 *pp_name_out = discard_const_p(char, name_in);
1613 return status;