s3:smbd: s/struct fd_event/struct tevent_fd
[Samba/gebeck_regimport.git] / source3 / smbd / msdfs.c
blob5388db9147f32c6b58360cd3d0cb331189dbddb3
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;
238 const char *servicename = lp_const_servicename(snum);
240 sconn = talloc_zero(ctx, struct smbd_server_connection);
241 if (sconn == NULL) {
242 return NT_STATUS_NO_MEMORY;
245 sconn->ev_ctx = ev;
246 sconn->msg_ctx = msg;
247 sconn->sock = -1;
248 sconn->smb1.echo_handler.trusted_fd = -1;
249 sconn->smb1.echo_handler.socket_lock_fd = -1;
251 conn = conn_new(sconn);
252 if (conn == NULL) {
253 TALLOC_FREE(sconn);
254 return NT_STATUS_NO_MEMORY;
257 /* Now we have conn, we need to make sconn a child of conn,
258 * for a proper talloc tree */
259 talloc_steal(conn, sconn);
261 if (snum == -1 && servicename == NULL) {
262 servicename = "Unknown Service (snum == -1)";
265 connpath = talloc_strdup(conn, path);
266 if (!connpath) {
267 TALLOC_FREE(conn);
268 return NT_STATUS_NO_MEMORY;
270 connpath = talloc_string_sub(conn,
271 connpath,
272 "%S",
273 servicename);
274 if (!connpath) {
275 TALLOC_FREE(conn);
276 return NT_STATUS_NO_MEMORY;
279 /* needed for smbd_vfs_init() */
281 conn->params->service = snum;
282 conn->cnum = TID_FIELD_INVALID;
284 if (session_info != NULL) {
285 conn->session_info = copy_session_info(conn, session_info);
286 if (conn->session_info == NULL) {
287 DEBUG(0, ("copy_serverinfo failed\n"));
288 TALLOC_FREE(conn);
289 return NT_STATUS_NO_MEMORY;
291 vfs_user = conn->session_info->unix_info->unix_name;
292 } else {
293 /* use current authenticated user in absence of session_info */
294 vfs_user = get_current_username();
297 set_conn_connectpath(conn, connpath);
300 * New code to check if there's a share security descripter
301 * added from NT server manager. This is done after the
302 * smb.conf checks are done as we need a uid and token. JRA.
305 if (conn->session_info) {
306 share_access_check(conn->session_info->security_token,
307 servicename,
308 MAXIMUM_ALLOWED_ACCESS,
309 &conn->share_access);
311 if ((conn->share_access & FILE_WRITE_DATA) == 0) {
312 if ((conn->share_access & FILE_READ_DATA) == 0) {
313 /* No access, read or write. */
314 DEBUG(0,("create_conn_struct: connection to %s "
315 "denied due to security "
316 "descriptor.\n",
317 servicename));
318 conn_free(conn);
319 return NT_STATUS_ACCESS_DENIED;
320 } else {
321 conn->read_only = true;
324 } else {
325 conn->share_access = 0;
326 conn->read_only = true;
329 if (!smbd_vfs_init(conn)) {
330 NTSTATUS status = map_nt_error_from_unix(errno);
331 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
332 conn_free(conn);
333 return status;
336 /* this must be the first filesystem operation that we do */
337 if (SMB_VFS_CONNECT(conn, servicename, vfs_user) < 0) {
338 DEBUG(0,("VFS connect failed!\n"));
339 conn_free(conn);
340 return NT_STATUS_UNSUCCESSFUL;
343 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
344 *pconn = conn;
346 return NT_STATUS_OK;
349 /********************************************************
350 Fake up a connection struct for the VFS layer.
351 Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
353 The old working directory is returned on *poldcwd, allocated on ctx.
354 *********************************************************/
356 NTSTATUS create_conn_struct_cwd(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,
363 char **poldcwd)
365 connection_struct *conn;
366 char *oldcwd;
368 NTSTATUS status = create_conn_struct(ctx, ev,
369 msg, &conn,
370 snum, path,
371 session_info);
372 if (!NT_STATUS_IS_OK(status)) {
373 return status;
377 * Windows seems to insist on doing trans2getdfsreferral() calls on
378 * the IPC$ share as the anonymous user. If we try to chdir as that
379 * user we will fail.... WTF ? JRA.
382 oldcwd = vfs_GetWd(ctx, conn);
383 if (oldcwd == NULL) {
384 status = map_nt_error_from_unix(errno);
385 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
386 conn_free(conn);
387 return status;
390 if (vfs_ChDir(conn,conn->connectpath) != 0) {
391 status = map_nt_error_from_unix(errno);
392 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
393 "Error was %s\n",
394 conn->connectpath, strerror(errno) ));
395 conn_free(conn);
396 return status;
399 *pconn = conn;
400 *poldcwd = oldcwd;
402 return NT_STATUS_OK;
405 /**********************************************************************
406 Parse the contents of a symlink to verify if it is an msdfs referral
407 A valid referral is of the form:
409 msdfs:server1\share1,server2\share2
410 msdfs:server1\share1\pathname,server2\share2\pathname
411 msdfs:server1/share1,server2/share2
412 msdfs:server1/share1/pathname,server2/share2/pathname.
414 Note that the alternate paths returned here must be of the canonicalized
415 form:
417 \server\share or
418 \server\share\path\to\file,
420 even in posix path mode. This is because we have no knowledge if the
421 server we're referring to understands posix paths.
422 **********************************************************************/
424 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
425 const char *target,
426 struct referral **preflist,
427 int *refcount)
429 char *temp = NULL;
430 char *prot;
431 char **alt_path = NULL;
432 int count = 0, i;
433 struct referral *reflist;
434 char *saveptr;
436 temp = talloc_strdup(ctx, target);
437 if (!temp) {
438 return False;
440 prot = strtok_r(temp, ":", &saveptr);
441 if (!prot) {
442 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
443 return False;
446 alt_path = talloc_array(ctx, char *, MAX_REFERRAL_COUNT);
447 if (!alt_path) {
448 return False;
451 /* parse out the alternate paths */
452 while((count<MAX_REFERRAL_COUNT) &&
453 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
454 count++;
457 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
459 if (count) {
460 reflist = *preflist = talloc_zero_array(ctx,
461 struct referral, count);
462 if(reflist == NULL) {
463 TALLOC_FREE(alt_path);
464 return False;
466 } else {
467 reflist = *preflist = NULL;
470 for(i=0;i<count;i++) {
471 char *p;
473 /* Canonicalize link target.
474 * Replace all /'s in the path by a \ */
475 string_replace(alt_path[i], '/', '\\');
477 /* Remove leading '\\'s */
478 p = alt_path[i];
479 while (*p && (*p == '\\')) {
480 p++;
483 reflist[i].alternate_path = talloc_asprintf(ctx,
484 "\\%s",
486 if (!reflist[i].alternate_path) {
487 return False;
490 reflist[i].proximity = 0;
491 reflist[i].ttl = REFERRAL_TTL;
492 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
493 reflist[i].alternate_path));
496 *refcount = count;
498 TALLOC_FREE(alt_path);
499 return True;
502 /**********************************************************************
503 Returns true if the unix path is a valid msdfs symlink and also
504 returns the target string from inside the link.
505 **********************************************************************/
507 static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
508 connection_struct *conn,
509 const char *path,
510 char **pp_link_target,
511 SMB_STRUCT_STAT *sbufp)
513 int referral_len = 0;
514 #if defined(HAVE_BROKEN_READLINK)
515 char link_target_buf[PATH_MAX];
516 #else
517 char link_target_buf[7];
518 #endif
519 size_t bufsize = 0;
520 char *link_target = NULL;
521 struct smb_filename smb_fname;
523 if (pp_link_target) {
524 bufsize = 1024;
525 link_target = talloc_array(ctx, char, bufsize);
526 if (!link_target) {
527 return False;
529 *pp_link_target = link_target;
530 } else {
531 bufsize = sizeof(link_target_buf);
532 link_target = link_target_buf;
535 ZERO_STRUCT(smb_fname);
536 smb_fname.base_name = discard_const_p(char, path);
538 if (SMB_VFS_LSTAT(conn, &smb_fname) != 0) {
539 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
540 path));
541 goto err;
543 if (!S_ISLNK(smb_fname.st.st_ex_mode)) {
544 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
545 path));
546 goto err;
548 if (sbufp != NULL) {
549 *sbufp = smb_fname.st;
552 referral_len = SMB_VFS_READLINK(conn, path, link_target, bufsize - 1);
553 if (referral_len == -1) {
554 DEBUG(0,("is_msdfs_link_read_target: Error reading "
555 "msdfs link %s: %s\n",
556 path, strerror(errno)));
557 goto err;
559 link_target[referral_len] = '\0';
561 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path,
562 link_target));
564 if (!strnequal(link_target, "msdfs:", 6)) {
565 goto err;
567 return True;
569 err:
571 if (link_target != link_target_buf) {
572 TALLOC_FREE(link_target);
574 return False;
577 /**********************************************************************
578 Returns true if the unix path is a valid msdfs symlink.
579 **********************************************************************/
581 bool is_msdfs_link(connection_struct *conn,
582 const char *path,
583 SMB_STRUCT_STAT *sbufp)
585 return is_msdfs_link_internal(talloc_tos(),
586 conn,
587 path,
588 NULL,
589 sbufp);
592 /*****************************************************************
593 Used by other functions to decide if a dfs path is remote,
594 and to get the list of referred locations for that remote path.
596 search_flag: For findfirsts, dfs links themselves are not
597 redirected, but paths beyond the links are. For normal smb calls,
598 even dfs links need to be redirected.
600 consumedcntp: how much of the dfs path is being redirected. the client
601 should try the remaining path on the redirected server.
603 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
604 link redirect are in targetpath.
605 *****************************************************************/
607 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
608 connection_struct *conn,
609 const char *dfspath, /* Incoming complete dfs path */
610 const struct dfs_path *pdp, /* Parsed out
611 server+share+extrapath. */
612 bool search_flag, /* Called from a findfirst ? */
613 int *consumedcntp,
614 char **pp_targetpath)
616 char *p = NULL;
617 char *q = NULL;
618 NTSTATUS status;
619 struct smb_filename *smb_fname = NULL;
620 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
621 components). */
623 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
624 conn->connectpath, pdp->reqpath));
627 * Note the unix path conversion here we're doing we
628 * throw away. We're looking for a symlink for a dfs
629 * resolution, if we don't find it we'll do another
630 * unix_convert later in the codepath.
633 status = unix_convert(ctx, conn, pdp->reqpath, &smb_fname,
634 search_flag ? UCF_ALWAYS_ALLOW_WCARD_LCOMP : 0);
636 if (!NT_STATUS_IS_OK(status)) {
637 if (!NT_STATUS_EQUAL(status,
638 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
639 return status;
641 if (smb_fname == NULL || smb_fname->base_name == NULL) {
642 return status;
646 /* Optimization - check if we can redirect the whole path. */
648 if (is_msdfs_link_internal(ctx, conn, smb_fname->base_name,
649 pp_targetpath, NULL)) {
650 if (search_flag) {
651 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
652 "for dfs link %s.\n", dfspath));
653 status = NT_STATUS_OK;
654 goto out;
657 DEBUG(6,("dfs_path_lookup: %s resolves to a "
658 "valid dfs link %s.\n", dfspath,
659 pp_targetpath ? *pp_targetpath : ""));
661 if (consumedcntp) {
662 *consumedcntp = strlen(dfspath);
664 status = NT_STATUS_PATH_NOT_COVERED;
665 goto out;
668 /* Prepare to test only for '/' components in the given path,
669 * so if a Windows path replace all '\\' characters with '/'.
670 * For a POSIX DFS path we know all separators are already '/'. */
672 canon_dfspath = talloc_strdup(ctx, dfspath);
673 if (!canon_dfspath) {
674 status = NT_STATUS_NO_MEMORY;
675 goto out;
677 if (!pdp->posix_path) {
678 string_replace(canon_dfspath, '\\', '/');
682 * localpath comes out of unix_convert, so it has
683 * no trailing backslash. Make sure that canon_dfspath hasn't either.
684 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
687 trim_char(canon_dfspath,0,'/');
690 * Redirect if any component in the path is a link.
691 * We do this by walking backwards through the
692 * local path, chopping off the last component
693 * in both the local path and the canonicalized
694 * DFS path. If we hit a DFS link then we're done.
697 p = strrchr_m(smb_fname->base_name, '/');
698 if (consumedcntp) {
699 q = strrchr_m(canon_dfspath, '/');
702 while (p) {
703 *p = '\0';
704 if (q) {
705 *q = '\0';
708 if (is_msdfs_link_internal(ctx, conn,
709 smb_fname->base_name, pp_targetpath,
710 NULL)) {
711 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
712 "parent %s is dfs link\n", dfspath,
713 smb_fname_str_dbg(smb_fname)));
715 if (consumedcntp) {
716 *consumedcntp = strlen(canon_dfspath);
717 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
718 "(%d)\n",
719 canon_dfspath,
720 *consumedcntp));
723 status = NT_STATUS_PATH_NOT_COVERED;
724 goto out;
727 /* Step back on the filesystem. */
728 p = strrchr_m(smb_fname->base_name, '/');
730 if (consumedcntp) {
731 /* And in the canonicalized dfs path. */
732 q = strrchr_m(canon_dfspath, '/');
736 status = NT_STATUS_OK;
737 out:
738 TALLOC_FREE(smb_fname);
739 return status;
742 /*****************************************************************
743 Decides if a dfs pathname should be redirected or not.
744 If not, the pathname is converted to a tcon-relative local unix path
746 search_wcard_flag: this flag performs 2 functions both related
747 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
748 for details.
750 This function can return NT_STATUS_OK, meaning use the returned path as-is
751 (mapped into a local path).
752 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
753 any other NT_STATUS error which is a genuine error to be
754 returned to the client.
755 *****************************************************************/
757 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
758 connection_struct *conn,
759 const char *path_in,
760 bool search_wcard_flag,
761 bool allow_broken_path,
762 char **pp_path_out,
763 bool *ppath_contains_wcard)
765 NTSTATUS status;
766 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
768 if (!pdp) {
769 return NT_STATUS_NO_MEMORY;
772 status = parse_dfs_path(conn, path_in, search_wcard_flag,
773 allow_broken_path, pdp,
774 ppath_contains_wcard);
775 if (!NT_STATUS_IS_OK(status)) {
776 TALLOC_FREE(pdp);
777 return status;
780 if (pdp->reqpath[0] == '\0') {
781 TALLOC_FREE(pdp);
782 *pp_path_out = talloc_strdup(ctx, "");
783 if (!*pp_path_out) {
784 return NT_STATUS_NO_MEMORY;
786 DEBUG(5,("dfs_redirect: self-referral.\n"));
787 return NT_STATUS_OK;
790 /* If dfs pathname for a non-dfs share, convert to tcon-relative
791 path and return OK */
793 if (!lp_msdfs_root(SNUM(conn))) {
794 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
795 TALLOC_FREE(pdp);
796 if (!*pp_path_out) {
797 return NT_STATUS_NO_MEMORY;
799 return NT_STATUS_OK;
802 /* If it looked like a local path (zero hostname/servicename)
803 * just treat as a tcon-relative path. */
805 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
806 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
807 TALLOC_FREE(pdp);
808 if (!*pp_path_out) {
809 return NT_STATUS_NO_MEMORY;
811 return NT_STATUS_OK;
814 if (!( strequal(pdp->servicename, lp_servicename(talloc_tos(), SNUM(conn)))
815 || (strequal(pdp->servicename, HOMES_NAME)
816 && strequal(lp_servicename(talloc_tos(), SNUM(conn)),
817 conn->session_info->unix_info->sanitized_username) )) ) {
819 /* The given sharename doesn't match this connection. */
820 TALLOC_FREE(pdp);
822 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
825 status = dfs_path_lookup(ctx, conn, path_in, pdp,
826 search_wcard_flag, NULL, NULL);
827 if (!NT_STATUS_IS_OK(status)) {
828 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
829 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
830 } else {
831 DEBUG(10,("dfs_redirect: dfs_path_lookup "
832 "failed for %s with %s\n",
833 path_in, nt_errstr(status) ));
835 return status;
838 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
840 /* Form non-dfs tcon-relative path */
841 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
842 TALLOC_FREE(pdp);
843 if (!*pp_path_out) {
844 return NT_STATUS_NO_MEMORY;
847 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
848 path_in,
849 *pp_path_out));
851 return NT_STATUS_OK;
854 /**********************************************************************
855 Return a self referral.
856 **********************************************************************/
858 static NTSTATUS self_ref(TALLOC_CTX *ctx,
859 const char *dfs_path,
860 struct junction_map *jucn,
861 int *consumedcntp,
862 bool *self_referralp)
864 struct referral *ref;
866 *self_referralp = True;
868 jucn->referral_count = 1;
869 if((ref = talloc_zero(ctx, struct referral)) == NULL) {
870 return NT_STATUS_NO_MEMORY;
873 ref->alternate_path = talloc_strdup(ctx, dfs_path);
874 if (!ref->alternate_path) {
875 TALLOC_FREE(ref);
876 return NT_STATUS_NO_MEMORY;
878 ref->proximity = 0;
879 ref->ttl = REFERRAL_TTL;
880 jucn->referral_list = ref;
881 *consumedcntp = strlen(dfs_path);
882 return NT_STATUS_OK;
885 /**********************************************************************
886 Gets valid referrals for a dfs path and fills up the
887 junction_map structure.
888 **********************************************************************/
890 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
891 const char *dfs_path,
892 bool allow_broken_path,
893 struct junction_map *jucn,
894 int *consumedcntp,
895 bool *self_referralp)
897 struct connection_struct *conn;
898 char *targetpath = NULL;
899 int snum;
900 NTSTATUS status = NT_STATUS_NOT_FOUND;
901 bool dummy;
902 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
903 char *oldpath;
905 if (!pdp) {
906 return NT_STATUS_NO_MEMORY;
909 *self_referralp = False;
911 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
912 pdp, &dummy);
913 if (!NT_STATUS_IS_OK(status)) {
914 return status;
917 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
918 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
919 if (!jucn->service_name || !jucn->volume_name) {
920 TALLOC_FREE(pdp);
921 return NT_STATUS_NO_MEMORY;
924 /* Verify the share is a dfs root */
925 snum = lp_servicenumber(jucn->service_name);
926 if(snum < 0) {
927 char *service_name = NULL;
928 if ((snum = find_service(ctx, jucn->service_name, &service_name)) < 0) {
929 return NT_STATUS_NOT_FOUND;
931 if (!service_name) {
932 return NT_STATUS_NO_MEMORY;
934 TALLOC_FREE(jucn->service_name);
935 jucn->service_name = talloc_strdup(ctx, service_name);
936 if (!jucn->service_name) {
937 TALLOC_FREE(pdp);
938 return NT_STATUS_NO_MEMORY;
942 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(talloc_tos(), snum) == '\0')) {
943 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
944 "a dfs root.\n",
945 pdp->servicename, dfs_path));
946 TALLOC_FREE(pdp);
947 return NT_STATUS_NOT_FOUND;
951 * Self referrals are tested with a anonymous IPC connection and
952 * a GET_DFS_REFERRAL call to \\server\share. (which means
953 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
954 * into the directory and will fail if it cannot (as the anonymous
955 * user). Cope with this.
958 if (pdp->reqpath[0] == '\0') {
959 char *tmp;
960 struct referral *ref;
962 if (*lp_msdfs_proxy(talloc_tos(), snum) == '\0') {
963 TALLOC_FREE(pdp);
964 return self_ref(ctx,
965 dfs_path,
966 jucn,
967 consumedcntp,
968 self_referralp);
972 * It's an msdfs proxy share. Redirect to
973 * the configured target share.
976 jucn->referral_count = 1;
977 if ((ref = talloc_zero(ctx, struct referral)) == NULL) {
978 TALLOC_FREE(pdp);
979 return NT_STATUS_NO_MEMORY;
982 if (!(tmp = talloc_strdup(ctx, lp_msdfs_proxy(talloc_tos(), snum)))) {
983 TALLOC_FREE(pdp);
984 return NT_STATUS_NO_MEMORY;
987 trim_string(tmp, "\\", 0);
989 ref->alternate_path = talloc_asprintf(ctx, "\\%s", tmp);
990 TALLOC_FREE(tmp);
992 if (!ref->alternate_path) {
993 TALLOC_FREE(pdp);
994 return NT_STATUS_NO_MEMORY;
997 if (pdp->reqpath[0] != '\0') {
998 ref->alternate_path = talloc_asprintf_append(
999 ref->alternate_path,
1000 "%s",
1001 pdp->reqpath);
1002 if (!ref->alternate_path) {
1003 TALLOC_FREE(pdp);
1004 return NT_STATUS_NO_MEMORY;
1007 ref->proximity = 0;
1008 ref->ttl = REFERRAL_TTL;
1009 jucn->referral_list = ref;
1010 *consumedcntp = strlen(dfs_path);
1011 TALLOC_FREE(pdp);
1012 return NT_STATUS_OK;
1015 status = create_conn_struct_cwd(ctx,
1016 server_event_context(),
1017 server_messaging_context(),
1018 &conn, snum,
1019 lp_pathname(talloc_tos(), snum), NULL, &oldpath);
1020 if (!NT_STATUS_IS_OK(status)) {
1021 TALLOC_FREE(pdp);
1022 return status;
1025 /* If this is a DFS path dfs_lookup should return
1026 * NT_STATUS_PATH_NOT_COVERED. */
1028 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
1029 False, consumedcntp, &targetpath);
1031 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
1032 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
1033 dfs_path));
1034 if (NT_STATUS_IS_OK(status)) {
1036 * We are in an error path here (we
1037 * know it's not a DFS path), but
1038 * dfs_path_lookup() can return
1039 * NT_STATUS_OK. Ensure we always
1040 * return a valid error code.
1042 * #9588 - ACLs are not inherited to directories
1043 * for DFS shares.
1045 status = NT_STATUS_NOT_FOUND;
1047 goto err_exit;
1050 /* We know this is a valid dfs link. Parse the targetpath. */
1051 if (!parse_msdfs_symlink(ctx, targetpath,
1052 &jucn->referral_list,
1053 &jucn->referral_count)) {
1054 DEBUG(3,("get_referred_path: failed to parse symlink "
1055 "target %s\n", targetpath ));
1056 status = NT_STATUS_NOT_FOUND;
1057 goto err_exit;
1060 status = NT_STATUS_OK;
1061 err_exit:
1062 vfs_ChDir(conn, oldpath);
1063 SMB_VFS_DISCONNECT(conn);
1064 conn_free(conn);
1065 TALLOC_FREE(pdp);
1066 return status;
1069 /******************************************************************
1070 Set up the DFS referral for the dfs pathname. This call returns
1071 the amount of the path covered by this server, and where the
1072 client should be redirected to. This is the meat of the
1073 TRANS2_GET_DFS_REFERRAL call.
1074 ******************************************************************/
1076 int setup_dfs_referral(connection_struct *orig_conn,
1077 const char *dfs_path,
1078 int max_referral_level,
1079 char **ppdata, NTSTATUS *pstatus)
1081 char *pdata = *ppdata;
1082 int reply_size = 0;
1083 struct dfs_GetDFSReferral *r;
1084 DATA_BLOB blob = data_blob_null;
1085 NTSTATUS status;
1086 enum ndr_err_code ndr_err;
1088 r = talloc_zero(talloc_tos(), struct dfs_GetDFSReferral);
1089 if (r == NULL) {
1090 *pstatus = NT_STATUS_NO_MEMORY;
1091 return -1;
1094 r->in.req.max_referral_level = max_referral_level;
1095 r->in.req.servername = talloc_strdup(r, dfs_path);
1096 if (r->in.req.servername == NULL) {
1097 talloc_free(r);
1098 *pstatus = NT_STATUS_NO_MEMORY;
1099 return -1;
1102 status = SMB_VFS_GET_DFS_REFERRALS(orig_conn, r);
1103 if (!NT_STATUS_IS_OK(status)) {
1104 talloc_free(r);
1105 *pstatus = status;
1106 return -1;
1109 ndr_err = ndr_push_struct_blob(&blob, r,
1110 r->out.resp,
1111 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1112 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1113 TALLOC_FREE(r);
1114 *pstatus = NT_STATUS_INVALID_PARAMETER;
1115 return -1;
1118 pdata = (char *)SMB_REALLOC(pdata, blob.length);
1119 if(pdata == NULL) {
1120 TALLOC_FREE(r);
1121 DEBUG(0,("referral setup:"
1122 "malloc failed for Realloc!\n"));
1123 return -1;
1125 *ppdata = pdata;
1126 reply_size = blob.length;
1127 memcpy(pdata, blob.data, blob.length);
1128 TALLOC_FREE(r);
1130 *pstatus = NT_STATUS_OK;
1131 return reply_size;
1134 /**********************************************************************
1135 The following functions are called by the NETDFS RPC pipe functions
1136 **********************************************************************/
1138 /*********************************************************************
1139 Creates a junction structure from a DFS pathname
1140 **********************************************************************/
1142 bool create_junction(TALLOC_CTX *ctx,
1143 const char *dfs_path,
1144 bool allow_broken_path,
1145 struct junction_map *jucn)
1147 int snum;
1148 bool dummy;
1149 struct dfs_path *pdp = talloc(ctx,struct dfs_path);
1150 NTSTATUS status;
1152 if (!pdp) {
1153 return False;
1155 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1156 pdp, &dummy);
1157 if (!NT_STATUS_IS_OK(status)) {
1158 return False;
1161 /* check if path is dfs : validate first token */
1162 if (!is_myname_or_ipaddr(pdp->hostname)) {
1163 DEBUG(4,("create_junction: Invalid hostname %s "
1164 "in dfs path %s\n",
1165 pdp->hostname, dfs_path));
1166 TALLOC_FREE(pdp);
1167 return False;
1170 /* Check for a non-DFS share */
1171 snum = lp_servicenumber(pdp->servicename);
1173 if(snum < 0 || !lp_msdfs_root(snum)) {
1174 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1175 pdp->servicename));
1176 TALLOC_FREE(pdp);
1177 return False;
1180 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1181 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1182 jucn->comment = lp_comment(ctx, snum);
1184 TALLOC_FREE(pdp);
1185 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1186 return False;
1188 return True;
1191 /**********************************************************************
1192 Forms a valid Unix pathname from the junction
1193 **********************************************************************/
1195 static bool junction_to_local_path(const struct junction_map *jucn,
1196 char **pp_path_out,
1197 connection_struct **conn_out,
1198 char **oldpath)
1200 int snum;
1201 NTSTATUS status;
1203 snum = lp_servicenumber(jucn->service_name);
1204 if(snum < 0) {
1205 return False;
1207 status = create_conn_struct_cwd(talloc_tos(),
1208 server_event_context(),
1209 server_messaging_context(),
1210 conn_out,
1211 snum, lp_pathname(talloc_tos(), snum), NULL, oldpath);
1212 if (!NT_STATUS_IS_OK(status)) {
1213 return False;
1216 *pp_path_out = talloc_asprintf(*conn_out,
1217 "%s/%s",
1218 lp_pathname(talloc_tos(), snum),
1219 jucn->volume_name);
1220 if (!*pp_path_out) {
1221 vfs_ChDir(*conn_out, *oldpath);
1222 SMB_VFS_DISCONNECT(*conn_out);
1223 conn_free(*conn_out);
1224 return False;
1226 return True;
1229 bool create_msdfs_link(const struct junction_map *jucn)
1231 char *path = NULL;
1232 char *cwd;
1233 char *msdfs_link = NULL;
1234 connection_struct *conn;
1235 int i=0;
1236 bool insert_comma = False;
1237 bool ret = False;
1239 if(!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1240 return False;
1243 /* Form the msdfs_link contents */
1244 msdfs_link = talloc_strdup(conn, "msdfs:");
1245 if (!msdfs_link) {
1246 goto out;
1248 for(i=0; i<jucn->referral_count; i++) {
1249 char *refpath = jucn->referral_list[i].alternate_path;
1251 /* Alternate paths always use Windows separators. */
1252 trim_char(refpath, '\\', '\\');
1253 if(*refpath == '\0') {
1254 if (i == 0) {
1255 insert_comma = False;
1257 continue;
1259 if (i > 0 && insert_comma) {
1260 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1261 ",%s",
1262 refpath);
1263 } else {
1264 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1265 "%s",
1266 refpath);
1269 if (!msdfs_link) {
1270 goto out;
1272 if (!insert_comma) {
1273 insert_comma = True;
1277 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1278 path, msdfs_link));
1280 if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1281 if (errno == EEXIST) {
1282 struct smb_filename *smb_fname = NULL;
1283 NTSTATUS status;
1285 status = create_synthetic_smb_fname(talloc_tos(), path,
1286 NULL, NULL,
1287 &smb_fname);
1288 if (!NT_STATUS_IS_OK(status)) {
1289 errno = map_errno_from_nt_status(status);
1290 goto out;
1293 if(SMB_VFS_UNLINK(conn, smb_fname)!=0) {
1294 TALLOC_FREE(smb_fname);
1295 goto out;
1297 TALLOC_FREE(smb_fname);
1299 if (SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1300 DEBUG(1,("create_msdfs_link: symlink failed "
1301 "%s -> %s\nError: %s\n",
1302 path, msdfs_link, strerror(errno)));
1303 goto out;
1307 ret = True;
1309 out:
1310 vfs_ChDir(conn, cwd);
1311 SMB_VFS_DISCONNECT(conn);
1312 conn_free(conn);
1313 return ret;
1316 bool remove_msdfs_link(const struct junction_map *jucn)
1318 char *path = NULL;
1319 char *cwd;
1320 connection_struct *conn;
1321 bool ret = False;
1322 struct smb_filename *smb_fname = NULL;
1323 NTSTATUS status;
1325 if (!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1326 return false;
1329 status = create_synthetic_smb_fname(talloc_tos(), path,
1330 NULL, NULL,
1331 &smb_fname);
1332 if (!NT_STATUS_IS_OK(status)) {
1333 errno = map_errno_from_nt_status(status);
1334 return false;
1337 if( SMB_VFS_UNLINK(conn, smb_fname) == 0 ) {
1338 ret = True;
1341 TALLOC_FREE(smb_fname);
1342 vfs_ChDir(conn, cwd);
1343 SMB_VFS_DISCONNECT(conn);
1344 conn_free(conn);
1345 return ret;
1348 /*********************************************************************
1349 Return the number of DFS links at the root of this share.
1350 *********************************************************************/
1352 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1354 size_t cnt = 0;
1355 DIR *dirp = NULL;
1356 const char *dname = NULL;
1357 char *talloced = NULL;
1358 const char *connect_path = lp_pathname(talloc_tos(), snum);
1359 const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum);
1360 connection_struct *conn;
1361 NTSTATUS status;
1362 char *cwd;
1364 if(*connect_path == '\0') {
1365 return 0;
1369 * Fake up a connection struct for the VFS layer.
1372 status = create_conn_struct_cwd(talloc_tos(),
1373 server_event_context(),
1374 server_messaging_context(),
1375 &conn,
1376 snum, connect_path, NULL, &cwd);
1377 if (!NT_STATUS_IS_OK(status)) {
1378 DEBUG(3, ("create_conn_struct failed: %s\n",
1379 nt_errstr(status)));
1380 return 0;
1383 /* Count a link for the msdfs root - convention */
1384 cnt = 1;
1386 /* No more links if this is an msdfs proxy. */
1387 if (*msdfs_proxy != '\0') {
1388 goto out;
1391 /* Now enumerate all dfs links */
1392 dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1393 if(!dirp) {
1394 goto out;
1397 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1398 != NULL) {
1399 if (is_msdfs_link(conn,
1400 dname,
1401 NULL)) {
1402 cnt++;
1404 TALLOC_FREE(talloced);
1407 SMB_VFS_CLOSEDIR(conn,dirp);
1409 out:
1410 vfs_ChDir(conn, cwd);
1411 SMB_VFS_DISCONNECT(conn);
1412 conn_free(conn);
1413 return cnt;
1416 /*********************************************************************
1417 *********************************************************************/
1419 static int form_junctions(TALLOC_CTX *ctx,
1420 int snum,
1421 struct junction_map *jucn,
1422 size_t jn_remain)
1424 size_t cnt = 0;
1425 DIR *dirp = NULL;
1426 const char *dname = NULL;
1427 char *talloced = NULL;
1428 const char *connect_path = lp_pathname(talloc_tos(), snum);
1429 char *service_name = lp_servicename(talloc_tos(), snum);
1430 const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum);
1431 connection_struct *conn;
1432 struct referral *ref = NULL;
1433 char *cwd;
1434 NTSTATUS status;
1436 if (jn_remain == 0) {
1437 return 0;
1440 if(*connect_path == '\0') {
1441 return 0;
1445 * Fake up a connection struct for the VFS layer.
1448 status = create_conn_struct_cwd(ctx,
1449 server_event_context(),
1450 server_messaging_context(),
1451 &conn, snum, connect_path, NULL,
1452 &cwd);
1453 if (!NT_STATUS_IS_OK(status)) {
1454 DEBUG(3, ("create_conn_struct failed: %s\n",
1455 nt_errstr(status)));
1456 return 0;
1459 /* form a junction for the msdfs root - convention
1460 DO NOT REMOVE THIS: NT clients will not work with us
1461 if this is not present
1463 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1464 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1465 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1466 goto out;
1468 jucn[cnt].comment = "";
1469 jucn[cnt].referral_count = 1;
1471 ref = jucn[cnt].referral_list = talloc_zero(ctx, struct referral);
1472 if (jucn[cnt].referral_list == NULL) {
1473 goto out;
1476 ref->proximity = 0;
1477 ref->ttl = REFERRAL_TTL;
1478 if (*msdfs_proxy != '\0') {
1479 ref->alternate_path = talloc_strdup(ctx,
1480 msdfs_proxy);
1481 } else {
1482 ref->alternate_path = talloc_asprintf(ctx,
1483 "\\\\%s\\%s",
1484 get_local_machine_name(),
1485 service_name);
1488 if (!ref->alternate_path) {
1489 goto out;
1491 cnt++;
1493 /* Don't enumerate if we're an msdfs proxy. */
1494 if (*msdfs_proxy != '\0') {
1495 goto out;
1498 /* Now enumerate all dfs links */
1499 dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1500 if(!dirp) {
1501 goto out;
1504 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1505 != NULL) {
1506 char *link_target = NULL;
1507 if (cnt >= jn_remain) {
1508 DEBUG(2, ("form_junctions: ran out of MSDFS "
1509 "junction slots"));
1510 TALLOC_FREE(talloced);
1511 goto out;
1513 if (is_msdfs_link_internal(ctx,
1514 conn,
1515 dname, &link_target,
1516 NULL)) {
1517 if (parse_msdfs_symlink(ctx,
1518 link_target,
1519 &jucn[cnt].referral_list,
1520 &jucn[cnt].referral_count)) {
1522 jucn[cnt].service_name = talloc_strdup(ctx,
1523 service_name);
1524 jucn[cnt].volume_name = talloc_strdup(ctx,
1525 dname);
1526 if (!jucn[cnt].service_name ||
1527 !jucn[cnt].volume_name) {
1528 TALLOC_FREE(talloced);
1529 goto out;
1531 jucn[cnt].comment = "";
1532 cnt++;
1534 TALLOC_FREE(link_target);
1536 TALLOC_FREE(talloced);
1539 out:
1541 if (dirp) {
1542 SMB_VFS_CLOSEDIR(conn,dirp);
1545 vfs_ChDir(conn, cwd);
1546 conn_free(conn);
1547 return cnt;
1550 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1552 struct junction_map *jn = NULL;
1553 int i=0;
1554 size_t jn_count = 0;
1555 int sharecount = 0;
1557 *p_num_jn = 0;
1558 if(!lp_host_msdfs()) {
1559 return NULL;
1562 /* Ensure all the usershares are loaded. */
1563 become_root();
1564 load_registry_shares();
1565 sharecount = load_usershare_shares(NULL, connections_snum_used);
1566 unbecome_root();
1568 for(i=0;i < sharecount;i++) {
1569 if(lp_msdfs_root(i)) {
1570 jn_count += count_dfs_links(ctx, i);
1573 if (jn_count == 0) {
1574 return NULL;
1576 jn = talloc_array(ctx, struct junction_map, jn_count);
1577 if (!jn) {
1578 return NULL;
1580 for(i=0; i < sharecount; i++) {
1581 if (*p_num_jn >= jn_count) {
1582 break;
1584 if(lp_msdfs_root(i)) {
1585 *p_num_jn += form_junctions(ctx, i,
1586 &jn[*p_num_jn],
1587 jn_count - *p_num_jn);
1590 return jn;
1593 /******************************************************************************
1594 Core function to resolve a dfs pathname possibly containing a wildcard. If
1595 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1596 detected during dfs resolution.
1597 ******************************************************************************/
1599 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1600 connection_struct *conn,
1601 bool dfs_pathnames,
1602 const char *name_in,
1603 bool allow_wcards,
1604 bool allow_broken_path,
1605 char **pp_name_out,
1606 bool *ppath_contains_wcard)
1608 bool path_contains_wcard;
1609 NTSTATUS status = NT_STATUS_OK;
1611 if (dfs_pathnames) {
1612 status = dfs_redirect(ctx,
1613 conn,
1614 name_in,
1615 allow_wcards,
1616 allow_broken_path,
1617 pp_name_out,
1618 &path_contains_wcard);
1620 if (NT_STATUS_IS_OK(status) && ppath_contains_wcard != NULL) {
1621 *ppath_contains_wcard = path_contains_wcard;
1623 } else {
1625 * Cheat and just return a copy of the in ptr.
1626 * Once srvstr_get_path() uses talloc it'll
1627 * be a talloced ptr anyway.
1629 *pp_name_out = discard_const_p(char, name_in);
1631 return status;