s3:smb2_sesssetup: cancel and wait for pending requests on logoff
[Samba.git] / source3 / smbd / msdfs.c
blob096a3a09c99b8b3c5ed9066e6aaeebb213a53158
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;
991 if (*lp_msdfs_proxy(talloc_tos(), snum) == '\0') {
992 TALLOC_FREE(pdp);
993 return self_ref(ctx,
994 dfs_path,
995 jucn,
996 consumedcntp,
997 self_referralp);
1001 * It's an msdfs proxy share. Redirect to
1002 * the configured target share.
1005 jucn->referral_count = 1;
1006 if ((ref = talloc_zero(ctx, struct referral)) == NULL) {
1007 TALLOC_FREE(pdp);
1008 return NT_STATUS_NO_MEMORY;
1011 if (!(tmp = talloc_strdup(ctx, lp_msdfs_proxy(talloc_tos(), snum)))) {
1012 TALLOC_FREE(pdp);
1013 return NT_STATUS_NO_MEMORY;
1016 trim_string(tmp, "\\", 0);
1018 ref->alternate_path = talloc_asprintf(ctx, "\\%s", tmp);
1019 TALLOC_FREE(tmp);
1021 if (!ref->alternate_path) {
1022 TALLOC_FREE(pdp);
1023 return NT_STATUS_NO_MEMORY;
1026 if (pdp->reqpath[0] != '\0') {
1027 ref->alternate_path = talloc_asprintf_append(
1028 ref->alternate_path,
1029 "%s",
1030 pdp->reqpath);
1031 if (!ref->alternate_path) {
1032 TALLOC_FREE(pdp);
1033 return NT_STATUS_NO_MEMORY;
1036 ref->proximity = 0;
1037 ref->ttl = REFERRAL_TTL;
1038 jucn->referral_list = ref;
1039 *consumedcntp = strlen(dfs_path);
1040 TALLOC_FREE(pdp);
1041 return NT_STATUS_OK;
1044 status = create_conn_struct_cwd(ctx,
1045 server_event_context(),
1046 server_messaging_context(),
1047 &conn, snum,
1048 lp_pathname(talloc_tos(), snum), NULL, &oldpath);
1049 if (!NT_STATUS_IS_OK(status)) {
1050 TALLOC_FREE(pdp);
1051 return status;
1054 /* If this is a DFS path dfs_lookup should return
1055 * NT_STATUS_PATH_NOT_COVERED. */
1057 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
1058 False, consumedcntp, &targetpath);
1060 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
1061 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
1062 dfs_path));
1063 if (NT_STATUS_IS_OK(status)) {
1065 * We are in an error path here (we
1066 * know it's not a DFS path), but
1067 * dfs_path_lookup() can return
1068 * NT_STATUS_OK. Ensure we always
1069 * return a valid error code.
1071 * #9588 - ACLs are not inherited to directories
1072 * for DFS shares.
1074 status = NT_STATUS_NOT_FOUND;
1076 goto err_exit;
1079 /* We know this is a valid dfs link. Parse the targetpath. */
1080 if (!parse_msdfs_symlink(ctx, targetpath,
1081 &jucn->referral_list,
1082 &jucn->referral_count)) {
1083 DEBUG(3,("get_referred_path: failed to parse symlink "
1084 "target %s\n", targetpath ));
1085 status = NT_STATUS_NOT_FOUND;
1086 goto err_exit;
1089 status = NT_STATUS_OK;
1090 err_exit:
1091 vfs_ChDir(conn, oldpath);
1092 SMB_VFS_DISCONNECT(conn);
1093 conn_free(conn);
1094 TALLOC_FREE(pdp);
1095 return status;
1098 /******************************************************************
1099 Set up the DFS referral for the dfs pathname. This call returns
1100 the amount of the path covered by this server, and where the
1101 client should be redirected to. This is the meat of the
1102 TRANS2_GET_DFS_REFERRAL call.
1103 ******************************************************************/
1105 int setup_dfs_referral(connection_struct *orig_conn,
1106 const char *dfs_path,
1107 int max_referral_level,
1108 char **ppdata, NTSTATUS *pstatus)
1110 char *pdata = *ppdata;
1111 int reply_size = 0;
1112 struct dfs_GetDFSReferral *r;
1113 DATA_BLOB blob = data_blob_null;
1114 NTSTATUS status;
1115 enum ndr_err_code ndr_err;
1117 r = talloc_zero(talloc_tos(), struct dfs_GetDFSReferral);
1118 if (r == NULL) {
1119 *pstatus = NT_STATUS_NO_MEMORY;
1120 return -1;
1123 r->in.req.max_referral_level = max_referral_level;
1124 r->in.req.servername = talloc_strdup(r, dfs_path);
1125 if (r->in.req.servername == NULL) {
1126 talloc_free(r);
1127 *pstatus = NT_STATUS_NO_MEMORY;
1128 return -1;
1131 status = SMB_VFS_GET_DFS_REFERRALS(orig_conn, r);
1132 if (!NT_STATUS_IS_OK(status)) {
1133 talloc_free(r);
1134 *pstatus = status;
1135 return -1;
1138 ndr_err = ndr_push_struct_blob(&blob, r,
1139 r->out.resp,
1140 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1141 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1142 TALLOC_FREE(r);
1143 *pstatus = NT_STATUS_INVALID_PARAMETER;
1144 return -1;
1147 pdata = (char *)SMB_REALLOC(pdata, blob.length);
1148 if(pdata == NULL) {
1149 TALLOC_FREE(r);
1150 DEBUG(0,("referral setup:"
1151 "malloc failed for Realloc!\n"));
1152 return -1;
1154 *ppdata = pdata;
1155 reply_size = blob.length;
1156 memcpy(pdata, blob.data, blob.length);
1157 TALLOC_FREE(r);
1159 *pstatus = NT_STATUS_OK;
1160 return reply_size;
1163 /**********************************************************************
1164 The following functions are called by the NETDFS RPC pipe functions
1165 **********************************************************************/
1167 /*********************************************************************
1168 Creates a junction structure from a DFS pathname
1169 **********************************************************************/
1171 bool create_junction(TALLOC_CTX *ctx,
1172 const char *dfs_path,
1173 bool allow_broken_path,
1174 struct junction_map *jucn)
1176 int snum;
1177 bool dummy;
1178 struct dfs_path *pdp = talloc(ctx,struct dfs_path);
1179 NTSTATUS status;
1181 if (!pdp) {
1182 return False;
1184 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1185 pdp, &dummy);
1186 if (!NT_STATUS_IS_OK(status)) {
1187 return False;
1190 /* check if path is dfs : validate first token */
1191 if (!is_myname_or_ipaddr(pdp->hostname)) {
1192 DEBUG(4,("create_junction: Invalid hostname %s "
1193 "in dfs path %s\n",
1194 pdp->hostname, dfs_path));
1195 TALLOC_FREE(pdp);
1196 return False;
1199 /* Check for a non-DFS share */
1200 snum = lp_servicenumber(pdp->servicename);
1202 if(snum < 0 || !lp_msdfs_root(snum)) {
1203 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1204 pdp->servicename));
1205 TALLOC_FREE(pdp);
1206 return False;
1209 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1210 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1211 jucn->comment = lp_comment(ctx, snum);
1213 TALLOC_FREE(pdp);
1214 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1215 return False;
1217 return True;
1220 /**********************************************************************
1221 Forms a valid Unix pathname from the junction
1222 **********************************************************************/
1224 static bool junction_to_local_path(const struct junction_map *jucn,
1225 char **pp_path_out,
1226 connection_struct **conn_out,
1227 char **oldpath)
1229 int snum;
1230 NTSTATUS status;
1232 snum = lp_servicenumber(jucn->service_name);
1233 if(snum < 0) {
1234 return False;
1236 status = create_conn_struct_cwd(talloc_tos(),
1237 server_event_context(),
1238 server_messaging_context(),
1239 conn_out,
1240 snum, lp_pathname(talloc_tos(), snum), NULL, oldpath);
1241 if (!NT_STATUS_IS_OK(status)) {
1242 return False;
1245 *pp_path_out = talloc_asprintf(*conn_out,
1246 "%s/%s",
1247 lp_pathname(talloc_tos(), snum),
1248 jucn->volume_name);
1249 if (!*pp_path_out) {
1250 vfs_ChDir(*conn_out, *oldpath);
1251 SMB_VFS_DISCONNECT(*conn_out);
1252 conn_free(*conn_out);
1253 return False;
1255 return True;
1258 bool create_msdfs_link(const struct junction_map *jucn)
1260 char *path = NULL;
1261 char *cwd;
1262 char *msdfs_link = NULL;
1263 connection_struct *conn;
1264 int i=0;
1265 bool insert_comma = False;
1266 bool ret = False;
1268 if(!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1269 return False;
1272 /* Form the msdfs_link contents */
1273 msdfs_link = talloc_strdup(conn, "msdfs:");
1274 if (!msdfs_link) {
1275 goto out;
1277 for(i=0; i<jucn->referral_count; i++) {
1278 char *refpath = jucn->referral_list[i].alternate_path;
1280 /* Alternate paths always use Windows separators. */
1281 trim_char(refpath, '\\', '\\');
1282 if(*refpath == '\0') {
1283 if (i == 0) {
1284 insert_comma = False;
1286 continue;
1288 if (i > 0 && insert_comma) {
1289 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1290 ",%s",
1291 refpath);
1292 } else {
1293 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1294 "%s",
1295 refpath);
1298 if (!msdfs_link) {
1299 goto out;
1301 if (!insert_comma) {
1302 insert_comma = True;
1306 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1307 path, msdfs_link));
1309 if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1310 if (errno == EEXIST) {
1311 struct smb_filename *smb_fname;
1313 smb_fname = synthetic_smb_fname(talloc_tos(), path,
1314 NULL, NULL);
1315 if (smb_fname == NULL) {
1316 errno = ENOMEM;
1317 goto out;
1320 if(SMB_VFS_UNLINK(conn, smb_fname)!=0) {
1321 TALLOC_FREE(smb_fname);
1322 goto out;
1324 TALLOC_FREE(smb_fname);
1326 if (SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1327 DEBUG(1,("create_msdfs_link: symlink failed "
1328 "%s -> %s\nError: %s\n",
1329 path, msdfs_link, strerror(errno)));
1330 goto out;
1334 ret = True;
1336 out:
1337 vfs_ChDir(conn, cwd);
1338 SMB_VFS_DISCONNECT(conn);
1339 conn_free(conn);
1340 return ret;
1343 bool remove_msdfs_link(const struct junction_map *jucn)
1345 char *path = NULL;
1346 char *cwd;
1347 connection_struct *conn;
1348 bool ret = False;
1349 struct smb_filename *smb_fname;
1351 if (!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1352 return false;
1355 smb_fname = synthetic_smb_fname(talloc_tos(), path, NULL, NULL);
1356 if (smb_fname == NULL) {
1357 errno = ENOMEM;
1358 return false;
1361 if( SMB_VFS_UNLINK(conn, smb_fname) == 0 ) {
1362 ret = True;
1365 TALLOC_FREE(smb_fname);
1366 vfs_ChDir(conn, cwd);
1367 SMB_VFS_DISCONNECT(conn);
1368 conn_free(conn);
1369 return ret;
1372 /*********************************************************************
1373 Return the number of DFS links at the root of this share.
1374 *********************************************************************/
1376 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1378 size_t cnt = 0;
1379 DIR *dirp = NULL;
1380 const char *dname = NULL;
1381 char *talloced = NULL;
1382 const char *connect_path = lp_pathname(talloc_tos(), snum);
1383 const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum);
1384 connection_struct *conn;
1385 NTSTATUS status;
1386 char *cwd;
1388 if(*connect_path == '\0') {
1389 return 0;
1393 * Fake up a connection struct for the VFS layer.
1396 status = create_conn_struct_cwd(talloc_tos(),
1397 server_event_context(),
1398 server_messaging_context(),
1399 &conn,
1400 snum, connect_path, NULL, &cwd);
1401 if (!NT_STATUS_IS_OK(status)) {
1402 DEBUG(3, ("create_conn_struct failed: %s\n",
1403 nt_errstr(status)));
1404 return 0;
1407 /* Count a link for the msdfs root - convention */
1408 cnt = 1;
1410 /* No more links if this is an msdfs proxy. */
1411 if (*msdfs_proxy != '\0') {
1412 goto out;
1415 /* Now enumerate all dfs links */
1416 dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1417 if(!dirp) {
1418 goto out;
1421 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1422 != NULL) {
1423 if (is_msdfs_link(conn,
1424 dname,
1425 NULL)) {
1426 cnt++;
1428 TALLOC_FREE(talloced);
1431 SMB_VFS_CLOSEDIR(conn,dirp);
1433 out:
1434 vfs_ChDir(conn, cwd);
1435 SMB_VFS_DISCONNECT(conn);
1436 conn_free(conn);
1437 return cnt;
1440 /*********************************************************************
1441 *********************************************************************/
1443 static int form_junctions(TALLOC_CTX *ctx,
1444 int snum,
1445 struct junction_map *jucn,
1446 size_t jn_remain)
1448 size_t cnt = 0;
1449 DIR *dirp = NULL;
1450 const char *dname = NULL;
1451 char *talloced = NULL;
1452 const char *connect_path = lp_pathname(talloc_tos(), snum);
1453 char *service_name = lp_servicename(talloc_tos(), snum);
1454 const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum);
1455 connection_struct *conn;
1456 struct referral *ref = NULL;
1457 char *cwd;
1458 NTSTATUS status;
1460 if (jn_remain == 0) {
1461 return 0;
1464 if(*connect_path == '\0') {
1465 return 0;
1469 * Fake up a connection struct for the VFS layer.
1472 status = create_conn_struct_cwd(ctx,
1473 server_event_context(),
1474 server_messaging_context(),
1475 &conn, snum, connect_path, NULL,
1476 &cwd);
1477 if (!NT_STATUS_IS_OK(status)) {
1478 DEBUG(3, ("create_conn_struct failed: %s\n",
1479 nt_errstr(status)));
1480 return 0;
1483 /* form a junction for the msdfs root - convention
1484 DO NOT REMOVE THIS: NT clients will not work with us
1485 if this is not present
1487 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1488 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1489 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1490 goto out;
1492 jucn[cnt].comment = "";
1493 jucn[cnt].referral_count = 1;
1495 ref = jucn[cnt].referral_list = talloc_zero(ctx, struct referral);
1496 if (jucn[cnt].referral_list == NULL) {
1497 goto out;
1500 ref->proximity = 0;
1501 ref->ttl = REFERRAL_TTL;
1502 if (*msdfs_proxy != '\0') {
1503 ref->alternate_path = talloc_strdup(ctx,
1504 msdfs_proxy);
1505 } else {
1506 ref->alternate_path = talloc_asprintf(ctx,
1507 "\\\\%s\\%s",
1508 get_local_machine_name(),
1509 service_name);
1512 if (!ref->alternate_path) {
1513 goto out;
1515 cnt++;
1517 /* Don't enumerate if we're an msdfs proxy. */
1518 if (*msdfs_proxy != '\0') {
1519 goto out;
1522 /* Now enumerate all dfs links */
1523 dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1524 if(!dirp) {
1525 goto out;
1528 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1529 != NULL) {
1530 char *link_target = NULL;
1531 if (cnt >= jn_remain) {
1532 DEBUG(2, ("form_junctions: ran out of MSDFS "
1533 "junction slots"));
1534 TALLOC_FREE(talloced);
1535 goto out;
1537 if (is_msdfs_link_internal(ctx,
1538 conn,
1539 dname, &link_target,
1540 NULL)) {
1541 if (parse_msdfs_symlink(ctx,
1542 link_target,
1543 &jucn[cnt].referral_list,
1544 &jucn[cnt].referral_count)) {
1546 jucn[cnt].service_name = talloc_strdup(ctx,
1547 service_name);
1548 jucn[cnt].volume_name = talloc_strdup(ctx,
1549 dname);
1550 if (!jucn[cnt].service_name ||
1551 !jucn[cnt].volume_name) {
1552 TALLOC_FREE(talloced);
1553 goto out;
1555 jucn[cnt].comment = "";
1556 cnt++;
1558 TALLOC_FREE(link_target);
1560 TALLOC_FREE(talloced);
1563 out:
1565 if (dirp) {
1566 SMB_VFS_CLOSEDIR(conn,dirp);
1569 vfs_ChDir(conn, cwd);
1570 conn_free(conn);
1571 return cnt;
1574 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1576 struct junction_map *jn = NULL;
1577 int i=0;
1578 size_t jn_count = 0;
1579 int sharecount = 0;
1581 *p_num_jn = 0;
1582 if(!lp_host_msdfs()) {
1583 return NULL;
1586 /* Ensure all the usershares are loaded. */
1587 become_root();
1588 load_registry_shares();
1589 sharecount = load_usershare_shares(NULL, connections_snum_used);
1590 unbecome_root();
1592 for(i=0;i < sharecount;i++) {
1593 if(lp_msdfs_root(i)) {
1594 jn_count += count_dfs_links(ctx, i);
1597 if (jn_count == 0) {
1598 return NULL;
1600 jn = talloc_array(ctx, struct junction_map, jn_count);
1601 if (!jn) {
1602 return NULL;
1604 for(i=0; i < sharecount; i++) {
1605 if (*p_num_jn >= jn_count) {
1606 break;
1608 if(lp_msdfs_root(i)) {
1609 *p_num_jn += form_junctions(ctx, i,
1610 &jn[*p_num_jn],
1611 jn_count - *p_num_jn);
1614 return jn;
1617 /******************************************************************************
1618 Core function to resolve a dfs pathname possibly containing a wildcard. If
1619 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1620 detected during dfs resolution.
1621 ******************************************************************************/
1623 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1624 connection_struct *conn,
1625 bool dfs_pathnames,
1626 const char *name_in,
1627 bool allow_wcards,
1628 bool allow_broken_path,
1629 char **pp_name_out,
1630 bool *ppath_contains_wcard)
1632 bool path_contains_wcard;
1633 NTSTATUS status = NT_STATUS_OK;
1635 if (dfs_pathnames) {
1636 status = dfs_redirect(ctx,
1637 conn,
1638 name_in,
1639 allow_wcards,
1640 allow_broken_path,
1641 pp_name_out,
1642 &path_contains_wcard);
1644 if (NT_STATUS_IS_OK(status) && ppath_contains_wcard != NULL) {
1645 *ppath_contains_wcard = path_contains_wcard;
1647 } else {
1649 * Cheat and just return a copy of the in ptr.
1650 * Once srvstr_get_path() uses talloc it'll
1651 * be a talloced ptr anyway.
1653 *pp_name_out = discard_const_p(char, name_in);
1655 return status;