s3: VFS: Protect errno if sys_getwd() fails across free() call.
[Samba.git] / source3 / smbd / msdfs.c
blobc25fb17cee86538bc526fe11fbea4c93bafa15d6
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
7 Copyright (C) Robin McCorkell 2015
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #define DBGC_CLASS DBGC_MSDFS
25 #include "includes.h"
26 #include "system/filesys.h"
27 #include "smbd/smbd.h"
28 #include "smbd/globals.h"
29 #include "msdfs.h"
30 #include "auth.h"
31 #include "lib/param/loadparm.h"
32 #include "libcli/security/security.h"
33 #include "librpc/gen_ndr/ndr_dfsblobs.h"
34 #include "lib/tsocket/tsocket.h"
36 /**********************************************************************
37 Parse a DFS pathname of the form \hostname\service\reqpath
38 into the dfs_path structure.
39 If POSIX pathnames is true, the pathname may also be of the
40 form /hostname/service/reqpath.
41 We cope with either here.
43 Unfortunately, due to broken clients who might set the
44 SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
45 send a local path, we have to cope with that too....
47 If conn != NULL then ensure the provided service is
48 the one pointed to by the connection.
50 This version does everything using pointers within one copy of the
51 pathname string, talloced on the struct dfs_path pointer (which
52 must be talloced). This may be too clever to live....
53 JRA.
54 **********************************************************************/
56 static NTSTATUS parse_dfs_path(connection_struct *conn,
57 const char *pathname,
58 bool allow_wcards,
59 bool allow_broken_path,
60 struct dfs_path *pdp, /* MUST BE TALLOCED */
61 bool *ppath_contains_wcard)
63 char *pathname_local;
64 char *p,*temp;
65 char *servicename;
66 char *eos_ptr;
67 NTSTATUS status = NT_STATUS_OK;
68 char sepchar;
70 ZERO_STRUCTP(pdp);
73 * This is the only talloc we should need to do
74 * on the struct dfs_path. All the pointers inside
75 * it should point to offsets within this string.
78 pathname_local = talloc_strdup(pdp, pathname);
79 if (!pathname_local) {
80 return NT_STATUS_NO_MEMORY;
82 /* Get a pointer to the terminating '\0' */
83 eos_ptr = &pathname_local[strlen(pathname_local)];
84 p = temp = pathname_local;
87 * Non-broken DFS paths *must* start with the
88 * path separator. For Windows this is always '\\',
89 * for posix paths this is always '/'.
92 if (*pathname == '/') {
93 pdp->posix_path = true;
94 sepchar = '/';
95 } else {
96 pdp->posix_path = false;
97 sepchar = '\\';
100 if (allow_broken_path && (*pathname != sepchar)) {
101 DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
102 pathname, sepchar ));
104 * Possibly client sent a local path by mistake.
105 * Try and convert to a local path.
106 * Note that this is an SMB1-only fallback
107 * to cope with known broken SMB1 clients.
110 pdp->hostname = eos_ptr; /* "" */
111 pdp->servicename = eos_ptr; /* "" */
113 /* We've got no info about separators. */
114 pdp->posix_path = lp_posix_pathnames();
115 p = temp;
116 DEBUG(10,("parse_dfs_path: trying to convert %s to a "
117 "local path\n",
118 temp));
119 goto local_path;
123 * Safe to use on talloc'ed string as it only shrinks.
124 * It also doesn't affect the eos_ptr.
126 trim_char(temp,sepchar,sepchar);
128 DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
129 temp, sepchar));
131 /* Now tokenize. */
132 /* Parse out hostname. */
133 p = strchr_m(temp,sepchar);
134 if(p == NULL) {
135 DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
136 temp));
138 * Possibly client sent a local path by mistake.
139 * Try and convert to a local path.
142 pdp->hostname = eos_ptr; /* "" */
143 pdp->servicename = eos_ptr; /* "" */
145 p = temp;
146 DEBUG(10,("parse_dfs_path: trying to convert %s "
147 "to a local path\n",
148 temp));
149 goto local_path;
151 *p = '\0';
152 pdp->hostname = temp;
154 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
156 /* Parse out servicename. */
157 servicename = p+1;
158 p = strchr_m(servicename,sepchar);
159 if (p) {
160 *p = '\0';
163 /* Is this really our servicename ? */
164 if (conn && !( strequal(servicename, lp_servicename(talloc_tos(), SNUM(conn)))
165 || (strequal(servicename, HOMES_NAME)
166 && strequal(lp_servicename(talloc_tos(), SNUM(conn)),
167 get_current_username()) )) ) {
168 DEBUG(10,("parse_dfs_path: %s is not our servicename\n",
169 servicename));
172 * Possibly client sent a local path by mistake.
173 * Try and convert to a local path.
176 pdp->hostname = eos_ptr; /* "" */
177 pdp->servicename = eos_ptr; /* "" */
179 /* Repair the path - replace the sepchar's
180 we nulled out */
181 servicename--;
182 *servicename = sepchar;
183 if (p) {
184 *p = sepchar;
187 p = temp;
188 DEBUG(10,("parse_dfs_path: trying to convert %s "
189 "to a local path\n",
190 temp));
191 goto local_path;
194 pdp->servicename = servicename;
196 DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
198 if(p == NULL) {
199 /* Client sent self referral \server\share. */
200 pdp->reqpath = eos_ptr; /* "" */
201 return NT_STATUS_OK;
204 p++;
206 local_path:
208 *ppath_contains_wcard = False;
210 pdp->reqpath = p;
212 /* Rest is reqpath. */
213 if (pdp->posix_path) {
214 status = check_path_syntax_posix(pdp->reqpath);
215 } else {
216 if (allow_wcards) {
217 status = check_path_syntax_wcard(pdp->reqpath,
218 ppath_contains_wcard);
219 } else {
220 status = check_path_syntax(pdp->reqpath);
224 if (!NT_STATUS_IS_OK(status)) {
225 DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
226 p, nt_errstr(status) ));
227 return status;
230 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
231 return NT_STATUS_OK;
234 /********************************************************
235 Fake up a connection struct for the VFS layer, for use in
236 applications (such as the python bindings), that do not want the
237 global working directory changed under them.
239 SMB_VFS_CONNECT requires root privileges.
240 *********************************************************/
242 static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx,
243 struct tevent_context *ev,
244 struct messaging_context *msg,
245 connection_struct **pconn,
246 int snum,
247 const char *path,
248 const struct auth_session_info *session_info)
250 connection_struct *conn;
251 char *connpath;
252 const char *vfs_user;
253 struct smbd_server_connection *sconn;
254 const char *servicename = lp_const_servicename(snum);
256 sconn = talloc_zero(ctx, struct smbd_server_connection);
257 if (sconn == NULL) {
258 return NT_STATUS_NO_MEMORY;
261 sconn->ev_ctx = ev;
262 sconn->msg_ctx = msg;
264 conn = conn_new(sconn);
265 if (conn == NULL) {
266 TALLOC_FREE(sconn);
267 return NT_STATUS_NO_MEMORY;
270 /* Now we have conn, we need to make sconn a child of conn,
271 * for a proper talloc tree */
272 talloc_steal(conn, sconn);
274 if (snum == -1 && servicename == NULL) {
275 servicename = "Unknown Service (snum == -1)";
278 connpath = talloc_strdup(conn, path);
279 if (!connpath) {
280 TALLOC_FREE(conn);
281 return NT_STATUS_NO_MEMORY;
283 connpath = talloc_string_sub(conn,
284 connpath,
285 "%S",
286 servicename);
287 if (!connpath) {
288 TALLOC_FREE(conn);
289 return NT_STATUS_NO_MEMORY;
292 /* needed for smbd_vfs_init() */
294 conn->params->service = snum;
295 conn->cnum = TID_FIELD_INVALID;
297 if (session_info != NULL) {
298 conn->session_info = copy_session_info(conn, session_info);
299 if (conn->session_info == NULL) {
300 DEBUG(0, ("copy_serverinfo failed\n"));
301 TALLOC_FREE(conn);
302 return NT_STATUS_NO_MEMORY;
304 vfs_user = conn->session_info->unix_info->unix_name;
305 } else {
306 /* use current authenticated user in absence of session_info */
307 vfs_user = get_current_username();
310 set_conn_connectpath(conn, connpath);
313 * New code to check if there's a share security descriptor
314 * added from NT server manager. This is done after the
315 * smb.conf checks are done as we need a uid and token. JRA.
318 if (conn->session_info) {
319 share_access_check(conn->session_info->security_token,
320 servicename,
321 MAXIMUM_ALLOWED_ACCESS,
322 &conn->share_access);
324 if ((conn->share_access & FILE_WRITE_DATA) == 0) {
325 if ((conn->share_access & FILE_READ_DATA) == 0) {
326 /* No access, read or write. */
327 DEBUG(3,("create_conn_struct: connection to %s "
328 "denied due to security "
329 "descriptor.\n",
330 servicename));
331 conn_free(conn);
332 return NT_STATUS_ACCESS_DENIED;
333 } else {
334 conn->read_only = true;
337 } else {
338 conn->share_access = 0;
339 conn->read_only = true;
342 if (!smbd_vfs_init(conn)) {
343 NTSTATUS status = map_nt_error_from_unix(errno);
344 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
345 conn_free(conn);
346 return status;
349 /* this must be the first filesystem operation that we do */
350 if (SMB_VFS_CONNECT(conn, servicename, vfs_user) < 0) {
351 DEBUG(0,("VFS connect failed!\n"));
352 conn_free(conn);
353 return NT_STATUS_UNSUCCESSFUL;
356 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
357 *pconn = conn;
359 return NT_STATUS_OK;
362 /********************************************************
363 Fake up a connection struct for the VFS layer, for use in
364 applications (such as the python bindings), that do not want the
365 global working directory changed under them.
367 SMB_VFS_CONNECT requires root privileges.
368 *********************************************************/
370 NTSTATUS create_conn_struct(TALLOC_CTX *ctx,
371 struct tevent_context *ev,
372 struct messaging_context *msg,
373 connection_struct **pconn,
374 int snum,
375 const char *path,
376 const struct auth_session_info *session_info)
378 NTSTATUS status;
379 become_root();
380 status = create_conn_struct_as_root(ctx, ev,
381 msg, pconn,
382 snum, path,
383 session_info);
384 unbecome_root();
386 return status;
389 /********************************************************
390 Fake up a connection struct for the VFS layer.
391 Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
393 The old working directory is returned on *poldcwd, allocated on ctx.
394 *********************************************************/
396 NTSTATUS create_conn_struct_cwd(TALLOC_CTX *ctx,
397 struct tevent_context *ev,
398 struct messaging_context *msg,
399 connection_struct **pconn,
400 int snum,
401 const char *path,
402 const struct auth_session_info *session_info,
403 char **poldcwd)
405 connection_struct *conn;
406 char *oldcwd;
408 NTSTATUS status = create_conn_struct(ctx, ev,
409 msg, &conn,
410 snum, path,
411 session_info);
412 if (!NT_STATUS_IS_OK(status)) {
413 return status;
417 * Windows seems to insist on doing trans2getdfsreferral() calls on
418 * the IPC$ share as the anonymous user. If we try to chdir as that
419 * user we will fail.... WTF ? JRA.
422 oldcwd = vfs_GetWd(ctx, conn);
423 if (oldcwd == NULL) {
424 status = map_nt_error_from_unix(errno);
425 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
426 conn_free(conn);
427 return status;
430 if (vfs_ChDir(conn,conn->connectpath) != 0) {
431 status = map_nt_error_from_unix(errno);
432 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
433 "Error was %s\n",
434 conn->connectpath, strerror(errno) ));
435 conn_free(conn);
436 return status;
439 *pconn = conn;
440 *poldcwd = oldcwd;
442 return NT_STATUS_OK;
445 static void shuffle_strlist(char **list, int count)
447 int i;
448 uint32_t r;
449 char *tmp;
451 for (i = count; i > 1; i--) {
452 r = generate_random() % i;
454 tmp = list[i-1];
455 list[i-1] = list[r];
456 list[r] = tmp;
460 /**********************************************************************
461 Parse the contents of a symlink to verify if it is an msdfs referral
462 A valid referral is of the form:
464 msdfs:server1\share1,server2\share2
465 msdfs:server1\share1\pathname,server2\share2\pathname
466 msdfs:server1/share1,server2/share2
467 msdfs:server1/share1/pathname,server2/share2/pathname.
469 Note that the alternate paths returned here must be of the canonicalized
470 form:
472 \server\share or
473 \server\share\path\to\file,
475 even in posix path mode. This is because we have no knowledge if the
476 server we're referring to understands posix paths.
477 **********************************************************************/
479 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
480 int snum,
481 const char *target,
482 struct referral **preflist,
483 int *refcount)
485 char *temp = NULL;
486 char *prot;
487 char **alt_path = NULL;
488 int count = 0, i;
489 struct referral *reflist;
490 char *saveptr;
492 temp = talloc_strdup(ctx, target);
493 if (!temp) {
494 return False;
496 prot = strtok_r(temp, ":", &saveptr);
497 if (!prot) {
498 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
499 return False;
502 alt_path = talloc_array(ctx, char *, MAX_REFERRAL_COUNT);
503 if (!alt_path) {
504 return False;
507 /* parse out the alternate paths */
508 while((count<MAX_REFERRAL_COUNT) &&
509 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
510 count++;
513 /* shuffle alternate paths */
514 if (lp_msdfs_shuffle_referrals(snum)) {
515 shuffle_strlist(alt_path, count);
518 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
520 if (count) {
521 reflist = *preflist = talloc_zero_array(ctx,
522 struct referral, count);
523 if(reflist == NULL) {
524 TALLOC_FREE(alt_path);
525 return False;
527 } else {
528 reflist = *preflist = NULL;
531 for(i=0;i<count;i++) {
532 char *p;
534 /* Canonicalize link target.
535 * Replace all /'s in the path by a \ */
536 string_replace(alt_path[i], '/', '\\');
538 /* Remove leading '\\'s */
539 p = alt_path[i];
540 while (*p && (*p == '\\')) {
541 p++;
544 reflist[i].alternate_path = talloc_asprintf(ctx,
545 "\\%s",
547 if (!reflist[i].alternate_path) {
548 return False;
551 reflist[i].proximity = 0;
552 reflist[i].ttl = REFERRAL_TTL;
553 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
554 reflist[i].alternate_path));
557 *refcount = count;
559 TALLOC_FREE(alt_path);
560 return True;
563 /**********************************************************************
564 Returns true if the unix path is a valid msdfs symlink and also
565 returns the target string from inside the link.
566 **********************************************************************/
568 static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
569 connection_struct *conn,
570 const char *path,
571 char **pp_link_target,
572 SMB_STRUCT_STAT *sbufp)
574 int referral_len = 0;
575 #if defined(HAVE_BROKEN_READLINK)
576 char link_target_buf[PATH_MAX];
577 #else
578 char link_target_buf[7];
579 #endif
580 size_t bufsize = 0;
581 char *link_target = NULL;
582 struct smb_filename smb_fname;
584 if (pp_link_target) {
585 bufsize = 1024;
586 link_target = talloc_array(ctx, char, bufsize);
587 if (!link_target) {
588 return False;
590 *pp_link_target = link_target;
591 } else {
592 bufsize = sizeof(link_target_buf);
593 link_target = link_target_buf;
596 ZERO_STRUCT(smb_fname);
597 smb_fname.base_name = discard_const_p(char, path);
599 if (SMB_VFS_LSTAT(conn, &smb_fname) != 0) {
600 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
601 path));
602 goto err;
604 if (!S_ISLNK(smb_fname.st.st_ex_mode)) {
605 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
606 path));
607 goto err;
609 if (sbufp != NULL) {
610 *sbufp = smb_fname.st;
613 referral_len = SMB_VFS_READLINK(conn, path, link_target, bufsize - 1);
614 if (referral_len == -1) {
615 DEBUG(0,("is_msdfs_link_read_target: Error reading "
616 "msdfs link %s: %s\n",
617 path, strerror(errno)));
618 goto err;
620 link_target[referral_len] = '\0';
622 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path,
623 link_target));
625 if (!strnequal(link_target, "msdfs:", 6)) {
626 goto err;
628 return True;
630 err:
632 if (link_target != link_target_buf) {
633 TALLOC_FREE(link_target);
635 return False;
638 /**********************************************************************
639 Returns true if the unix path is a valid msdfs symlink.
640 **********************************************************************/
642 bool is_msdfs_link(connection_struct *conn,
643 const char *path,
644 SMB_STRUCT_STAT *sbufp)
646 return is_msdfs_link_internal(talloc_tos(),
647 conn,
648 path,
649 NULL,
650 sbufp);
653 /*****************************************************************
654 Used by other functions to decide if a dfs path is remote,
655 and to get the list of referred locations for that remote path.
657 search_flag: For findfirsts, dfs links themselves are not
658 redirected, but paths beyond the links are. For normal smb calls,
659 even dfs links need to be redirected.
661 consumedcntp: how much of the dfs path is being redirected. the client
662 should try the remaining path on the redirected server.
664 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
665 link redirect are in targetpath.
666 *****************************************************************/
668 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
669 connection_struct *conn,
670 const char *dfspath, /* Incoming complete dfs path */
671 const struct dfs_path *pdp, /* Parsed out
672 server+share+extrapath. */
673 uint32_t ucf_flags,
674 int *consumedcntp,
675 char **pp_targetpath)
677 char *p = NULL;
678 char *q = NULL;
679 NTSTATUS status;
680 struct smb_filename *smb_fname = NULL;
681 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
682 components). */
684 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
685 conn->connectpath, pdp->reqpath));
688 * Note the unix path conversion here we're doing we
689 * throw away. We're looking for a symlink for a dfs
690 * resolution, if we don't find it we'll do another
691 * unix_convert later in the codepath.
694 status = unix_convert(ctx, conn, pdp->reqpath, &smb_fname,
695 ucf_flags);
697 if (!NT_STATUS_IS_OK(status)) {
698 if (!NT_STATUS_EQUAL(status,
699 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
700 return status;
702 if (smb_fname == NULL || smb_fname->base_name == NULL) {
703 return status;
707 /* Optimization - check if we can redirect the whole path. */
709 if (is_msdfs_link_internal(ctx, conn, smb_fname->base_name,
710 pp_targetpath, NULL)) {
711 /* XX_ALLOW_WCARD_XXX is called from search functions. */
712 if (ucf_flags &
713 (UCF_COND_ALLOW_WCARD_LCOMP|
714 UCF_ALWAYS_ALLOW_WCARD_LCOMP)) {
715 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
716 "for dfs link %s.\n", dfspath));
717 status = NT_STATUS_OK;
718 goto out;
721 DEBUG(6,("dfs_path_lookup: %s resolves to a "
722 "valid dfs link %s.\n", dfspath,
723 pp_targetpath ? *pp_targetpath : ""));
725 if (consumedcntp) {
726 *consumedcntp = strlen(dfspath);
728 status = NT_STATUS_PATH_NOT_COVERED;
729 goto out;
732 /* Prepare to test only for '/' components in the given path,
733 * so if a Windows path replace all '\\' characters with '/'.
734 * For a POSIX DFS path we know all separators are already '/'. */
736 canon_dfspath = talloc_strdup(ctx, dfspath);
737 if (!canon_dfspath) {
738 status = NT_STATUS_NO_MEMORY;
739 goto out;
741 if (!pdp->posix_path) {
742 string_replace(canon_dfspath, '\\', '/');
746 * localpath comes out of unix_convert, so it has
747 * no trailing backslash. Make sure that canon_dfspath hasn't either.
748 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
751 trim_char(canon_dfspath,0,'/');
754 * Redirect if any component in the path is a link.
755 * We do this by walking backwards through the
756 * local path, chopping off the last component
757 * in both the local path and the canonicalized
758 * DFS path. If we hit a DFS link then we're done.
761 p = strrchr_m(smb_fname->base_name, '/');
762 if (consumedcntp) {
763 q = strrchr_m(canon_dfspath, '/');
766 while (p) {
767 *p = '\0';
768 if (q) {
769 *q = '\0';
772 if (is_msdfs_link_internal(ctx, conn,
773 smb_fname->base_name, pp_targetpath,
774 NULL)) {
775 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
776 "parent %s is dfs link\n", dfspath,
777 smb_fname_str_dbg(smb_fname)));
779 if (consumedcntp) {
780 *consumedcntp = strlen(canon_dfspath);
781 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
782 "(%d)\n",
783 canon_dfspath,
784 *consumedcntp));
787 status = NT_STATUS_PATH_NOT_COVERED;
788 goto out;
791 /* Step back on the filesystem. */
792 p = strrchr_m(smb_fname->base_name, '/');
794 if (consumedcntp) {
795 /* And in the canonicalized dfs path. */
796 q = strrchr_m(canon_dfspath, '/');
800 status = NT_STATUS_OK;
801 out:
802 TALLOC_FREE(smb_fname);
803 return status;
806 /*****************************************************************
807 Decides if a dfs pathname should be redirected or not.
808 If not, the pathname is converted to a tcon-relative local unix path
810 search_wcard_flag: this flag performs 2 functions both related
811 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
812 for details.
814 This function can return NT_STATUS_OK, meaning use the returned path as-is
815 (mapped into a local path).
816 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
817 any other NT_STATUS error which is a genuine error to be
818 returned to the client.
819 *****************************************************************/
821 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
822 connection_struct *conn,
823 const char *path_in,
824 uint32_t ucf_flags,
825 bool allow_broken_path,
826 char **pp_path_out,
827 bool *ppath_contains_wcard)
829 NTSTATUS status;
830 bool search_wcard_flag = (ucf_flags &
831 (UCF_COND_ALLOW_WCARD_LCOMP|UCF_ALWAYS_ALLOW_WCARD_LCOMP));
832 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
834 if (!pdp) {
835 return NT_STATUS_NO_MEMORY;
838 status = parse_dfs_path(conn, path_in, search_wcard_flag,
839 allow_broken_path, pdp,
840 ppath_contains_wcard);
841 if (!NT_STATUS_IS_OK(status)) {
842 TALLOC_FREE(pdp);
843 return status;
846 if (pdp->reqpath[0] == '\0') {
847 TALLOC_FREE(pdp);
848 *pp_path_out = talloc_strdup(ctx, "");
849 if (!*pp_path_out) {
850 return NT_STATUS_NO_MEMORY;
852 DEBUG(5,("dfs_redirect: self-referral.\n"));
853 return NT_STATUS_OK;
856 /* If dfs pathname for a non-dfs share, convert to tcon-relative
857 path and return OK */
859 if (!lp_msdfs_root(SNUM(conn))) {
860 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
861 TALLOC_FREE(pdp);
862 if (!*pp_path_out) {
863 return NT_STATUS_NO_MEMORY;
865 return NT_STATUS_OK;
868 /* If it looked like a local path (zero hostname/servicename)
869 * just treat as a tcon-relative path. */
871 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
872 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
873 TALLOC_FREE(pdp);
874 if (!*pp_path_out) {
875 return NT_STATUS_NO_MEMORY;
877 return NT_STATUS_OK;
880 if (!( strequal(pdp->servicename, lp_servicename(talloc_tos(), SNUM(conn)))
881 || (strequal(pdp->servicename, HOMES_NAME)
882 && strequal(lp_servicename(talloc_tos(), SNUM(conn)),
883 conn->session_info->unix_info->sanitized_username) )) ) {
885 /* The given sharename doesn't match this connection. */
886 TALLOC_FREE(pdp);
888 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
891 status = dfs_path_lookup(ctx, conn, path_in, pdp,
892 ucf_flags, NULL, NULL);
893 if (!NT_STATUS_IS_OK(status)) {
894 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
895 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
896 } else {
897 DEBUG(10,("dfs_redirect: dfs_path_lookup "
898 "failed for %s with %s\n",
899 path_in, nt_errstr(status) ));
901 return status;
904 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
906 /* Form non-dfs tcon-relative path */
907 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
908 TALLOC_FREE(pdp);
909 if (!*pp_path_out) {
910 return NT_STATUS_NO_MEMORY;
913 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
914 path_in,
915 *pp_path_out));
917 return NT_STATUS_OK;
920 /**********************************************************************
921 Return a self referral.
922 **********************************************************************/
924 static NTSTATUS self_ref(TALLOC_CTX *ctx,
925 const char *dfs_path,
926 struct junction_map *jucn,
927 int *consumedcntp,
928 bool *self_referralp)
930 struct referral *ref;
932 *self_referralp = True;
934 jucn->referral_count = 1;
935 if((ref = talloc_zero(ctx, struct referral)) == NULL) {
936 return NT_STATUS_NO_MEMORY;
939 ref->alternate_path = talloc_strdup(ctx, dfs_path);
940 if (!ref->alternate_path) {
941 TALLOC_FREE(ref);
942 return NT_STATUS_NO_MEMORY;
944 ref->proximity = 0;
945 ref->ttl = REFERRAL_TTL;
946 jucn->referral_list = ref;
947 *consumedcntp = strlen(dfs_path);
948 return NT_STATUS_OK;
951 /**********************************************************************
952 Gets valid referrals for a dfs path and fills up the
953 junction_map structure.
954 **********************************************************************/
956 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
957 const char *dfs_path,
958 const struct tsocket_address *remote_address,
959 const struct tsocket_address *local_address,
960 bool allow_broken_path,
961 struct junction_map *jucn,
962 int *consumedcntp,
963 bool *self_referralp)
965 struct connection_struct *conn;
966 char *targetpath = NULL;
967 int snum;
968 NTSTATUS status = NT_STATUS_NOT_FOUND;
969 bool dummy;
970 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
971 char *oldpath;
973 if (!pdp) {
974 return NT_STATUS_NO_MEMORY;
977 *self_referralp = False;
979 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
980 pdp, &dummy);
981 if (!NT_STATUS_IS_OK(status)) {
982 return status;
985 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
986 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
987 if (!jucn->service_name || !jucn->volume_name) {
988 TALLOC_FREE(pdp);
989 return NT_STATUS_NO_MEMORY;
992 /* Verify the share is a dfs root */
993 snum = lp_servicenumber(jucn->service_name);
994 if(snum < 0) {
995 char *service_name = NULL;
996 if ((snum = find_service(ctx, jucn->service_name, &service_name)) < 0) {
997 return NT_STATUS_NOT_FOUND;
999 if (!service_name) {
1000 return NT_STATUS_NO_MEMORY;
1002 TALLOC_FREE(jucn->service_name);
1003 jucn->service_name = talloc_strdup(ctx, service_name);
1004 if (!jucn->service_name) {
1005 TALLOC_FREE(pdp);
1006 return NT_STATUS_NO_MEMORY;
1010 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(talloc_tos(), snum) == '\0')) {
1011 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
1012 "a dfs root.\n",
1013 pdp->servicename, dfs_path));
1014 TALLOC_FREE(pdp);
1015 return NT_STATUS_NOT_FOUND;
1019 * Self referrals are tested with a anonymous IPC connection and
1020 * a GET_DFS_REFERRAL call to \\server\share. (which means
1021 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
1022 * into the directory and will fail if it cannot (as the anonymous
1023 * user). Cope with this.
1026 if (pdp->reqpath[0] == '\0') {
1027 char *tmp;
1028 struct referral *ref;
1029 int refcount;
1031 if (*lp_msdfs_proxy(talloc_tos(), snum) == '\0') {
1032 TALLOC_FREE(pdp);
1033 return self_ref(ctx,
1034 dfs_path,
1035 jucn,
1036 consumedcntp,
1037 self_referralp);
1041 * It's an msdfs proxy share. Redirect to
1042 * the configured target share.
1045 tmp = talloc_asprintf(talloc_tos(), "msdfs:%s",
1046 lp_msdfs_proxy(talloc_tos(), snum));
1047 if (tmp == NULL) {
1048 TALLOC_FREE(pdp);
1049 return NT_STATUS_NO_MEMORY;
1052 if (!parse_msdfs_symlink(ctx, snum, tmp, &ref, &refcount)) {
1053 TALLOC_FREE(tmp);
1054 TALLOC_FREE(pdp);
1055 return NT_STATUS_INVALID_PARAMETER;
1057 TALLOC_FREE(tmp);
1058 jucn->referral_count = refcount;
1059 jucn->referral_list = ref;
1060 *consumedcntp = strlen(dfs_path);
1061 TALLOC_FREE(pdp);
1062 return NT_STATUS_OK;
1065 status = create_conn_struct_cwd(ctx,
1066 server_event_context(),
1067 server_messaging_context(),
1068 &conn, snum,
1069 lp_path(talloc_tos(), snum), NULL, &oldpath);
1070 if (!NT_STATUS_IS_OK(status)) {
1071 TALLOC_FREE(pdp);
1072 return status;
1076 * TODO
1078 * The remote and local address should be passed down to
1079 * create_conn_struct_cwd.
1081 if (conn->sconn->remote_address == NULL) {
1082 conn->sconn->remote_address =
1083 tsocket_address_copy(remote_address, conn->sconn);
1084 if (conn->sconn->remote_address == NULL) {
1085 TALLOC_FREE(pdp);
1086 return NT_STATUS_NO_MEMORY;
1089 if (conn->sconn->local_address == NULL) {
1090 conn->sconn->local_address =
1091 tsocket_address_copy(local_address, conn->sconn);
1092 if (conn->sconn->local_address == NULL) {
1093 TALLOC_FREE(pdp);
1094 return NT_STATUS_NO_MEMORY;
1098 /* If this is a DFS path dfs_lookup should return
1099 * NT_STATUS_PATH_NOT_COVERED. */
1101 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
1102 0, consumedcntp, &targetpath);
1104 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
1105 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
1106 dfs_path));
1107 if (NT_STATUS_IS_OK(status)) {
1109 * We are in an error path here (we
1110 * know it's not a DFS path), but
1111 * dfs_path_lookup() can return
1112 * NT_STATUS_OK. Ensure we always
1113 * return a valid error code.
1115 * #9588 - ACLs are not inherited to directories
1116 * for DFS shares.
1118 status = NT_STATUS_NOT_FOUND;
1120 goto err_exit;
1123 /* We know this is a valid dfs link. Parse the targetpath. */
1124 if (!parse_msdfs_symlink(ctx, snum, targetpath,
1125 &jucn->referral_list,
1126 &jucn->referral_count)) {
1127 DEBUG(3,("get_referred_path: failed to parse symlink "
1128 "target %s\n", targetpath ));
1129 status = NT_STATUS_NOT_FOUND;
1130 goto err_exit;
1133 status = NT_STATUS_OK;
1134 err_exit:
1135 vfs_ChDir(conn, oldpath);
1136 SMB_VFS_DISCONNECT(conn);
1137 conn_free(conn);
1138 TALLOC_FREE(pdp);
1139 return status;
1142 /******************************************************************
1143 Set up the DFS referral for the dfs pathname. This call returns
1144 the amount of the path covered by this server, and where the
1145 client should be redirected to. This is the meat of the
1146 TRANS2_GET_DFS_REFERRAL call.
1147 ******************************************************************/
1149 int setup_dfs_referral(connection_struct *orig_conn,
1150 const char *dfs_path,
1151 int max_referral_level,
1152 char **ppdata, NTSTATUS *pstatus)
1154 char *pdata = *ppdata;
1155 int reply_size = 0;
1156 struct dfs_GetDFSReferral *r;
1157 DATA_BLOB blob = data_blob_null;
1158 NTSTATUS status;
1159 enum ndr_err_code ndr_err;
1161 r = talloc_zero(talloc_tos(), struct dfs_GetDFSReferral);
1162 if (r == NULL) {
1163 *pstatus = NT_STATUS_NO_MEMORY;
1164 return -1;
1167 r->in.req.max_referral_level = max_referral_level;
1168 r->in.req.servername = talloc_strdup(r, dfs_path);
1169 if (r->in.req.servername == NULL) {
1170 talloc_free(r);
1171 *pstatus = NT_STATUS_NO_MEMORY;
1172 return -1;
1175 status = SMB_VFS_GET_DFS_REFERRALS(orig_conn, r);
1176 if (!NT_STATUS_IS_OK(status)) {
1177 talloc_free(r);
1178 *pstatus = status;
1179 return -1;
1182 ndr_err = ndr_push_struct_blob(&blob, r,
1183 r->out.resp,
1184 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1185 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1186 TALLOC_FREE(r);
1187 *pstatus = NT_STATUS_INVALID_PARAMETER;
1188 return -1;
1191 pdata = (char *)SMB_REALLOC(pdata, blob.length);
1192 if(pdata == NULL) {
1193 TALLOC_FREE(r);
1194 DEBUG(0,("referral setup:"
1195 "malloc failed for Realloc!\n"));
1196 return -1;
1198 *ppdata = pdata;
1199 reply_size = blob.length;
1200 memcpy(pdata, blob.data, blob.length);
1201 TALLOC_FREE(r);
1203 *pstatus = NT_STATUS_OK;
1204 return reply_size;
1207 /**********************************************************************
1208 The following functions are called by the NETDFS RPC pipe functions
1209 **********************************************************************/
1211 /*********************************************************************
1212 Creates a junction structure from a DFS pathname
1213 **********************************************************************/
1215 bool create_junction(TALLOC_CTX *ctx,
1216 const char *dfs_path,
1217 bool allow_broken_path,
1218 struct junction_map *jucn)
1220 int snum;
1221 bool dummy;
1222 struct dfs_path *pdp = talloc(ctx,struct dfs_path);
1223 NTSTATUS status;
1225 if (!pdp) {
1226 return False;
1228 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1229 pdp, &dummy);
1230 if (!NT_STATUS_IS_OK(status)) {
1231 return False;
1234 /* check if path is dfs : validate first token */
1235 if (!is_myname_or_ipaddr(pdp->hostname)) {
1236 DEBUG(4,("create_junction: Invalid hostname %s "
1237 "in dfs path %s\n",
1238 pdp->hostname, dfs_path));
1239 TALLOC_FREE(pdp);
1240 return False;
1243 /* Check for a non-DFS share */
1244 snum = lp_servicenumber(pdp->servicename);
1246 if(snum < 0 || !lp_msdfs_root(snum)) {
1247 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1248 pdp->servicename));
1249 TALLOC_FREE(pdp);
1250 return False;
1253 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1254 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1255 jucn->comment = lp_comment(ctx, snum);
1257 TALLOC_FREE(pdp);
1258 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1259 return False;
1261 return True;
1264 /**********************************************************************
1265 Forms a valid Unix pathname from the junction
1266 **********************************************************************/
1268 static bool junction_to_local_path(const struct junction_map *jucn,
1269 char **pp_path_out,
1270 connection_struct **conn_out,
1271 char **oldpath)
1273 int snum;
1274 NTSTATUS status;
1276 snum = lp_servicenumber(jucn->service_name);
1277 if(snum < 0) {
1278 return False;
1280 status = create_conn_struct_cwd(talloc_tos(),
1281 server_event_context(),
1282 server_messaging_context(),
1283 conn_out,
1284 snum, lp_path(talloc_tos(), snum), NULL, oldpath);
1285 if (!NT_STATUS_IS_OK(status)) {
1286 return False;
1289 *pp_path_out = talloc_asprintf(*conn_out,
1290 "%s/%s",
1291 lp_path(talloc_tos(), snum),
1292 jucn->volume_name);
1293 if (!*pp_path_out) {
1294 vfs_ChDir(*conn_out, *oldpath);
1295 SMB_VFS_DISCONNECT(*conn_out);
1296 conn_free(*conn_out);
1297 return False;
1299 return True;
1302 bool create_msdfs_link(const struct junction_map *jucn)
1304 char *path = NULL;
1305 char *cwd;
1306 char *msdfs_link = NULL;
1307 connection_struct *conn;
1308 int i=0;
1309 bool insert_comma = False;
1310 bool ret = False;
1312 if(!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1313 return False;
1316 /* Form the msdfs_link contents */
1317 msdfs_link = talloc_strdup(conn, "msdfs:");
1318 if (!msdfs_link) {
1319 goto out;
1321 for(i=0; i<jucn->referral_count; i++) {
1322 char *refpath = jucn->referral_list[i].alternate_path;
1324 /* Alternate paths always use Windows separators. */
1325 trim_char(refpath, '\\', '\\');
1326 if(*refpath == '\0') {
1327 if (i == 0) {
1328 insert_comma = False;
1330 continue;
1332 if (i > 0 && insert_comma) {
1333 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1334 ",%s",
1335 refpath);
1336 } else {
1337 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1338 "%s",
1339 refpath);
1342 if (!msdfs_link) {
1343 goto out;
1345 if (!insert_comma) {
1346 insert_comma = True;
1350 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1351 path, msdfs_link));
1353 if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1354 if (errno == EEXIST) {
1355 struct smb_filename *smb_fname;
1357 smb_fname = synthetic_smb_fname(talloc_tos(),
1358 path,
1359 NULL,
1360 NULL,
1362 if (smb_fname == NULL) {
1363 errno = ENOMEM;
1364 goto out;
1367 if(SMB_VFS_UNLINK(conn, smb_fname)!=0) {
1368 TALLOC_FREE(smb_fname);
1369 goto out;
1371 TALLOC_FREE(smb_fname);
1373 if (SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1374 DEBUG(1,("create_msdfs_link: symlink failed "
1375 "%s -> %s\nError: %s\n",
1376 path, msdfs_link, strerror(errno)));
1377 goto out;
1381 ret = True;
1383 out:
1384 vfs_ChDir(conn, cwd);
1385 SMB_VFS_DISCONNECT(conn);
1386 conn_free(conn);
1387 return ret;
1390 bool remove_msdfs_link(const struct junction_map *jucn)
1392 char *path = NULL;
1393 char *cwd;
1394 connection_struct *conn;
1395 bool ret = False;
1396 struct smb_filename *smb_fname;
1398 if (!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1399 return false;
1402 smb_fname = synthetic_smb_fname(talloc_tos(),
1403 path,
1404 NULL,
1405 NULL,
1407 if (smb_fname == NULL) {
1408 errno = ENOMEM;
1409 return false;
1412 if( SMB_VFS_UNLINK(conn, smb_fname) == 0 ) {
1413 ret = True;
1416 TALLOC_FREE(smb_fname);
1417 vfs_ChDir(conn, cwd);
1418 SMB_VFS_DISCONNECT(conn);
1419 conn_free(conn);
1420 return ret;
1423 /*********************************************************************
1424 Return the number of DFS links at the root of this share.
1425 *********************************************************************/
1427 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1429 size_t cnt = 0;
1430 DIR *dirp = NULL;
1431 const char *dname = NULL;
1432 char *talloced = NULL;
1433 const char *connect_path = lp_path(talloc_tos(), snum);
1434 const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum);
1435 connection_struct *conn;
1436 NTSTATUS status;
1437 char *cwd;
1438 struct smb_filename *smb_fname = NULL;
1440 if(*connect_path == '\0') {
1441 return 0;
1445 * Fake up a connection struct for the VFS layer.
1448 status = create_conn_struct_cwd(talloc_tos(),
1449 server_event_context(),
1450 server_messaging_context(),
1451 &conn,
1452 snum, connect_path, NULL, &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 /* Count a link for the msdfs root - convention */
1460 cnt = 1;
1462 /* No more links if this is an msdfs proxy. */
1463 if (*msdfs_proxy != '\0') {
1464 goto out;
1467 smb_fname = synthetic_smb_fname(talloc_tos(),
1468 ".",
1469 NULL,
1470 NULL,
1472 if (smb_fname == NULL) {
1473 goto out;
1476 /* Now enumerate all dfs links */
1477 dirp = SMB_VFS_OPENDIR(conn, smb_fname, NULL, 0);
1478 if(!dirp) {
1479 goto out;
1482 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1483 != NULL) {
1484 if (is_msdfs_link(conn,
1485 dname,
1486 NULL)) {
1487 cnt++;
1489 TALLOC_FREE(talloced);
1492 SMB_VFS_CLOSEDIR(conn,dirp);
1494 out:
1495 TALLOC_FREE(smb_fname);
1496 vfs_ChDir(conn, cwd);
1497 SMB_VFS_DISCONNECT(conn);
1498 conn_free(conn);
1499 return cnt;
1502 /*********************************************************************
1503 *********************************************************************/
1505 static int form_junctions(TALLOC_CTX *ctx,
1506 int snum,
1507 struct junction_map *jucn,
1508 size_t jn_remain)
1510 size_t cnt = 0;
1511 DIR *dirp = NULL;
1512 const char *dname = NULL;
1513 char *talloced = NULL;
1514 const char *connect_path = lp_path(talloc_tos(), snum);
1515 char *service_name = lp_servicename(talloc_tos(), snum);
1516 const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum);
1517 connection_struct *conn;
1518 struct referral *ref = NULL;
1519 char *cwd;
1520 struct smb_filename *smb_fname = NULL;
1521 NTSTATUS status;
1523 if (jn_remain == 0) {
1524 return 0;
1527 if(*connect_path == '\0') {
1528 return 0;
1532 * Fake up a connection struct for the VFS layer.
1535 status = create_conn_struct_cwd(ctx,
1536 server_event_context(),
1537 server_messaging_context(),
1538 &conn, snum, connect_path, NULL,
1539 &cwd);
1540 if (!NT_STATUS_IS_OK(status)) {
1541 DEBUG(3, ("create_conn_struct failed: %s\n",
1542 nt_errstr(status)));
1543 return 0;
1546 /* form a junction for the msdfs root - convention
1547 DO NOT REMOVE THIS: NT clients will not work with us
1548 if this is not present
1550 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1551 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1552 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1553 goto out;
1555 jucn[cnt].comment = "";
1556 jucn[cnt].referral_count = 1;
1558 ref = jucn[cnt].referral_list = talloc_zero(ctx, struct referral);
1559 if (jucn[cnt].referral_list == NULL) {
1560 goto out;
1563 ref->proximity = 0;
1564 ref->ttl = REFERRAL_TTL;
1565 if (*msdfs_proxy != '\0') {
1566 ref->alternate_path = talloc_strdup(ctx,
1567 msdfs_proxy);
1568 } else {
1569 ref->alternate_path = talloc_asprintf(ctx,
1570 "\\\\%s\\%s",
1571 get_local_machine_name(),
1572 service_name);
1575 if (!ref->alternate_path) {
1576 goto out;
1578 cnt++;
1580 /* Don't enumerate if we're an msdfs proxy. */
1581 if (*msdfs_proxy != '\0') {
1582 goto out;
1585 smb_fname = synthetic_smb_fname(talloc_tos(),
1586 ".",
1587 NULL,
1588 NULL,
1590 if (smb_fname == NULL) {
1591 goto out;
1594 /* Now enumerate all dfs links */
1595 dirp = SMB_VFS_OPENDIR(conn, smb_fname, NULL, 0);
1596 if(!dirp) {
1597 goto out;
1600 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1601 != NULL) {
1602 char *link_target = NULL;
1603 if (cnt >= jn_remain) {
1604 DEBUG(2, ("form_junctions: ran out of MSDFS "
1605 "junction slots"));
1606 TALLOC_FREE(talloced);
1607 goto out;
1609 if (is_msdfs_link_internal(ctx,
1610 conn,
1611 dname, &link_target,
1612 NULL)) {
1613 if (parse_msdfs_symlink(ctx, snum,
1614 link_target,
1615 &jucn[cnt].referral_list,
1616 &jucn[cnt].referral_count)) {
1618 jucn[cnt].service_name = talloc_strdup(ctx,
1619 service_name);
1620 jucn[cnt].volume_name = talloc_strdup(ctx,
1621 dname);
1622 if (!jucn[cnt].service_name ||
1623 !jucn[cnt].volume_name) {
1624 TALLOC_FREE(talloced);
1625 goto out;
1627 jucn[cnt].comment = "";
1628 cnt++;
1630 TALLOC_FREE(link_target);
1632 TALLOC_FREE(talloced);
1635 out:
1637 if (dirp) {
1638 SMB_VFS_CLOSEDIR(conn,dirp);
1641 TALLOC_FREE(smb_fname);
1642 vfs_ChDir(conn, cwd);
1643 conn_free(conn);
1644 return cnt;
1647 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1649 struct junction_map *jn = NULL;
1650 int i=0;
1651 size_t jn_count = 0;
1652 int sharecount = 0;
1654 *p_num_jn = 0;
1655 if(!lp_host_msdfs()) {
1656 return NULL;
1659 /* Ensure all the usershares are loaded. */
1660 become_root();
1661 load_registry_shares();
1662 sharecount = load_usershare_shares(NULL, connections_snum_used);
1663 unbecome_root();
1665 for(i=0;i < sharecount;i++) {
1666 if(lp_msdfs_root(i)) {
1667 jn_count += count_dfs_links(ctx, i);
1670 if (jn_count == 0) {
1671 return NULL;
1673 jn = talloc_array(ctx, struct junction_map, jn_count);
1674 if (!jn) {
1675 return NULL;
1677 for(i=0; i < sharecount; i++) {
1678 if (*p_num_jn >= jn_count) {
1679 break;
1681 if(lp_msdfs_root(i)) {
1682 *p_num_jn += form_junctions(ctx, i,
1683 &jn[*p_num_jn],
1684 jn_count - *p_num_jn);
1687 return jn;
1690 /******************************************************************************
1691 Core function to resolve a dfs pathname possibly containing a wildcard. If
1692 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1693 detected during dfs resolution.
1694 ******************************************************************************/
1696 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1697 connection_struct *conn,
1698 bool dfs_pathnames,
1699 const char *name_in,
1700 uint32_t ucf_flags,
1701 bool allow_broken_path,
1702 char **pp_name_out,
1703 bool *ppath_contains_wcard)
1705 bool path_contains_wcard;
1706 NTSTATUS status = NT_STATUS_OK;
1708 if (dfs_pathnames) {
1709 status = dfs_redirect(ctx,
1710 conn,
1711 name_in,
1712 ucf_flags,
1713 allow_broken_path,
1714 pp_name_out,
1715 &path_contains_wcard);
1717 if (NT_STATUS_IS_OK(status) && ppath_contains_wcard != NULL) {
1718 *ppath_contains_wcard = path_contains_wcard;
1720 } else {
1722 * Cheat and just return a copy of the in ptr.
1723 * Once srvstr_get_path() uses talloc it'll
1724 * be a talloced ptr anyway.
1726 *pp_name_out = discard_const_p(char, name_in);
1728 return status;