ctdb-vacuum: make ctdb_process_delete_list() void
[Samba.git] / source3 / smbd / msdfs.c
blob97849d2e6e6a775a0fef0963468383cc8bd93a1e
1 /*
2 Unix SMB/Netbios implementation.
3 Version 3.0
4 MSDFS services for Samba
5 Copyright (C) Shirish Kalele 2000
6 Copyright (C) Jeremy Allison 2007
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #define DBGC_CLASS DBGC_MSDFS
24 #include "includes.h"
25 #include "system/filesys.h"
26 #include "smbd/smbd.h"
27 #include "smbd/globals.h"
28 #include "msdfs.h"
29 #include "auth.h"
30 #include "lib/param/loadparm.h"
31 #include "libcli/security/security.h"
32 #include "librpc/gen_ndr/ndr_dfsblobs.h"
34 /**********************************************************************
35 Parse a DFS pathname of the form \hostname\service\reqpath
36 into the dfs_path structure.
37 If POSIX pathnames is true, the pathname may also be of the
38 form /hostname/service/reqpath.
39 We cope with either here.
41 Unfortunately, due to broken clients who might set the
42 SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
43 send a local path, we have to cope with that too....
45 If conn != NULL then ensure the provided service is
46 the one pointed to by the connection.
48 This version does everything using pointers within one copy of the
49 pathname string, talloced on the struct dfs_path pointer (which
50 must be talloced). This may be too clever to live....
51 JRA.
52 **********************************************************************/
54 static NTSTATUS parse_dfs_path(connection_struct *conn,
55 const char *pathname,
56 bool allow_wcards,
57 bool allow_broken_path,
58 struct dfs_path *pdp, /* MUST BE TALLOCED */
59 bool *ppath_contains_wcard)
61 char *pathname_local;
62 char *p,*temp;
63 char *servicename;
64 char *eos_ptr;
65 NTSTATUS status = NT_STATUS_OK;
66 char sepchar;
68 ZERO_STRUCTP(pdp);
71 * This is the only talloc we should need to do
72 * on the struct dfs_path. All the pointers inside
73 * it should point to offsets within this string.
76 pathname_local = talloc_strdup(pdp, pathname);
77 if (!pathname_local) {
78 return NT_STATUS_NO_MEMORY;
80 /* Get a pointer to the terminating '\0' */
81 eos_ptr = &pathname_local[strlen(pathname_local)];
82 p = temp = pathname_local;
84 pdp->posix_path = (lp_posix_pathnames() && *pathname == '/');
86 sepchar = pdp->posix_path ? '/' : '\\';
88 if (allow_broken_path && (*pathname != sepchar)) {
89 DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
90 pathname, sepchar ));
92 * Possibly client sent a local path by mistake.
93 * Try and convert to a local path.
96 pdp->hostname = eos_ptr; /* "" */
97 pdp->servicename = eos_ptr; /* "" */
99 /* We've got no info about separators. */
100 pdp->posix_path = lp_posix_pathnames();
101 p = temp;
102 DEBUG(10,("parse_dfs_path: trying to convert %s to a "
103 "local path\n",
104 temp));
105 goto local_path;
109 * Safe to use on talloc'ed string as it only shrinks.
110 * It also doesn't affect the eos_ptr.
112 trim_char(temp,sepchar,sepchar);
114 DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
115 temp, sepchar));
117 /* Now tokenize. */
118 /* Parse out hostname. */
119 p = strchr_m(temp,sepchar);
120 if(p == NULL) {
121 DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
122 temp));
124 * Possibly client sent a local path by mistake.
125 * Try and convert to a local path.
128 pdp->hostname = eos_ptr; /* "" */
129 pdp->servicename = eos_ptr; /* "" */
131 p = temp;
132 DEBUG(10,("parse_dfs_path: trying to convert %s "
133 "to a local path\n",
134 temp));
135 goto local_path;
137 *p = '\0';
138 pdp->hostname = temp;
140 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
142 /* Parse out servicename. */
143 servicename = p+1;
144 p = strchr_m(servicename,sepchar);
145 if (p) {
146 *p = '\0';
149 /* Is this really our servicename ? */
150 if (conn && !( strequal(servicename, lp_servicename(talloc_tos(), SNUM(conn)))
151 || (strequal(servicename, HOMES_NAME)
152 && strequal(lp_servicename(talloc_tos(), SNUM(conn)),
153 get_current_username()) )) ) {
154 DEBUG(10,("parse_dfs_path: %s is not our servicename\n",
155 servicename));
158 * Possibly client sent a local path by mistake.
159 * Try and convert to a local path.
162 pdp->hostname = eos_ptr; /* "" */
163 pdp->servicename = eos_ptr; /* "" */
165 /* Repair the path - replace the sepchar's
166 we nulled out */
167 servicename--;
168 *servicename = sepchar;
169 if (p) {
170 *p = sepchar;
173 p = temp;
174 DEBUG(10,("parse_dfs_path: trying to convert %s "
175 "to a local path\n",
176 temp));
177 goto local_path;
180 pdp->servicename = servicename;
182 DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
184 if(p == NULL) {
185 /* Client sent self referral \server\share. */
186 pdp->reqpath = eos_ptr; /* "" */
187 return NT_STATUS_OK;
190 p++;
192 local_path:
194 *ppath_contains_wcard = False;
196 pdp->reqpath = p;
198 /* Rest is reqpath. */
199 if (pdp->posix_path) {
200 status = check_path_syntax_posix(pdp->reqpath);
201 } else {
202 if (allow_wcards) {
203 status = check_path_syntax_wcard(pdp->reqpath,
204 ppath_contains_wcard);
205 } else {
206 status = check_path_syntax(pdp->reqpath);
210 if (!NT_STATUS_IS_OK(status)) {
211 DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
212 p, nt_errstr(status) ));
213 return status;
216 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
217 return NT_STATUS_OK;
220 /********************************************************
221 Fake up a connection struct for the VFS layer, for use in
222 applications (such as the python bindings), that do not want the
223 global working directory changed under them.
225 SMB_VFS_CONNECT requires root privileges.
226 *********************************************************/
228 static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx,
229 struct tevent_context *ev,
230 struct messaging_context *msg,
231 connection_struct **pconn,
232 int snum,
233 const char *path,
234 const struct auth_session_info *session_info)
236 connection_struct *conn;
237 char *connpath;
238 const char *vfs_user;
239 struct smbd_server_connection *sconn;
240 const char *servicename = lp_const_servicename(snum);
242 sconn = talloc_zero(ctx, struct smbd_server_connection);
243 if (sconn == NULL) {
244 return NT_STATUS_NO_MEMORY;
247 sconn->ev_ctx = ev;
248 sconn->msg_ctx = msg;
249 sconn->sock = -1;
250 sconn->smb1.echo_handler.trusted_fd = -1;
251 sconn->smb1.echo_handler.socket_lock_fd = -1;
253 conn = conn_new(sconn);
254 if (conn == NULL) {
255 TALLOC_FREE(sconn);
256 return NT_STATUS_NO_MEMORY;
259 /* Now we have conn, we need to make sconn a child of conn,
260 * for a proper talloc tree */
261 talloc_steal(conn, sconn);
263 if (snum == -1 && servicename == NULL) {
264 servicename = "Unknown Service (snum == -1)";
267 connpath = talloc_strdup(conn, path);
268 if (!connpath) {
269 TALLOC_FREE(conn);
270 return NT_STATUS_NO_MEMORY;
272 connpath = talloc_string_sub(conn,
273 connpath,
274 "%S",
275 servicename);
276 if (!connpath) {
277 TALLOC_FREE(conn);
278 return NT_STATUS_NO_MEMORY;
281 /* needed for smbd_vfs_init() */
283 conn->params->service = snum;
284 conn->cnum = TID_FIELD_INVALID;
286 if (session_info != NULL) {
287 conn->session_info = copy_session_info(conn, session_info);
288 if (conn->session_info == NULL) {
289 DEBUG(0, ("copy_serverinfo failed\n"));
290 TALLOC_FREE(conn);
291 return NT_STATUS_NO_MEMORY;
293 vfs_user = conn->session_info->unix_info->unix_name;
294 } else {
295 /* use current authenticated user in absence of session_info */
296 vfs_user = get_current_username();
299 set_conn_connectpath(conn, connpath);
302 * New code to check if there's a share security descripter
303 * added from NT server manager. This is done after the
304 * smb.conf checks are done as we need a uid and token. JRA.
307 if (conn->session_info) {
308 share_access_check(conn->session_info->security_token,
309 servicename,
310 MAXIMUM_ALLOWED_ACCESS,
311 &conn->share_access);
313 if ((conn->share_access & FILE_WRITE_DATA) == 0) {
314 if ((conn->share_access & FILE_READ_DATA) == 0) {
315 /* No access, read or write. */
316 DEBUG(0,("create_conn_struct: connection to %s "
317 "denied due to security "
318 "descriptor.\n",
319 servicename));
320 conn_free(conn);
321 return NT_STATUS_ACCESS_DENIED;
322 } else {
323 conn->read_only = true;
326 } else {
327 conn->share_access = 0;
328 conn->read_only = true;
331 if (!smbd_vfs_init(conn)) {
332 NTSTATUS status = map_nt_error_from_unix(errno);
333 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
334 conn_free(conn);
335 return status;
338 /* this must be the first filesystem operation that we do */
339 if (SMB_VFS_CONNECT(conn, servicename, vfs_user) < 0) {
340 DEBUG(0,("VFS connect failed!\n"));
341 conn_free(conn);
342 return NT_STATUS_UNSUCCESSFUL;
345 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
346 *pconn = conn;
348 return NT_STATUS_OK;
351 /********************************************************
352 Fake up a connection struct for the VFS layer, for use in
353 applications (such as the python bindings), that do not want the
354 global working directory changed under them.
356 SMB_VFS_CONNECT requires root privileges.
357 *********************************************************/
359 NTSTATUS create_conn_struct(TALLOC_CTX *ctx,
360 struct tevent_context *ev,
361 struct messaging_context *msg,
362 connection_struct **pconn,
363 int snum,
364 const char *path,
365 const struct auth_session_info *session_info)
367 NTSTATUS status;
368 become_root();
369 status = create_conn_struct_as_root(ctx, ev,
370 msg, pconn,
371 snum, path,
372 session_info);
373 unbecome_root();
375 return status;
378 /********************************************************
379 Fake up a connection struct for the VFS layer.
380 Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
382 The old working directory is returned on *poldcwd, allocated on ctx.
383 *********************************************************/
385 NTSTATUS create_conn_struct_cwd(TALLOC_CTX *ctx,
386 struct tevent_context *ev,
387 struct messaging_context *msg,
388 connection_struct **pconn,
389 int snum,
390 const char *path,
391 const struct auth_session_info *session_info,
392 char **poldcwd)
394 connection_struct *conn;
395 char *oldcwd;
397 NTSTATUS status = create_conn_struct(ctx, ev,
398 msg, &conn,
399 snum, path,
400 session_info);
401 if (!NT_STATUS_IS_OK(status)) {
402 return status;
406 * Windows seems to insist on doing trans2getdfsreferral() calls on
407 * the IPC$ share as the anonymous user. If we try to chdir as that
408 * user we will fail.... WTF ? JRA.
411 oldcwd = vfs_GetWd(ctx, conn);
412 if (oldcwd == NULL) {
413 status = map_nt_error_from_unix(errno);
414 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
415 conn_free(conn);
416 return status;
419 if (vfs_ChDir(conn,conn->connectpath) != 0) {
420 status = map_nt_error_from_unix(errno);
421 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
422 "Error was %s\n",
423 conn->connectpath, strerror(errno) ));
424 conn_free(conn);
425 return status;
428 *pconn = conn;
429 *poldcwd = oldcwd;
431 return NT_STATUS_OK;
434 /**********************************************************************
435 Parse the contents of a symlink to verify if it is an msdfs referral
436 A valid referral is of the form:
438 msdfs:server1\share1,server2\share2
439 msdfs:server1\share1\pathname,server2\share2\pathname
440 msdfs:server1/share1,server2/share2
441 msdfs:server1/share1/pathname,server2/share2/pathname.
443 Note that the alternate paths returned here must be of the canonicalized
444 form:
446 \server\share or
447 \server\share\path\to\file,
449 even in posix path mode. This is because we have no knowledge if the
450 server we're referring to understands posix paths.
451 **********************************************************************/
453 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
454 const char *target,
455 struct referral **preflist,
456 int *refcount)
458 char *temp = NULL;
459 char *prot;
460 char **alt_path = NULL;
461 int count = 0, i;
462 struct referral *reflist;
463 char *saveptr;
465 temp = talloc_strdup(ctx, target);
466 if (!temp) {
467 return False;
469 prot = strtok_r(temp, ":", &saveptr);
470 if (!prot) {
471 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
472 return False;
475 alt_path = talloc_array(ctx, char *, MAX_REFERRAL_COUNT);
476 if (!alt_path) {
477 return False;
480 /* parse out the alternate paths */
481 while((count<MAX_REFERRAL_COUNT) &&
482 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
483 count++;
486 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
488 if (count) {
489 reflist = *preflist = talloc_zero_array(ctx,
490 struct referral, count);
491 if(reflist == NULL) {
492 TALLOC_FREE(alt_path);
493 return False;
495 } else {
496 reflist = *preflist = NULL;
499 for(i=0;i<count;i++) {
500 char *p;
502 /* Canonicalize link target.
503 * Replace all /'s in the path by a \ */
504 string_replace(alt_path[i], '/', '\\');
506 /* Remove leading '\\'s */
507 p = alt_path[i];
508 while (*p && (*p == '\\')) {
509 p++;
512 reflist[i].alternate_path = talloc_asprintf(ctx,
513 "\\%s",
515 if (!reflist[i].alternate_path) {
516 return False;
519 reflist[i].proximity = 0;
520 reflist[i].ttl = REFERRAL_TTL;
521 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
522 reflist[i].alternate_path));
525 *refcount = count;
527 TALLOC_FREE(alt_path);
528 return True;
531 /**********************************************************************
532 Returns true if the unix path is a valid msdfs symlink and also
533 returns the target string from inside the link.
534 **********************************************************************/
536 static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
537 connection_struct *conn,
538 const char *path,
539 char **pp_link_target,
540 SMB_STRUCT_STAT *sbufp)
542 int referral_len = 0;
543 #if defined(HAVE_BROKEN_READLINK)
544 char link_target_buf[PATH_MAX];
545 #else
546 char link_target_buf[7];
547 #endif
548 size_t bufsize = 0;
549 char *link_target = NULL;
550 struct smb_filename smb_fname;
552 if (pp_link_target) {
553 bufsize = 1024;
554 link_target = talloc_array(ctx, char, bufsize);
555 if (!link_target) {
556 return False;
558 *pp_link_target = link_target;
559 } else {
560 bufsize = sizeof(link_target_buf);
561 link_target = link_target_buf;
564 ZERO_STRUCT(smb_fname);
565 smb_fname.base_name = discard_const_p(char, path);
567 if (SMB_VFS_LSTAT(conn, &smb_fname) != 0) {
568 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
569 path));
570 goto err;
572 if (!S_ISLNK(smb_fname.st.st_ex_mode)) {
573 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
574 path));
575 goto err;
577 if (sbufp != NULL) {
578 *sbufp = smb_fname.st;
581 referral_len = SMB_VFS_READLINK(conn, path, link_target, bufsize - 1);
582 if (referral_len == -1) {
583 DEBUG(0,("is_msdfs_link_read_target: Error reading "
584 "msdfs link %s: %s\n",
585 path, strerror(errno)));
586 goto err;
588 link_target[referral_len] = '\0';
590 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path,
591 link_target));
593 if (!strnequal(link_target, "msdfs:", 6)) {
594 goto err;
596 return True;
598 err:
600 if (link_target != link_target_buf) {
601 TALLOC_FREE(link_target);
603 return False;
606 /**********************************************************************
607 Returns true if the unix path is a valid msdfs symlink.
608 **********************************************************************/
610 bool is_msdfs_link(connection_struct *conn,
611 const char *path,
612 SMB_STRUCT_STAT *sbufp)
614 return is_msdfs_link_internal(talloc_tos(),
615 conn,
616 path,
617 NULL,
618 sbufp);
621 /*****************************************************************
622 Used by other functions to decide if a dfs path is remote,
623 and to get the list of referred locations for that remote path.
625 search_flag: For findfirsts, dfs links themselves are not
626 redirected, but paths beyond the links are. For normal smb calls,
627 even dfs links need to be redirected.
629 consumedcntp: how much of the dfs path is being redirected. the client
630 should try the remaining path on the redirected server.
632 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
633 link redirect are in targetpath.
634 *****************************************************************/
636 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
637 connection_struct *conn,
638 const char *dfspath, /* Incoming complete dfs path */
639 const struct dfs_path *pdp, /* Parsed out
640 server+share+extrapath. */
641 bool search_flag, /* Called from a findfirst ? */
642 int *consumedcntp,
643 char **pp_targetpath)
645 char *p = NULL;
646 char *q = NULL;
647 NTSTATUS status;
648 struct smb_filename *smb_fname = NULL;
649 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
650 components). */
652 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
653 conn->connectpath, pdp->reqpath));
656 * Note the unix path conversion here we're doing we
657 * throw away. We're looking for a symlink for a dfs
658 * resolution, if we don't find it we'll do another
659 * unix_convert later in the codepath.
662 status = unix_convert(ctx, conn, pdp->reqpath, &smb_fname,
663 search_flag ? UCF_ALWAYS_ALLOW_WCARD_LCOMP : 0);
665 if (!NT_STATUS_IS_OK(status)) {
666 if (!NT_STATUS_EQUAL(status,
667 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
668 return status;
670 if (smb_fname == NULL || smb_fname->base_name == NULL) {
671 return status;
675 /* Optimization - check if we can redirect the whole path. */
677 if (is_msdfs_link_internal(ctx, conn, smb_fname->base_name,
678 pp_targetpath, NULL)) {
679 if (search_flag) {
680 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
681 "for dfs link %s.\n", dfspath));
682 status = NT_STATUS_OK;
683 goto out;
686 DEBUG(6,("dfs_path_lookup: %s resolves to a "
687 "valid dfs link %s.\n", dfspath,
688 pp_targetpath ? *pp_targetpath : ""));
690 if (consumedcntp) {
691 *consumedcntp = strlen(dfspath);
693 status = NT_STATUS_PATH_NOT_COVERED;
694 goto out;
697 /* Prepare to test only for '/' components in the given path,
698 * so if a Windows path replace all '\\' characters with '/'.
699 * For a POSIX DFS path we know all separators are already '/'. */
701 canon_dfspath = talloc_strdup(ctx, dfspath);
702 if (!canon_dfspath) {
703 status = NT_STATUS_NO_MEMORY;
704 goto out;
706 if (!pdp->posix_path) {
707 string_replace(canon_dfspath, '\\', '/');
711 * localpath comes out of unix_convert, so it has
712 * no trailing backslash. Make sure that canon_dfspath hasn't either.
713 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
716 trim_char(canon_dfspath,0,'/');
719 * Redirect if any component in the path is a link.
720 * We do this by walking backwards through the
721 * local path, chopping off the last component
722 * in both the local path and the canonicalized
723 * DFS path. If we hit a DFS link then we're done.
726 p = strrchr_m(smb_fname->base_name, '/');
727 if (consumedcntp) {
728 q = strrchr_m(canon_dfspath, '/');
731 while (p) {
732 *p = '\0';
733 if (q) {
734 *q = '\0';
737 if (is_msdfs_link_internal(ctx, conn,
738 smb_fname->base_name, pp_targetpath,
739 NULL)) {
740 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
741 "parent %s is dfs link\n", dfspath,
742 smb_fname_str_dbg(smb_fname)));
744 if (consumedcntp) {
745 *consumedcntp = strlen(canon_dfspath);
746 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
747 "(%d)\n",
748 canon_dfspath,
749 *consumedcntp));
752 status = NT_STATUS_PATH_NOT_COVERED;
753 goto out;
756 /* Step back on the filesystem. */
757 p = strrchr_m(smb_fname->base_name, '/');
759 if (consumedcntp) {
760 /* And in the canonicalized dfs path. */
761 q = strrchr_m(canon_dfspath, '/');
765 status = NT_STATUS_OK;
766 out:
767 TALLOC_FREE(smb_fname);
768 return status;
771 /*****************************************************************
772 Decides if a dfs pathname should be redirected or not.
773 If not, the pathname is converted to a tcon-relative local unix path
775 search_wcard_flag: this flag performs 2 functions both related
776 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
777 for details.
779 This function can return NT_STATUS_OK, meaning use the returned path as-is
780 (mapped into a local path).
781 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
782 any other NT_STATUS error which is a genuine error to be
783 returned to the client.
784 *****************************************************************/
786 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
787 connection_struct *conn,
788 const char *path_in,
789 bool search_wcard_flag,
790 bool allow_broken_path,
791 char **pp_path_out,
792 bool *ppath_contains_wcard)
794 NTSTATUS status;
795 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
797 if (!pdp) {
798 return NT_STATUS_NO_MEMORY;
801 status = parse_dfs_path(conn, path_in, search_wcard_flag,
802 allow_broken_path, pdp,
803 ppath_contains_wcard);
804 if (!NT_STATUS_IS_OK(status)) {
805 TALLOC_FREE(pdp);
806 return status;
809 if (pdp->reqpath[0] == '\0') {
810 TALLOC_FREE(pdp);
811 *pp_path_out = talloc_strdup(ctx, "");
812 if (!*pp_path_out) {
813 return NT_STATUS_NO_MEMORY;
815 DEBUG(5,("dfs_redirect: self-referral.\n"));
816 return NT_STATUS_OK;
819 /* If dfs pathname for a non-dfs share, convert to tcon-relative
820 path and return OK */
822 if (!lp_msdfs_root(SNUM(conn))) {
823 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
824 TALLOC_FREE(pdp);
825 if (!*pp_path_out) {
826 return NT_STATUS_NO_MEMORY;
828 return NT_STATUS_OK;
831 /* If it looked like a local path (zero hostname/servicename)
832 * just treat as a tcon-relative path. */
834 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
835 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
836 TALLOC_FREE(pdp);
837 if (!*pp_path_out) {
838 return NT_STATUS_NO_MEMORY;
840 return NT_STATUS_OK;
843 if (!( strequal(pdp->servicename, lp_servicename(talloc_tos(), SNUM(conn)))
844 || (strequal(pdp->servicename, HOMES_NAME)
845 && strequal(lp_servicename(talloc_tos(), SNUM(conn)),
846 conn->session_info->unix_info->sanitized_username) )) ) {
848 /* The given sharename doesn't match this connection. */
849 TALLOC_FREE(pdp);
851 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
854 status = dfs_path_lookup(ctx, conn, path_in, pdp,
855 search_wcard_flag, NULL, NULL);
856 if (!NT_STATUS_IS_OK(status)) {
857 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
858 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
859 } else {
860 DEBUG(10,("dfs_redirect: dfs_path_lookup "
861 "failed for %s with %s\n",
862 path_in, nt_errstr(status) ));
864 return status;
867 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
869 /* Form non-dfs tcon-relative path */
870 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
871 TALLOC_FREE(pdp);
872 if (!*pp_path_out) {
873 return NT_STATUS_NO_MEMORY;
876 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
877 path_in,
878 *pp_path_out));
880 return NT_STATUS_OK;
883 /**********************************************************************
884 Return a self referral.
885 **********************************************************************/
887 static NTSTATUS self_ref(TALLOC_CTX *ctx,
888 const char *dfs_path,
889 struct junction_map *jucn,
890 int *consumedcntp,
891 bool *self_referralp)
893 struct referral *ref;
895 *self_referralp = True;
897 jucn->referral_count = 1;
898 if((ref = talloc_zero(ctx, struct referral)) == NULL) {
899 return NT_STATUS_NO_MEMORY;
902 ref->alternate_path = talloc_strdup(ctx, dfs_path);
903 if (!ref->alternate_path) {
904 TALLOC_FREE(ref);
905 return NT_STATUS_NO_MEMORY;
907 ref->proximity = 0;
908 ref->ttl = REFERRAL_TTL;
909 jucn->referral_list = ref;
910 *consumedcntp = strlen(dfs_path);
911 return NT_STATUS_OK;
914 /**********************************************************************
915 Gets valid referrals for a dfs path and fills up the
916 junction_map structure.
917 **********************************************************************/
919 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
920 const char *dfs_path,
921 bool allow_broken_path,
922 struct junction_map *jucn,
923 int *consumedcntp,
924 bool *self_referralp)
926 struct connection_struct *conn;
927 char *targetpath = NULL;
928 int snum;
929 NTSTATUS status = NT_STATUS_NOT_FOUND;
930 bool dummy;
931 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
932 char *oldpath;
934 if (!pdp) {
935 return NT_STATUS_NO_MEMORY;
938 *self_referralp = False;
940 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
941 pdp, &dummy);
942 if (!NT_STATUS_IS_OK(status)) {
943 return status;
946 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
947 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
948 if (!jucn->service_name || !jucn->volume_name) {
949 TALLOC_FREE(pdp);
950 return NT_STATUS_NO_MEMORY;
953 /* Verify the share is a dfs root */
954 snum = lp_servicenumber(jucn->service_name);
955 if(snum < 0) {
956 char *service_name = NULL;
957 if ((snum = find_service(ctx, jucn->service_name, &service_name)) < 0) {
958 return NT_STATUS_NOT_FOUND;
960 if (!service_name) {
961 return NT_STATUS_NO_MEMORY;
963 TALLOC_FREE(jucn->service_name);
964 jucn->service_name = talloc_strdup(ctx, service_name);
965 if (!jucn->service_name) {
966 TALLOC_FREE(pdp);
967 return NT_STATUS_NO_MEMORY;
971 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(talloc_tos(), snum) == '\0')) {
972 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
973 "a dfs root.\n",
974 pdp->servicename, dfs_path));
975 TALLOC_FREE(pdp);
976 return NT_STATUS_NOT_FOUND;
980 * Self referrals are tested with a anonymous IPC connection and
981 * a GET_DFS_REFERRAL call to \\server\share. (which means
982 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
983 * into the directory and will fail if it cannot (as the anonymous
984 * user). Cope with this.
987 if (pdp->reqpath[0] == '\0') {
988 char *tmp;
989 struct referral *ref;
990 int refcount;
992 if (*lp_msdfs_proxy(talloc_tos(), snum) == '\0') {
993 TALLOC_FREE(pdp);
994 return self_ref(ctx,
995 dfs_path,
996 jucn,
997 consumedcntp,
998 self_referralp);
1002 * It's an msdfs proxy share. Redirect to
1003 * the configured target share.
1006 tmp = talloc_asprintf(talloc_tos(), "msdfs:%s",
1007 lp_msdfs_proxy(talloc_tos(), snum));
1008 if (tmp == NULL) {
1009 TALLOC_FREE(pdp);
1010 return NT_STATUS_NO_MEMORY;
1013 if (!parse_msdfs_symlink(ctx, tmp, &ref, &refcount)) {
1014 TALLOC_FREE(tmp);
1015 TALLOC_FREE(pdp);
1016 return NT_STATUS_INVALID_PARAMETER;
1018 TALLOC_FREE(tmp);
1019 jucn->referral_count = refcount;
1020 jucn->referral_list = ref;
1021 *consumedcntp = strlen(dfs_path);
1022 TALLOC_FREE(pdp);
1023 return NT_STATUS_OK;
1026 status = create_conn_struct_cwd(ctx,
1027 server_event_context(),
1028 server_messaging_context(),
1029 &conn, snum,
1030 lp_path(talloc_tos(), snum), NULL, &oldpath);
1031 if (!NT_STATUS_IS_OK(status)) {
1032 TALLOC_FREE(pdp);
1033 return status;
1036 /* If this is a DFS path dfs_lookup should return
1037 * NT_STATUS_PATH_NOT_COVERED. */
1039 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
1040 False, consumedcntp, &targetpath);
1042 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
1043 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
1044 dfs_path));
1045 if (NT_STATUS_IS_OK(status)) {
1047 * We are in an error path here (we
1048 * know it's not a DFS path), but
1049 * dfs_path_lookup() can return
1050 * NT_STATUS_OK. Ensure we always
1051 * return a valid error code.
1053 * #9588 - ACLs are not inherited to directories
1054 * for DFS shares.
1056 status = NT_STATUS_NOT_FOUND;
1058 goto err_exit;
1061 /* We know this is a valid dfs link. Parse the targetpath. */
1062 if (!parse_msdfs_symlink(ctx, targetpath,
1063 &jucn->referral_list,
1064 &jucn->referral_count)) {
1065 DEBUG(3,("get_referred_path: failed to parse symlink "
1066 "target %s\n", targetpath ));
1067 status = NT_STATUS_NOT_FOUND;
1068 goto err_exit;
1071 status = NT_STATUS_OK;
1072 err_exit:
1073 vfs_ChDir(conn, oldpath);
1074 SMB_VFS_DISCONNECT(conn);
1075 conn_free(conn);
1076 TALLOC_FREE(pdp);
1077 return status;
1080 /******************************************************************
1081 Set up the DFS referral for the dfs pathname. This call returns
1082 the amount of the path covered by this server, and where the
1083 client should be redirected to. This is the meat of the
1084 TRANS2_GET_DFS_REFERRAL call.
1085 ******************************************************************/
1087 int setup_dfs_referral(connection_struct *orig_conn,
1088 const char *dfs_path,
1089 int max_referral_level,
1090 char **ppdata, NTSTATUS *pstatus)
1092 char *pdata = *ppdata;
1093 int reply_size = 0;
1094 struct dfs_GetDFSReferral *r;
1095 DATA_BLOB blob = data_blob_null;
1096 NTSTATUS status;
1097 enum ndr_err_code ndr_err;
1099 r = talloc_zero(talloc_tos(), struct dfs_GetDFSReferral);
1100 if (r == NULL) {
1101 *pstatus = NT_STATUS_NO_MEMORY;
1102 return -1;
1105 r->in.req.max_referral_level = max_referral_level;
1106 r->in.req.servername = talloc_strdup(r, dfs_path);
1107 if (r->in.req.servername == NULL) {
1108 talloc_free(r);
1109 *pstatus = NT_STATUS_NO_MEMORY;
1110 return -1;
1113 status = SMB_VFS_GET_DFS_REFERRALS(orig_conn, r);
1114 if (!NT_STATUS_IS_OK(status)) {
1115 talloc_free(r);
1116 *pstatus = status;
1117 return -1;
1120 ndr_err = ndr_push_struct_blob(&blob, r,
1121 r->out.resp,
1122 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1123 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1124 TALLOC_FREE(r);
1125 *pstatus = NT_STATUS_INVALID_PARAMETER;
1126 return -1;
1129 pdata = (char *)SMB_REALLOC(pdata, blob.length);
1130 if(pdata == NULL) {
1131 TALLOC_FREE(r);
1132 DEBUG(0,("referral setup:"
1133 "malloc failed for Realloc!\n"));
1134 return -1;
1136 *ppdata = pdata;
1137 reply_size = blob.length;
1138 memcpy(pdata, blob.data, blob.length);
1139 TALLOC_FREE(r);
1141 *pstatus = NT_STATUS_OK;
1142 return reply_size;
1145 /**********************************************************************
1146 The following functions are called by the NETDFS RPC pipe functions
1147 **********************************************************************/
1149 /*********************************************************************
1150 Creates a junction structure from a DFS pathname
1151 **********************************************************************/
1153 bool create_junction(TALLOC_CTX *ctx,
1154 const char *dfs_path,
1155 bool allow_broken_path,
1156 struct junction_map *jucn)
1158 int snum;
1159 bool dummy;
1160 struct dfs_path *pdp = talloc(ctx,struct dfs_path);
1161 NTSTATUS status;
1163 if (!pdp) {
1164 return False;
1166 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1167 pdp, &dummy);
1168 if (!NT_STATUS_IS_OK(status)) {
1169 return False;
1172 /* check if path is dfs : validate first token */
1173 if (!is_myname_or_ipaddr(pdp->hostname)) {
1174 DEBUG(4,("create_junction: Invalid hostname %s "
1175 "in dfs path %s\n",
1176 pdp->hostname, dfs_path));
1177 TALLOC_FREE(pdp);
1178 return False;
1181 /* Check for a non-DFS share */
1182 snum = lp_servicenumber(pdp->servicename);
1184 if(snum < 0 || !lp_msdfs_root(snum)) {
1185 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1186 pdp->servicename));
1187 TALLOC_FREE(pdp);
1188 return False;
1191 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1192 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1193 jucn->comment = lp_comment(ctx, snum);
1195 TALLOC_FREE(pdp);
1196 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1197 return False;
1199 return True;
1202 /**********************************************************************
1203 Forms a valid Unix pathname from the junction
1204 **********************************************************************/
1206 static bool junction_to_local_path(const struct junction_map *jucn,
1207 char **pp_path_out,
1208 connection_struct **conn_out,
1209 char **oldpath)
1211 int snum;
1212 NTSTATUS status;
1214 snum = lp_servicenumber(jucn->service_name);
1215 if(snum < 0) {
1216 return False;
1218 status = create_conn_struct_cwd(talloc_tos(),
1219 server_event_context(),
1220 server_messaging_context(),
1221 conn_out,
1222 snum, lp_path(talloc_tos(), snum), NULL, oldpath);
1223 if (!NT_STATUS_IS_OK(status)) {
1224 return False;
1227 *pp_path_out = talloc_asprintf(*conn_out,
1228 "%s/%s",
1229 lp_path(talloc_tos(), snum),
1230 jucn->volume_name);
1231 if (!*pp_path_out) {
1232 vfs_ChDir(*conn_out, *oldpath);
1233 SMB_VFS_DISCONNECT(*conn_out);
1234 conn_free(*conn_out);
1235 return False;
1237 return True;
1240 bool create_msdfs_link(const struct junction_map *jucn)
1242 char *path = NULL;
1243 char *cwd;
1244 char *msdfs_link = NULL;
1245 connection_struct *conn;
1246 int i=0;
1247 bool insert_comma = False;
1248 bool ret = False;
1250 if(!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1251 return False;
1254 /* Form the msdfs_link contents */
1255 msdfs_link = talloc_strdup(conn, "msdfs:");
1256 if (!msdfs_link) {
1257 goto out;
1259 for(i=0; i<jucn->referral_count; i++) {
1260 char *refpath = jucn->referral_list[i].alternate_path;
1262 /* Alternate paths always use Windows separators. */
1263 trim_char(refpath, '\\', '\\');
1264 if(*refpath == '\0') {
1265 if (i == 0) {
1266 insert_comma = False;
1268 continue;
1270 if (i > 0 && insert_comma) {
1271 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1272 ",%s",
1273 refpath);
1274 } else {
1275 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1276 "%s",
1277 refpath);
1280 if (!msdfs_link) {
1281 goto out;
1283 if (!insert_comma) {
1284 insert_comma = True;
1288 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1289 path, msdfs_link));
1291 if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1292 if (errno == EEXIST) {
1293 struct smb_filename *smb_fname;
1295 smb_fname = synthetic_smb_fname(talloc_tos(), path,
1296 NULL, NULL);
1297 if (smb_fname == NULL) {
1298 errno = ENOMEM;
1299 goto out;
1302 if(SMB_VFS_UNLINK(conn, smb_fname)!=0) {
1303 TALLOC_FREE(smb_fname);
1304 goto out;
1306 TALLOC_FREE(smb_fname);
1308 if (SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1309 DEBUG(1,("create_msdfs_link: symlink failed "
1310 "%s -> %s\nError: %s\n",
1311 path, msdfs_link, strerror(errno)));
1312 goto out;
1316 ret = True;
1318 out:
1319 vfs_ChDir(conn, cwd);
1320 SMB_VFS_DISCONNECT(conn);
1321 conn_free(conn);
1322 return ret;
1325 bool remove_msdfs_link(const struct junction_map *jucn)
1327 char *path = NULL;
1328 char *cwd;
1329 connection_struct *conn;
1330 bool ret = False;
1331 struct smb_filename *smb_fname;
1333 if (!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1334 return false;
1337 smb_fname = synthetic_smb_fname(talloc_tos(), path, NULL, NULL);
1338 if (smb_fname == NULL) {
1339 errno = ENOMEM;
1340 return false;
1343 if( SMB_VFS_UNLINK(conn, smb_fname) == 0 ) {
1344 ret = True;
1347 TALLOC_FREE(smb_fname);
1348 vfs_ChDir(conn, cwd);
1349 SMB_VFS_DISCONNECT(conn);
1350 conn_free(conn);
1351 return ret;
1354 /*********************************************************************
1355 Return the number of DFS links at the root of this share.
1356 *********************************************************************/
1358 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1360 size_t cnt = 0;
1361 DIR *dirp = NULL;
1362 const char *dname = NULL;
1363 char *talloced = NULL;
1364 const char *connect_path = lp_path(talloc_tos(), snum);
1365 const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum);
1366 connection_struct *conn;
1367 NTSTATUS status;
1368 char *cwd;
1370 if(*connect_path == '\0') {
1371 return 0;
1375 * Fake up a connection struct for the VFS layer.
1378 status = create_conn_struct_cwd(talloc_tos(),
1379 server_event_context(),
1380 server_messaging_context(),
1381 &conn,
1382 snum, connect_path, NULL, &cwd);
1383 if (!NT_STATUS_IS_OK(status)) {
1384 DEBUG(3, ("create_conn_struct failed: %s\n",
1385 nt_errstr(status)));
1386 return 0;
1389 /* Count a link for the msdfs root - convention */
1390 cnt = 1;
1392 /* No more links if this is an msdfs proxy. */
1393 if (*msdfs_proxy != '\0') {
1394 goto out;
1397 /* Now enumerate all dfs links */
1398 dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1399 if(!dirp) {
1400 goto out;
1403 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1404 != NULL) {
1405 if (is_msdfs_link(conn,
1406 dname,
1407 NULL)) {
1408 cnt++;
1410 TALLOC_FREE(talloced);
1413 SMB_VFS_CLOSEDIR(conn,dirp);
1415 out:
1416 vfs_ChDir(conn, cwd);
1417 SMB_VFS_DISCONNECT(conn);
1418 conn_free(conn);
1419 return cnt;
1422 /*********************************************************************
1423 *********************************************************************/
1425 static int form_junctions(TALLOC_CTX *ctx,
1426 int snum,
1427 struct junction_map *jucn,
1428 size_t jn_remain)
1430 size_t cnt = 0;
1431 DIR *dirp = NULL;
1432 const char *dname = NULL;
1433 char *talloced = NULL;
1434 const char *connect_path = lp_path(talloc_tos(), snum);
1435 char *service_name = lp_servicename(talloc_tos(), snum);
1436 const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum);
1437 connection_struct *conn;
1438 struct referral *ref = NULL;
1439 char *cwd;
1440 NTSTATUS status;
1442 if (jn_remain == 0) {
1443 return 0;
1446 if(*connect_path == '\0') {
1447 return 0;
1451 * Fake up a connection struct for the VFS layer.
1454 status = create_conn_struct_cwd(ctx,
1455 server_event_context(),
1456 server_messaging_context(),
1457 &conn, snum, connect_path, NULL,
1458 &cwd);
1459 if (!NT_STATUS_IS_OK(status)) {
1460 DEBUG(3, ("create_conn_struct failed: %s\n",
1461 nt_errstr(status)));
1462 return 0;
1465 /* form a junction for the msdfs root - convention
1466 DO NOT REMOVE THIS: NT clients will not work with us
1467 if this is not present
1469 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1470 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1471 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1472 goto out;
1474 jucn[cnt].comment = "";
1475 jucn[cnt].referral_count = 1;
1477 ref = jucn[cnt].referral_list = talloc_zero(ctx, struct referral);
1478 if (jucn[cnt].referral_list == NULL) {
1479 goto out;
1482 ref->proximity = 0;
1483 ref->ttl = REFERRAL_TTL;
1484 if (*msdfs_proxy != '\0') {
1485 ref->alternate_path = talloc_strdup(ctx,
1486 msdfs_proxy);
1487 } else {
1488 ref->alternate_path = talloc_asprintf(ctx,
1489 "\\\\%s\\%s",
1490 get_local_machine_name(),
1491 service_name);
1494 if (!ref->alternate_path) {
1495 goto out;
1497 cnt++;
1499 /* Don't enumerate if we're an msdfs proxy. */
1500 if (*msdfs_proxy != '\0') {
1501 goto out;
1504 /* Now enumerate all dfs links */
1505 dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1506 if(!dirp) {
1507 goto out;
1510 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1511 != NULL) {
1512 char *link_target = NULL;
1513 if (cnt >= jn_remain) {
1514 DEBUG(2, ("form_junctions: ran out of MSDFS "
1515 "junction slots"));
1516 TALLOC_FREE(talloced);
1517 goto out;
1519 if (is_msdfs_link_internal(ctx,
1520 conn,
1521 dname, &link_target,
1522 NULL)) {
1523 if (parse_msdfs_symlink(ctx,
1524 link_target,
1525 &jucn[cnt].referral_list,
1526 &jucn[cnt].referral_count)) {
1528 jucn[cnt].service_name = talloc_strdup(ctx,
1529 service_name);
1530 jucn[cnt].volume_name = talloc_strdup(ctx,
1531 dname);
1532 if (!jucn[cnt].service_name ||
1533 !jucn[cnt].volume_name) {
1534 TALLOC_FREE(talloced);
1535 goto out;
1537 jucn[cnt].comment = "";
1538 cnt++;
1540 TALLOC_FREE(link_target);
1542 TALLOC_FREE(talloced);
1545 out:
1547 if (dirp) {
1548 SMB_VFS_CLOSEDIR(conn,dirp);
1551 vfs_ChDir(conn, cwd);
1552 conn_free(conn);
1553 return cnt;
1556 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1558 struct junction_map *jn = NULL;
1559 int i=0;
1560 size_t jn_count = 0;
1561 int sharecount = 0;
1563 *p_num_jn = 0;
1564 if(!lp_host_msdfs()) {
1565 return NULL;
1568 /* Ensure all the usershares are loaded. */
1569 become_root();
1570 load_registry_shares();
1571 sharecount = load_usershare_shares(NULL, connections_snum_used);
1572 unbecome_root();
1574 for(i=0;i < sharecount;i++) {
1575 if(lp_msdfs_root(i)) {
1576 jn_count += count_dfs_links(ctx, i);
1579 if (jn_count == 0) {
1580 return NULL;
1582 jn = talloc_array(ctx, struct junction_map, jn_count);
1583 if (!jn) {
1584 return NULL;
1586 for(i=0; i < sharecount; i++) {
1587 if (*p_num_jn >= jn_count) {
1588 break;
1590 if(lp_msdfs_root(i)) {
1591 *p_num_jn += form_junctions(ctx, i,
1592 &jn[*p_num_jn],
1593 jn_count - *p_num_jn);
1596 return jn;
1599 /******************************************************************************
1600 Core function to resolve a dfs pathname possibly containing a wildcard. If
1601 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1602 detected during dfs resolution.
1603 ******************************************************************************/
1605 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1606 connection_struct *conn,
1607 bool dfs_pathnames,
1608 const char *name_in,
1609 bool allow_wcards,
1610 bool allow_broken_path,
1611 char **pp_name_out,
1612 bool *ppath_contains_wcard)
1614 bool path_contains_wcard;
1615 NTSTATUS status = NT_STATUS_OK;
1617 if (dfs_pathnames) {
1618 status = dfs_redirect(ctx,
1619 conn,
1620 name_in,
1621 allow_wcards,
1622 allow_broken_path,
1623 pp_name_out,
1624 &path_contains_wcard);
1626 if (NT_STATUS_IS_OK(status) && ppath_contains_wcard != NULL) {
1627 *ppath_contains_wcard = path_contains_wcard;
1629 } else {
1631 * Cheat and just return a copy of the in ptr.
1632 * Once srvstr_get_path() uses talloc it'll
1633 * be a talloced ptr anyway.
1635 *pp_name_out = discard_const_p(char, name_in);
1637 return status;