smbdotconf: mark "comment" with substitution="1"
[Samba.git] / source3 / smbd / msdfs.c
blob7ef368240d5ce8d8c413e45f6756016a3a3630bd
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 "../auth/auth_util.h"
32 #include "lib/param/loadparm.h"
33 #include "libcli/security/security.h"
34 #include "librpc/gen_ndr/ndr_dfsblobs.h"
35 #include "lib/tsocket/tsocket.h"
37 /**********************************************************************
38 Parse a DFS pathname of the form \hostname\service\reqpath
39 into the dfs_path structure.
40 If POSIX pathnames is true, the pathname may also be of the
41 form /hostname/service/reqpath.
42 We cope with either here.
44 Unfortunately, due to broken clients who might set the
45 SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
46 send a local path, we have to cope with that too....
48 If conn != NULL then ensure the provided service is
49 the one pointed to by the connection.
51 This version does everything using pointers within one copy of the
52 pathname string, talloced on the struct dfs_path pointer (which
53 must be talloced). This may be too clever to live....
54 JRA.
55 **********************************************************************/
57 static NTSTATUS parse_dfs_path(connection_struct *conn,
58 const char *pathname,
59 bool allow_wcards,
60 bool allow_broken_path,
61 struct dfs_path *pdp, /* MUST BE TALLOCED */
62 bool *ppath_contains_wcard)
64 char *pathname_local;
65 char *p,*temp;
66 char *servicename;
67 char *eos_ptr;
68 NTSTATUS status = NT_STATUS_OK;
69 char sepchar;
71 ZERO_STRUCTP(pdp);
74 * This is the only talloc we should need to do
75 * on the struct dfs_path. All the pointers inside
76 * it should point to offsets within this string.
79 pathname_local = talloc_strdup(pdp, pathname);
80 if (!pathname_local) {
81 return NT_STATUS_NO_MEMORY;
83 /* Get a pointer to the terminating '\0' */
84 eos_ptr = &pathname_local[strlen(pathname_local)];
85 p = temp = pathname_local;
88 * Non-broken DFS paths *must* start with the
89 * path separator. For Windows this is always '\\',
90 * for posix paths this is always '/'.
93 if (*pathname == '/') {
94 pdp->posix_path = true;
95 sepchar = '/';
96 } else {
97 pdp->posix_path = false;
98 sepchar = '\\';
101 if (allow_broken_path && (*pathname != sepchar)) {
102 DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
103 pathname, sepchar ));
105 * Possibly client sent a local path by mistake.
106 * Try and convert to a local path.
107 * Note that this is an SMB1-only fallback
108 * to cope with known broken SMB1 clients.
111 pdp->hostname = eos_ptr; /* "" */
112 pdp->servicename = eos_ptr; /* "" */
114 /* We've got no info about separators. */
115 pdp->posix_path = lp_posix_pathnames();
116 p = temp;
117 DEBUG(10,("parse_dfs_path: trying to convert %s to a "
118 "local path\n",
119 temp));
120 goto local_path;
124 * Safe to use on talloc'ed string as it only shrinks.
125 * It also doesn't affect the eos_ptr.
127 trim_char(temp,sepchar,sepchar);
129 DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
130 temp, sepchar));
132 /* Now tokenize. */
133 /* Parse out hostname. */
134 p = strchr_m(temp,sepchar);
135 if(p == NULL) {
136 DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
137 temp));
139 * Possibly client sent a local path by mistake.
140 * Try and convert to a local path.
143 pdp->hostname = eos_ptr; /* "" */
144 pdp->servicename = eos_ptr; /* "" */
146 p = temp;
147 DEBUG(10,("parse_dfs_path: trying to convert %s "
148 "to a local path\n",
149 temp));
150 goto local_path;
152 *p = '\0';
153 pdp->hostname = temp;
155 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
157 /* Parse out servicename. */
158 servicename = p+1;
159 p = strchr_m(servicename,sepchar);
160 if (p) {
161 *p = '\0';
164 /* Is this really our servicename ? */
165 if (conn && !( strequal(servicename, lp_servicename(talloc_tos(), SNUM(conn)))
166 || (strequal(servicename, HOMES_NAME)
167 && strequal(lp_servicename(talloc_tos(), SNUM(conn)),
168 get_current_username()) )) ) {
169 DEBUG(10,("parse_dfs_path: %s is not our servicename\n",
170 servicename));
173 * Possibly client sent a local path by mistake.
174 * Try and convert to a local path.
177 pdp->hostname = eos_ptr; /* "" */
178 pdp->servicename = eos_ptr; /* "" */
180 /* Repair the path - replace the sepchar's
181 we nulled out */
182 servicename--;
183 *servicename = sepchar;
184 if (p) {
185 *p = sepchar;
188 p = temp;
189 DEBUG(10,("parse_dfs_path: trying to convert %s "
190 "to a local path\n",
191 temp));
192 goto local_path;
195 pdp->servicename = servicename;
197 DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
199 if(p == NULL) {
200 /* Client sent self referral \server\share. */
201 pdp->reqpath = eos_ptr; /* "" */
202 return NT_STATUS_OK;
205 p++;
207 local_path:
209 *ppath_contains_wcard = False;
211 pdp->reqpath = p;
213 /* Rest is reqpath. */
214 if (pdp->posix_path) {
215 status = check_path_syntax_posix(pdp->reqpath);
216 } else {
217 if (allow_wcards) {
218 status = check_path_syntax_wcard(pdp->reqpath,
219 ppath_contains_wcard);
220 } else {
221 status = check_path_syntax(pdp->reqpath);
225 if (!NT_STATUS_IS_OK(status)) {
226 DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
227 p, nt_errstr(status) ));
228 return status;
231 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
232 return NT_STATUS_OK;
235 /********************************************************
236 Fake up a connection struct for the VFS layer, for use in
237 applications (such as the python bindings), that do not want the
238 global working directory changed under them.
240 SMB_VFS_CONNECT requires root privileges.
241 *********************************************************/
243 static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx,
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 = samba_tevent_context_init(sconn);
262 if (sconn->ev_ctx == NULL) {
263 TALLOC_FREE(sconn);
264 return NT_STATUS_NO_MEMORY;
267 sconn->msg_ctx = msg;
269 conn = conn_new(sconn);
270 if (conn == NULL) {
271 TALLOC_FREE(sconn);
272 return NT_STATUS_NO_MEMORY;
275 /* Now we have conn, we need to make sconn a child of conn,
276 * for a proper talloc tree */
277 talloc_steal(conn, sconn);
279 if (snum == -1 && servicename == NULL) {
280 servicename = "Unknown Service (snum == -1)";
283 connpath = talloc_strdup(conn, path);
284 if (!connpath) {
285 TALLOC_FREE(conn);
286 return NT_STATUS_NO_MEMORY;
288 connpath = talloc_string_sub(conn,
289 connpath,
290 "%S",
291 servicename);
292 if (!connpath) {
293 TALLOC_FREE(conn);
294 return NT_STATUS_NO_MEMORY;
297 /* needed for smbd_vfs_init() */
299 conn->params->service = snum;
300 conn->cnum = TID_FIELD_INVALID;
302 if (session_info != NULL) {
303 conn->session_info = copy_session_info(conn, session_info);
304 if (conn->session_info == NULL) {
305 DEBUG(0, ("copy_serverinfo failed\n"));
306 TALLOC_FREE(conn);
307 return NT_STATUS_NO_MEMORY;
309 /* unix_info could be NULL in session_info */
310 if (conn->session_info->unix_info != NULL) {
311 vfs_user = conn->session_info->unix_info->unix_name;
312 } else {
313 vfs_user = get_current_username();
315 } else {
316 /* use current authenticated user in absence of session_info */
317 vfs_user = get_current_username();
320 set_conn_connectpath(conn, connpath);
323 * New code to check if there's a share security descriptor
324 * added from NT server manager. This is done after the
325 * smb.conf checks are done as we need a uid and token. JRA.
328 if (conn->session_info) {
329 share_access_check(conn->session_info->security_token,
330 servicename,
331 MAXIMUM_ALLOWED_ACCESS,
332 &conn->share_access);
334 if ((conn->share_access & FILE_WRITE_DATA) == 0) {
335 if ((conn->share_access & FILE_READ_DATA) == 0) {
336 /* No access, read or write. */
337 DEBUG(3,("create_conn_struct: connection to %s "
338 "denied due to security "
339 "descriptor.\n",
340 servicename));
341 conn_free(conn);
342 return NT_STATUS_ACCESS_DENIED;
343 } else {
344 conn->read_only = true;
347 } else {
348 conn->share_access = 0;
349 conn->read_only = true;
352 if (!smbd_vfs_init(conn)) {
353 NTSTATUS status = map_nt_error_from_unix(errno);
354 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
355 conn_free(conn);
356 return status;
359 /* this must be the first filesystem operation that we do */
360 if (SMB_VFS_CONNECT(conn, servicename, vfs_user) < 0) {
361 DEBUG(0,("VFS connect failed!\n"));
362 conn_free(conn);
363 return NT_STATUS_UNSUCCESSFUL;
366 talloc_free(conn->origpath);
367 conn->origpath = talloc_strdup(conn, conn->connectpath);
368 if (conn->origpath == NULL) {
369 conn_free(conn);
370 return NT_STATUS_NO_MEMORY;
373 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
374 conn->tcon_done = true;
375 *pconn = talloc_move(ctx, &conn);
377 return NT_STATUS_OK;
380 static int conn_struct_tos_destructor(struct conn_struct_tos *c)
382 if (c->oldcwd_fname != NULL) {
383 vfs_ChDir(c->conn, c->oldcwd_fname);
384 TALLOC_FREE(c->oldcwd_fname);
386 SMB_VFS_DISCONNECT(c->conn);
387 conn_free(c->conn);
388 return 0;
391 /********************************************************
392 Fake up a connection struct for the VFS layer, for use in
393 applications (such as the python bindings), that do not want the
394 global working directory changed under them.
396 SMB_VFS_CONNECT requires root privileges.
397 This temporary uses become_root() and unbecome_root().
399 But further impersonation has to be cone by the caller.
400 *********************************************************/
401 NTSTATUS create_conn_struct_tos(struct messaging_context *msg,
402 int snum,
403 const char *path,
404 const struct auth_session_info *session_info,
405 struct conn_struct_tos **_c)
407 struct conn_struct_tos *c = NULL;
408 NTSTATUS status;
410 *_c = NULL;
412 c = talloc_zero(talloc_tos(), struct conn_struct_tos);
413 if (c == NULL) {
414 return NT_STATUS_NO_MEMORY;
417 become_root();
418 status = create_conn_struct_as_root(c,
419 msg,
420 &c->conn,
421 snum,
422 path,
423 session_info);
424 unbecome_root();
425 if (!NT_STATUS_IS_OK(status)) {
426 TALLOC_FREE(c);
427 return status;
430 talloc_set_destructor(c, conn_struct_tos_destructor);
432 *_c = c;
433 return NT_STATUS_OK;
436 /********************************************************
437 Fake up a connection struct for the VFS layer.
438 Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
440 See also the comment for create_conn_struct_tos() above!
442 The CWD change is reverted by the destructor of
443 conn_struct_tos when the current talloc_tos() is destroyed.
444 *********************************************************/
445 NTSTATUS create_conn_struct_tos_cwd(struct messaging_context *msg,
446 int snum,
447 const char *path,
448 const struct auth_session_info *session_info,
449 struct conn_struct_tos **_c)
451 struct conn_struct_tos *c = NULL;
452 struct smb_filename smb_fname_connectpath = {0};
453 NTSTATUS status;
455 *_c = NULL;
457 status = create_conn_struct_tos(msg,
458 snum,
459 path,
460 session_info,
461 &c);
462 if (!NT_STATUS_IS_OK(status)) {
463 return status;
467 * Windows seems to insist on doing trans2getdfsreferral() calls on
468 * the IPC$ share as the anonymous user. If we try to chdir as that
469 * user we will fail.... WTF ? JRA.
472 c->oldcwd_fname = vfs_GetWd(c, c->conn);
473 if (c->oldcwd_fname == NULL) {
474 status = map_nt_error_from_unix(errno);
475 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
476 TALLOC_FREE(c);
477 return status;
480 smb_fname_connectpath = (struct smb_filename) {
481 .base_name = c->conn->connectpath
484 if (vfs_ChDir(c->conn, &smb_fname_connectpath) != 0) {
485 status = map_nt_error_from_unix(errno);
486 DBG_NOTICE("Can't ChDir to new conn path %s. "
487 "Error was %s\n",
488 c->conn->connectpath, strerror(errno));
489 TALLOC_FREE(c->oldcwd_fname);
490 TALLOC_FREE(c);
491 return status;
494 *_c = c;
495 return NT_STATUS_OK;
498 static void shuffle_strlist(char **list, int count)
500 int i;
501 uint32_t r;
502 char *tmp;
504 for (i = count; i > 1; i--) {
505 r = generate_random() % i;
507 tmp = list[i-1];
508 list[i-1] = list[r];
509 list[r] = tmp;
513 /**********************************************************************
514 Parse the contents of a symlink to verify if it is an msdfs referral
515 A valid referral is of the form:
517 msdfs:server1\share1,server2\share2
518 msdfs:server1\share1\pathname,server2\share2\pathname
519 msdfs:server1/share1,server2/share2
520 msdfs:server1/share1/pathname,server2/share2/pathname.
522 Note that the alternate paths returned here must be of the canonicalized
523 form:
525 \server\share or
526 \server\share\path\to\file,
528 even in posix path mode. This is because we have no knowledge if the
529 server we're referring to understands posix paths.
530 **********************************************************************/
532 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
533 int snum,
534 const char *target,
535 struct referral **preflist,
536 int *refcount)
538 char *temp = NULL;
539 char *prot;
540 char **alt_path = NULL;
541 int count = 0, i;
542 struct referral *reflist;
543 char *saveptr;
545 temp = talloc_strdup(ctx, target);
546 if (!temp) {
547 return False;
549 prot = strtok_r(temp, ":", &saveptr);
550 if (!prot) {
551 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
552 return False;
555 alt_path = talloc_array(ctx, char *, MAX_REFERRAL_COUNT);
556 if (!alt_path) {
557 return False;
560 /* parse out the alternate paths */
561 while((count<MAX_REFERRAL_COUNT) &&
562 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
563 count++;
566 /* shuffle alternate paths */
567 if (lp_msdfs_shuffle_referrals(snum)) {
568 shuffle_strlist(alt_path, count);
571 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
573 if (count) {
574 reflist = *preflist = talloc_zero_array(ctx,
575 struct referral, count);
576 if(reflist == NULL) {
577 TALLOC_FREE(alt_path);
578 return False;
580 } else {
581 reflist = *preflist = NULL;
584 for(i=0;i<count;i++) {
585 char *p;
587 /* Canonicalize link target.
588 * Replace all /'s in the path by a \ */
589 string_replace(alt_path[i], '/', '\\');
591 /* Remove leading '\\'s */
592 p = alt_path[i];
593 while (*p && (*p == '\\')) {
594 p++;
597 reflist[i].alternate_path = talloc_asprintf(ctx,
598 "\\%s",
600 if (!reflist[i].alternate_path) {
601 return False;
604 reflist[i].proximity = 0;
605 reflist[i].ttl = REFERRAL_TTL;
606 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
607 reflist[i].alternate_path));
610 *refcount = count;
612 TALLOC_FREE(alt_path);
613 return True;
616 /**********************************************************************
617 Returns true if the unix path is a valid msdfs symlink and also
618 returns the target string from inside the link.
619 **********************************************************************/
621 static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
622 connection_struct *conn,
623 struct smb_filename *smb_fname,
624 char **pp_link_target)
626 int referral_len = 0;
627 #if defined(HAVE_BROKEN_READLINK)
628 char link_target_buf[PATH_MAX];
629 #else
630 char link_target_buf[7];
631 #endif
632 size_t bufsize = 0;
633 char *link_target = NULL;
635 if (pp_link_target) {
636 bufsize = 1024;
637 link_target = talloc_array(ctx, char, bufsize);
638 if (!link_target) {
639 return False;
641 *pp_link_target = link_target;
642 } else {
643 bufsize = sizeof(link_target_buf);
644 link_target = link_target_buf;
647 if (SMB_VFS_LSTAT(conn, smb_fname) != 0) {
648 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
649 smb_fname->base_name));
650 goto err;
652 if (!S_ISLNK(smb_fname->st.st_ex_mode)) {
653 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
654 smb_fname->base_name));
655 goto err;
658 referral_len = SMB_VFS_READLINKAT(conn,
659 conn->cwd_fsp,
660 smb_fname,
661 link_target,
662 bufsize - 1);
664 if (referral_len == -1) {
665 DEBUG(0,("is_msdfs_link_read_target: Error reading "
666 "msdfs link %s: %s\n",
667 smb_fname->base_name, strerror(errno)));
668 goto err;
670 link_target[referral_len] = '\0';
672 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n", smb_fname->base_name,
673 link_target));
675 if (!strnequal(link_target, "msdfs:", 6)) {
676 goto err;
678 return True;
680 err:
682 if (link_target != link_target_buf) {
683 TALLOC_FREE(link_target);
685 return False;
688 /**********************************************************************
689 Returns true if the unix path is a valid msdfs symlink.
690 **********************************************************************/
692 bool is_msdfs_link(connection_struct *conn,
693 struct smb_filename *smb_fname)
695 return is_msdfs_link_internal(talloc_tos(),
696 conn,
697 smb_fname,
698 NULL);
701 /*****************************************************************
702 Used by other functions to decide if a dfs path is remote,
703 and to get the list of referred locations for that remote path.
705 search_flag: For findfirsts, dfs links themselves are not
706 redirected, but paths beyond the links are. For normal smb calls,
707 even dfs links need to be redirected.
709 consumedcntp: how much of the dfs path is being redirected. the client
710 should try the remaining path on the redirected server.
712 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
713 link redirect are in targetpath.
714 *****************************************************************/
716 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
717 connection_struct *conn,
718 const char *dfspath, /* Incoming complete dfs path */
719 const struct dfs_path *pdp, /* Parsed out
720 server+share+extrapath. */
721 uint32_t ucf_flags,
722 int *consumedcntp,
723 char **pp_targetpath)
725 char *p = NULL;
726 char *q = NULL;
727 NTSTATUS status;
728 struct smb_filename *smb_fname = NULL;
729 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
730 components). */
732 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
733 conn->connectpath, pdp->reqpath));
736 * Note the unix path conversion here we're doing we
737 * throw away. We're looking for a symlink for a dfs
738 * resolution, if we don't find it we'll do another
739 * unix_convert later in the codepath.
742 status = unix_convert(ctx, conn, pdp->reqpath, &smb_fname,
743 ucf_flags);
745 if (!NT_STATUS_IS_OK(status)) {
746 if (!NT_STATUS_EQUAL(status,
747 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
748 return status;
750 if (smb_fname == NULL || smb_fname->base_name == NULL) {
751 return status;
755 /* Optimization - check if we can redirect the whole path. */
757 if (is_msdfs_link_internal(ctx, conn, smb_fname, pp_targetpath)) {
758 /* XX_ALLOW_WCARD_XXX is called from search functions. */
759 if (ucf_flags &
760 (UCF_COND_ALLOW_WCARD_LCOMP|
761 UCF_ALWAYS_ALLOW_WCARD_LCOMP)) {
762 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
763 "for dfs link %s.\n", dfspath));
764 status = NT_STATUS_OK;
765 goto out;
768 DEBUG(6,("dfs_path_lookup: %s resolves to a "
769 "valid dfs link %s.\n", dfspath,
770 pp_targetpath ? *pp_targetpath : ""));
772 if (consumedcntp) {
773 *consumedcntp = strlen(dfspath);
775 status = NT_STATUS_PATH_NOT_COVERED;
776 goto out;
779 /* Prepare to test only for '/' components in the given path,
780 * so if a Windows path replace all '\\' characters with '/'.
781 * For a POSIX DFS path we know all separators are already '/'. */
783 canon_dfspath = talloc_strdup(ctx, dfspath);
784 if (!canon_dfspath) {
785 status = NT_STATUS_NO_MEMORY;
786 goto out;
788 if (!pdp->posix_path) {
789 string_replace(canon_dfspath, '\\', '/');
793 * localpath comes out of unix_convert, so it has
794 * no trailing backslash. Make sure that canon_dfspath hasn't either.
795 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
798 trim_char(canon_dfspath,0,'/');
801 * Redirect if any component in the path is a link.
802 * We do this by walking backwards through the
803 * local path, chopping off the last component
804 * in both the local path and the canonicalized
805 * DFS path. If we hit a DFS link then we're done.
808 p = strrchr_m(smb_fname->base_name, '/');
809 if (consumedcntp) {
810 q = strrchr_m(canon_dfspath, '/');
813 while (p) {
814 *p = '\0';
815 if (q) {
816 *q = '\0';
819 if (is_msdfs_link_internal(ctx, conn,
820 smb_fname, pp_targetpath)) {
821 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
822 "parent %s is dfs link\n", dfspath,
823 smb_fname_str_dbg(smb_fname)));
825 if (consumedcntp) {
826 *consumedcntp = strlen(canon_dfspath);
827 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
828 "(%d)\n",
829 canon_dfspath,
830 *consumedcntp));
833 status = NT_STATUS_PATH_NOT_COVERED;
834 goto out;
837 /* Step back on the filesystem. */
838 p = strrchr_m(smb_fname->base_name, '/');
840 if (consumedcntp) {
841 /* And in the canonicalized dfs path. */
842 q = strrchr_m(canon_dfspath, '/');
846 status = NT_STATUS_OK;
847 out:
848 TALLOC_FREE(smb_fname);
849 return status;
852 /*****************************************************************
853 Decides if a dfs pathname should be redirected or not.
854 If not, the pathname is converted to a tcon-relative local unix path
856 search_wcard_flag: this flag performs 2 functions both related
857 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
858 for details.
860 This function can return NT_STATUS_OK, meaning use the returned path as-is
861 (mapped into a local path).
862 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
863 any other NT_STATUS error which is a genuine error to be
864 returned to the client.
865 *****************************************************************/
867 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
868 connection_struct *conn,
869 const char *path_in,
870 uint32_t ucf_flags,
871 bool allow_broken_path,
872 char **pp_path_out,
873 bool *ppath_contains_wcard)
875 NTSTATUS status;
876 bool search_wcard_flag = (ucf_flags &
877 (UCF_COND_ALLOW_WCARD_LCOMP|UCF_ALWAYS_ALLOW_WCARD_LCOMP));
878 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
880 if (!pdp) {
881 return NT_STATUS_NO_MEMORY;
884 status = parse_dfs_path(conn, path_in, search_wcard_flag,
885 allow_broken_path, pdp,
886 ppath_contains_wcard);
887 if (!NT_STATUS_IS_OK(status)) {
888 TALLOC_FREE(pdp);
889 return status;
892 if (pdp->reqpath[0] == '\0') {
893 TALLOC_FREE(pdp);
894 *pp_path_out = talloc_strdup(ctx, "");
895 if (!*pp_path_out) {
896 return NT_STATUS_NO_MEMORY;
898 DEBUG(5,("dfs_redirect: self-referral.\n"));
899 return NT_STATUS_OK;
902 /* If dfs pathname for a non-dfs share, convert to tcon-relative
903 path and return OK */
905 if (!lp_msdfs_root(SNUM(conn))) {
906 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
907 TALLOC_FREE(pdp);
908 if (!*pp_path_out) {
909 return NT_STATUS_NO_MEMORY;
911 return NT_STATUS_OK;
914 /* If it looked like a local path (zero hostname/servicename)
915 * just treat as a tcon-relative path. */
917 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
918 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
919 TALLOC_FREE(pdp);
920 if (!*pp_path_out) {
921 return NT_STATUS_NO_MEMORY;
923 return NT_STATUS_OK;
926 if (!( strequal(pdp->servicename, lp_servicename(talloc_tos(), SNUM(conn)))
927 || (strequal(pdp->servicename, HOMES_NAME)
928 && strequal(lp_servicename(talloc_tos(), SNUM(conn)),
929 conn->session_info->unix_info->sanitized_username) )) ) {
931 /* The given sharename doesn't match this connection. */
932 TALLOC_FREE(pdp);
934 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
937 status = dfs_path_lookup(ctx, conn, path_in, pdp,
938 ucf_flags, NULL, NULL);
939 if (!NT_STATUS_IS_OK(status)) {
940 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
941 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
942 } else {
943 DEBUG(10,("dfs_redirect: dfs_path_lookup "
944 "failed for %s with %s\n",
945 path_in, nt_errstr(status) ));
947 return status;
950 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
952 /* Form non-dfs tcon-relative path */
953 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
954 TALLOC_FREE(pdp);
955 if (!*pp_path_out) {
956 return NT_STATUS_NO_MEMORY;
959 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
960 path_in,
961 *pp_path_out));
963 return NT_STATUS_OK;
966 /**********************************************************************
967 Return a self referral.
968 **********************************************************************/
970 static NTSTATUS self_ref(TALLOC_CTX *ctx,
971 const char *dfs_path,
972 struct junction_map *jucn,
973 int *consumedcntp,
974 bool *self_referralp)
976 struct referral *ref;
978 *self_referralp = True;
980 jucn->referral_count = 1;
981 if((ref = talloc_zero(ctx, struct referral)) == NULL) {
982 return NT_STATUS_NO_MEMORY;
985 ref->alternate_path = talloc_strdup(ctx, dfs_path);
986 if (!ref->alternate_path) {
987 TALLOC_FREE(ref);
988 return NT_STATUS_NO_MEMORY;
990 ref->proximity = 0;
991 ref->ttl = REFERRAL_TTL;
992 jucn->referral_list = ref;
993 *consumedcntp = strlen(dfs_path);
994 return NT_STATUS_OK;
997 /**********************************************************************
998 Gets valid referrals for a dfs path and fills up the
999 junction_map structure.
1000 **********************************************************************/
1002 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
1003 const char *dfs_path,
1004 const struct tsocket_address *remote_address,
1005 const struct tsocket_address *local_address,
1006 bool allow_broken_path,
1007 struct junction_map *jucn,
1008 int *consumedcntp,
1009 bool *self_referralp)
1011 TALLOC_CTX *frame = talloc_stackframe();
1012 struct conn_struct_tos *c = NULL;
1013 struct connection_struct *conn = NULL;
1014 char *targetpath = NULL;
1015 int snum;
1016 NTSTATUS status = NT_STATUS_NOT_FOUND;
1017 bool dummy;
1018 struct dfs_path *pdp = talloc_zero(frame, struct dfs_path);
1020 if (!pdp) {
1021 TALLOC_FREE(frame);
1022 return NT_STATUS_NO_MEMORY;
1025 *self_referralp = False;
1027 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1028 pdp, &dummy);
1029 if (!NT_STATUS_IS_OK(status)) {
1030 TALLOC_FREE(frame);
1031 return status;
1034 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1035 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1036 if (!jucn->service_name || !jucn->volume_name) {
1037 TALLOC_FREE(frame);
1038 return NT_STATUS_NO_MEMORY;
1041 /* Verify the share is a dfs root */
1042 snum = lp_servicenumber(jucn->service_name);
1043 if(snum < 0) {
1044 char *service_name = NULL;
1045 if ((snum = find_service(ctx, jucn->service_name, &service_name)) < 0) {
1046 TALLOC_FREE(frame);
1047 return NT_STATUS_NOT_FOUND;
1049 if (!service_name) {
1050 TALLOC_FREE(frame);
1051 return NT_STATUS_NO_MEMORY;
1053 TALLOC_FREE(jucn->service_name);
1054 jucn->service_name = talloc_strdup(ctx, service_name);
1055 if (!jucn->service_name) {
1056 TALLOC_FREE(frame);
1057 return NT_STATUS_NO_MEMORY;
1061 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(talloc_tos(), snum) == '\0')) {
1062 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
1063 "a dfs root.\n",
1064 pdp->servicename, dfs_path));
1065 TALLOC_FREE(frame);
1066 return NT_STATUS_NOT_FOUND;
1070 * Self referrals are tested with a anonymous IPC connection and
1071 * a GET_DFS_REFERRAL call to \\server\share. (which means
1072 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
1073 * into the directory and will fail if it cannot (as the anonymous
1074 * user). Cope with this.
1077 if (pdp->reqpath[0] == '\0') {
1078 char *tmp;
1079 struct referral *ref;
1080 int refcount;
1082 if (*lp_msdfs_proxy(talloc_tos(), snum) == '\0') {
1083 TALLOC_FREE(frame);
1084 return self_ref(ctx,
1085 dfs_path,
1086 jucn,
1087 consumedcntp,
1088 self_referralp);
1092 * It's an msdfs proxy share. Redirect to
1093 * the configured target share.
1096 tmp = talloc_asprintf(frame, "msdfs:%s",
1097 lp_msdfs_proxy(frame, snum));
1098 if (tmp == NULL) {
1099 TALLOC_FREE(frame);
1100 return NT_STATUS_NO_MEMORY;
1103 if (!parse_msdfs_symlink(ctx, snum, tmp, &ref, &refcount)) {
1104 TALLOC_FREE(frame);
1105 return NT_STATUS_INVALID_PARAMETER;
1107 jucn->referral_count = refcount;
1108 jucn->referral_list = ref;
1109 *consumedcntp = strlen(dfs_path);
1110 TALLOC_FREE(frame);
1111 return NT_STATUS_OK;
1114 status = create_conn_struct_tos_cwd(global_messaging_context(),
1115 snum,
1116 lp_path(frame, snum),
1117 NULL,
1118 &c);
1119 if (!NT_STATUS_IS_OK(status)) {
1120 TALLOC_FREE(frame);
1121 return status;
1123 conn = c->conn;
1126 * TODO
1128 * The remote and local address should be passed down to
1129 * create_conn_struct_cwd.
1131 if (conn->sconn->remote_address == NULL) {
1132 conn->sconn->remote_address =
1133 tsocket_address_copy(remote_address, conn->sconn);
1134 if (conn->sconn->remote_address == NULL) {
1135 TALLOC_FREE(frame);
1136 return NT_STATUS_NO_MEMORY;
1139 if (conn->sconn->local_address == NULL) {
1140 conn->sconn->local_address =
1141 tsocket_address_copy(local_address, conn->sconn);
1142 if (conn->sconn->local_address == NULL) {
1143 TALLOC_FREE(frame);
1144 return NT_STATUS_NO_MEMORY;
1148 /* If this is a DFS path dfs_lookup should return
1149 * NT_STATUS_PATH_NOT_COVERED. */
1151 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
1152 0, consumedcntp, &targetpath);
1154 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
1155 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
1156 dfs_path));
1157 if (NT_STATUS_IS_OK(status)) {
1159 * We are in an error path here (we
1160 * know it's not a DFS path), but
1161 * dfs_path_lookup() can return
1162 * NT_STATUS_OK. Ensure we always
1163 * return a valid error code.
1165 * #9588 - ACLs are not inherited to directories
1166 * for DFS shares.
1168 status = NT_STATUS_NOT_FOUND;
1170 goto err_exit;
1173 /* We know this is a valid dfs link. Parse the targetpath. */
1174 if (!parse_msdfs_symlink(ctx, snum, targetpath,
1175 &jucn->referral_list,
1176 &jucn->referral_count)) {
1177 DEBUG(3,("get_referred_path: failed to parse symlink "
1178 "target %s\n", targetpath ));
1179 status = NT_STATUS_NOT_FOUND;
1180 goto err_exit;
1183 status = NT_STATUS_OK;
1184 err_exit:
1185 TALLOC_FREE(frame);
1186 return status;
1189 /******************************************************************
1190 Set up the DFS referral for the dfs pathname. This call returns
1191 the amount of the path covered by this server, and where the
1192 client should be redirected to. This is the meat of the
1193 TRANS2_GET_DFS_REFERRAL call.
1194 ******************************************************************/
1196 int setup_dfs_referral(connection_struct *orig_conn,
1197 const char *dfs_path,
1198 int max_referral_level,
1199 char **ppdata, NTSTATUS *pstatus)
1201 char *pdata = *ppdata;
1202 int reply_size = 0;
1203 struct dfs_GetDFSReferral *r;
1204 DATA_BLOB blob = data_blob_null;
1205 NTSTATUS status;
1206 enum ndr_err_code ndr_err;
1208 r = talloc_zero(talloc_tos(), struct dfs_GetDFSReferral);
1209 if (r == NULL) {
1210 *pstatus = NT_STATUS_NO_MEMORY;
1211 return -1;
1214 r->in.req.max_referral_level = max_referral_level;
1215 r->in.req.servername = talloc_strdup(r, dfs_path);
1216 if (r->in.req.servername == NULL) {
1217 talloc_free(r);
1218 *pstatus = NT_STATUS_NO_MEMORY;
1219 return -1;
1222 status = SMB_VFS_GET_DFS_REFERRALS(orig_conn, r);
1223 if (!NT_STATUS_IS_OK(status)) {
1224 talloc_free(r);
1225 *pstatus = status;
1226 return -1;
1229 ndr_err = ndr_push_struct_blob(&blob, r,
1230 r->out.resp,
1231 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1232 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1233 TALLOC_FREE(r);
1234 *pstatus = NT_STATUS_INVALID_PARAMETER;
1235 return -1;
1238 pdata = (char *)SMB_REALLOC(pdata, blob.length);
1239 if(pdata == NULL) {
1240 TALLOC_FREE(r);
1241 DEBUG(0,("referral setup:"
1242 "malloc failed for Realloc!\n"));
1243 return -1;
1245 *ppdata = pdata;
1246 reply_size = blob.length;
1247 memcpy(pdata, blob.data, blob.length);
1248 TALLOC_FREE(r);
1250 *pstatus = NT_STATUS_OK;
1251 return reply_size;
1254 /**********************************************************************
1255 The following functions are called by the NETDFS RPC pipe functions
1256 **********************************************************************/
1258 /*********************************************************************
1259 Creates a junction structure from a DFS pathname
1260 **********************************************************************/
1262 bool create_junction(TALLOC_CTX *ctx,
1263 const char *dfs_path,
1264 bool allow_broken_path,
1265 struct junction_map *jucn)
1267 const struct loadparm_substitution *lp_sub =
1268 loadparm_s3_global_substitution();
1269 int snum;
1270 bool dummy;
1271 struct dfs_path *pdp = talloc(ctx,struct dfs_path);
1272 NTSTATUS status;
1274 if (!pdp) {
1275 return False;
1277 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1278 pdp, &dummy);
1279 if (!NT_STATUS_IS_OK(status)) {
1280 return False;
1283 /* check if path is dfs : validate first token */
1284 if (!is_myname_or_ipaddr(pdp->hostname)) {
1285 DEBUG(4,("create_junction: Invalid hostname %s "
1286 "in dfs path %s\n",
1287 pdp->hostname, dfs_path));
1288 TALLOC_FREE(pdp);
1289 return False;
1292 /* Check for a non-DFS share */
1293 snum = lp_servicenumber(pdp->servicename);
1295 if(snum < 0 || !lp_msdfs_root(snum)) {
1296 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1297 pdp->servicename));
1298 TALLOC_FREE(pdp);
1299 return False;
1302 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1303 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1304 jucn->comment = lp_comment(ctx, lp_sub, snum);
1306 TALLOC_FREE(pdp);
1307 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1308 return False;
1310 return True;
1313 /**********************************************************************
1314 Forms a valid Unix pathname from the junction
1315 **********************************************************************/
1317 static bool junction_to_local_path_tos(const struct junction_map *jucn,
1318 char **pp_path_out,
1319 connection_struct **conn_out)
1321 struct conn_struct_tos *c = NULL;
1322 int snum;
1323 char *path_out = NULL;
1324 NTSTATUS status;
1326 snum = lp_servicenumber(jucn->service_name);
1327 if(snum < 0) {
1328 return False;
1330 status = create_conn_struct_tos_cwd(global_messaging_context(),
1331 snum,
1332 lp_path(talloc_tos(), snum),
1333 NULL,
1334 &c);
1335 if (!NT_STATUS_IS_OK(status)) {
1336 return False;
1339 path_out = talloc_asprintf(c,
1340 "%s/%s",
1341 lp_path(talloc_tos(), snum),
1342 jucn->volume_name);
1343 if (path_out == NULL) {
1344 TALLOC_FREE(c);
1345 return False;
1347 *pp_path_out = path_out;
1348 *conn_out = c->conn;
1349 return True;
1352 bool create_msdfs_link(const struct junction_map *jucn)
1354 TALLOC_CTX *frame = talloc_stackframe();
1355 char *path = NULL;
1356 char *msdfs_link = NULL;
1357 connection_struct *conn;
1358 int i=0;
1359 bool insert_comma = False;
1360 bool ret = False;
1361 struct smb_filename *smb_fname = NULL;
1362 bool ok;
1363 int retval;
1365 ok = junction_to_local_path_tos(jucn, &path, &conn);
1366 if (!ok) {
1367 TALLOC_FREE(frame);
1368 return False;
1371 /* Form the msdfs_link contents */
1372 msdfs_link = talloc_strdup(conn, "msdfs:");
1373 if (!msdfs_link) {
1374 goto out;
1376 for(i=0; i<jucn->referral_count; i++) {
1377 char *refpath = jucn->referral_list[i].alternate_path;
1379 /* Alternate paths always use Windows separators. */
1380 trim_char(refpath, '\\', '\\');
1381 if(*refpath == '\0') {
1382 if (i == 0) {
1383 insert_comma = False;
1385 continue;
1387 if (i > 0 && insert_comma) {
1388 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1389 ",%s",
1390 refpath);
1391 } else {
1392 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1393 "%s",
1394 refpath);
1397 if (!msdfs_link) {
1398 goto out;
1400 if (!insert_comma) {
1401 insert_comma = True;
1405 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1406 path, msdfs_link));
1408 smb_fname = synthetic_smb_fname(frame,
1409 path,
1410 NULL,
1411 NULL,
1413 if (smb_fname == NULL) {
1414 errno = ENOMEM;
1415 goto out;
1418 retval = SMB_VFS_SYMLINKAT(conn,
1419 msdfs_link,
1420 conn->cwd_fsp,
1421 smb_fname);
1422 if (retval < 0) {
1423 if (errno == EEXIST) {
1424 retval = SMB_VFS_UNLINKAT(conn,
1425 conn->cwd_fsp,
1426 smb_fname,
1428 if (retval != 0) {
1429 TALLOC_FREE(smb_fname);
1430 goto out;
1433 retval = SMB_VFS_SYMLINKAT(conn,
1434 msdfs_link,
1435 conn->cwd_fsp,
1436 smb_fname);
1437 if (retval < 0) {
1438 DEBUG(1,("create_msdfs_link: symlinkat failed "
1439 "%s -> %s\nError: %s\n",
1440 path, msdfs_link, strerror(errno)));
1441 goto out;
1445 ret = True;
1447 out:
1448 TALLOC_FREE(frame);
1449 return ret;
1452 bool remove_msdfs_link(const struct junction_map *jucn)
1454 TALLOC_CTX *frame = talloc_stackframe();
1455 char *path = NULL;
1456 connection_struct *conn;
1457 bool ret = False;
1458 struct smb_filename *smb_fname;
1459 bool ok;
1460 int retval;
1462 ok = junction_to_local_path_tos(jucn, &path, &conn);
1463 if (!ok) {
1464 TALLOC_FREE(frame);
1465 return false;
1468 smb_fname = synthetic_smb_fname(frame,
1469 path,
1470 NULL,
1471 NULL,
1473 if (smb_fname == NULL) {
1474 TALLOC_FREE(frame);
1475 errno = ENOMEM;
1476 return false;
1479 retval = SMB_VFS_UNLINKAT(conn,
1480 conn->cwd_fsp,
1481 smb_fname,
1483 if (retval == 0) {
1484 ret = True;
1487 TALLOC_FREE(frame);
1488 return ret;
1491 /*********************************************************************
1492 Return the number of DFS links at the root of this share.
1493 *********************************************************************/
1495 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1497 TALLOC_CTX *frame = talloc_stackframe();
1498 size_t cnt = 0;
1499 DIR *dirp = NULL;
1500 const char *dname = NULL;
1501 char *talloced = NULL;
1502 const char *connect_path = lp_path(frame, snum);
1503 const char *msdfs_proxy = lp_msdfs_proxy(frame, snum);
1504 struct conn_struct_tos *c = NULL;
1505 connection_struct *conn = NULL;
1506 NTSTATUS status;
1507 struct smb_filename *smb_fname = NULL;
1509 if(*connect_path == '\0') {
1510 TALLOC_FREE(frame);
1511 return 0;
1515 * Fake up a connection struct for the VFS layer.
1518 status = create_conn_struct_tos_cwd(global_messaging_context(),
1519 snum,
1520 connect_path,
1521 NULL,
1522 &c);
1523 if (!NT_STATUS_IS_OK(status)) {
1524 DEBUG(3, ("create_conn_struct failed: %s\n",
1525 nt_errstr(status)));
1526 TALLOC_FREE(frame);
1527 return 0;
1529 conn = c->conn;
1531 /* Count a link for the msdfs root - convention */
1532 cnt = 1;
1534 /* No more links if this is an msdfs proxy. */
1535 if (*msdfs_proxy != '\0') {
1536 goto out;
1539 smb_fname = synthetic_smb_fname(frame,
1540 ".",
1541 NULL,
1542 NULL,
1544 if (smb_fname == NULL) {
1545 goto out;
1548 /* Now enumerate all dfs links */
1549 dirp = SMB_VFS_OPENDIR(conn, smb_fname, NULL, 0);
1550 if(!dirp) {
1551 goto out;
1554 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1555 != NULL) {
1556 struct smb_filename *smb_dname =
1557 synthetic_smb_fname(frame,
1558 dname,
1559 NULL,
1560 NULL,
1562 if (smb_dname == NULL) {
1563 goto out;
1565 if (is_msdfs_link(conn, smb_dname)) {
1566 cnt++;
1568 TALLOC_FREE(talloced);
1569 TALLOC_FREE(smb_dname);
1572 SMB_VFS_CLOSEDIR(conn,dirp);
1574 out:
1575 TALLOC_FREE(frame);
1576 return cnt;
1579 /*********************************************************************
1580 *********************************************************************/
1582 static int form_junctions(TALLOC_CTX *ctx,
1583 int snum,
1584 struct junction_map *jucn,
1585 size_t jn_remain)
1587 TALLOC_CTX *frame = talloc_stackframe();
1588 size_t cnt = 0;
1589 DIR *dirp = NULL;
1590 const char *dname = NULL;
1591 char *talloced = NULL;
1592 const char *connect_path = lp_path(frame, snum);
1593 char *service_name = lp_servicename(frame, snum);
1594 const char *msdfs_proxy = lp_msdfs_proxy(frame, snum);
1595 struct conn_struct_tos *c = NULL;
1596 connection_struct *conn = NULL;
1597 struct referral *ref = NULL;
1598 struct smb_filename *smb_fname = NULL;
1599 NTSTATUS status;
1601 if (jn_remain == 0) {
1602 TALLOC_FREE(frame);
1603 return 0;
1606 if(*connect_path == '\0') {
1607 TALLOC_FREE(frame);
1608 return 0;
1612 * Fake up a connection struct for the VFS layer.
1615 status = create_conn_struct_tos_cwd(global_messaging_context(),
1616 snum,
1617 connect_path,
1618 NULL,
1619 &c);
1620 if (!NT_STATUS_IS_OK(status)) {
1621 DEBUG(3, ("create_conn_struct failed: %s\n",
1622 nt_errstr(status)));
1623 TALLOC_FREE(frame);
1624 return 0;
1626 conn = c->conn;
1628 /* form a junction for the msdfs root - convention
1629 DO NOT REMOVE THIS: NT clients will not work with us
1630 if this is not present
1632 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1633 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1634 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1635 goto out;
1637 jucn[cnt].comment = "";
1638 jucn[cnt].referral_count = 1;
1640 ref = jucn[cnt].referral_list = talloc_zero(ctx, struct referral);
1641 if (jucn[cnt].referral_list == NULL) {
1642 goto out;
1645 ref->proximity = 0;
1646 ref->ttl = REFERRAL_TTL;
1647 if (*msdfs_proxy != '\0') {
1648 ref->alternate_path = talloc_strdup(ctx,
1649 msdfs_proxy);
1650 } else {
1651 ref->alternate_path = talloc_asprintf(ctx,
1652 "\\\\%s\\%s",
1653 get_local_machine_name(),
1654 service_name);
1657 if (!ref->alternate_path) {
1658 goto out;
1660 cnt++;
1662 /* Don't enumerate if we're an msdfs proxy. */
1663 if (*msdfs_proxy != '\0') {
1664 goto out;
1667 smb_fname = synthetic_smb_fname(frame,
1668 ".",
1669 NULL,
1670 NULL,
1672 if (smb_fname == NULL) {
1673 goto out;
1676 /* Now enumerate all dfs links */
1677 dirp = SMB_VFS_OPENDIR(conn, smb_fname, NULL, 0);
1678 if(!dirp) {
1679 goto out;
1682 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1683 != NULL) {
1684 char *link_target = NULL;
1685 struct smb_filename *smb_dname = NULL;
1687 if (cnt >= jn_remain) {
1688 DEBUG(2, ("form_junctions: ran out of MSDFS "
1689 "junction slots"));
1690 TALLOC_FREE(talloced);
1691 goto out;
1693 smb_dname = synthetic_smb_fname(talloc_tos(),
1694 dname,
1695 NULL,
1696 NULL,
1698 if (smb_dname == NULL) {
1699 TALLOC_FREE(talloced);
1700 goto out;
1702 if (is_msdfs_link_internal(ctx,
1703 conn,
1704 smb_dname, &link_target)) {
1705 if (parse_msdfs_symlink(ctx, snum,
1706 link_target,
1707 &jucn[cnt].referral_list,
1708 &jucn[cnt].referral_count)) {
1710 jucn[cnt].service_name = talloc_strdup(ctx,
1711 service_name);
1712 jucn[cnt].volume_name = talloc_strdup(ctx,
1713 dname);
1714 if (!jucn[cnt].service_name ||
1715 !jucn[cnt].volume_name) {
1716 TALLOC_FREE(talloced);
1717 goto out;
1719 jucn[cnt].comment = "";
1720 cnt++;
1722 TALLOC_FREE(link_target);
1724 TALLOC_FREE(talloced);
1725 TALLOC_FREE(smb_dname);
1728 out:
1730 if (dirp) {
1731 SMB_VFS_CLOSEDIR(conn,dirp);
1734 TALLOC_FREE(frame);
1735 return cnt;
1738 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1740 struct junction_map *jn = NULL;
1741 int i=0;
1742 size_t jn_count = 0;
1743 int sharecount = 0;
1745 *p_num_jn = 0;
1746 if(!lp_host_msdfs()) {
1747 return NULL;
1750 /* Ensure all the usershares are loaded. */
1751 become_root();
1752 load_registry_shares();
1753 sharecount = load_usershare_shares(NULL, connections_snum_used);
1754 unbecome_root();
1756 for(i=0;i < sharecount;i++) {
1757 if(lp_msdfs_root(i)) {
1758 jn_count += count_dfs_links(ctx, i);
1761 if (jn_count == 0) {
1762 return NULL;
1764 jn = talloc_array(ctx, struct junction_map, jn_count);
1765 if (!jn) {
1766 return NULL;
1768 for(i=0; i < sharecount; i++) {
1769 if (*p_num_jn >= jn_count) {
1770 break;
1772 if(lp_msdfs_root(i)) {
1773 *p_num_jn += form_junctions(ctx, i,
1774 &jn[*p_num_jn],
1775 jn_count - *p_num_jn);
1778 return jn;
1781 /******************************************************************************
1782 Core function to resolve a dfs pathname possibly containing a wildcard. If
1783 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1784 detected during dfs resolution.
1785 ******************************************************************************/
1787 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1788 connection_struct *conn,
1789 const char *name_in,
1790 uint32_t ucf_flags,
1791 bool allow_broken_path,
1792 char **pp_name_out,
1793 bool *ppath_contains_wcard)
1795 bool path_contains_wcard = false;
1796 NTSTATUS status = NT_STATUS_OK;
1798 status = dfs_redirect(ctx,
1799 conn,
1800 name_in,
1801 ucf_flags,
1802 allow_broken_path,
1803 pp_name_out,
1804 &path_contains_wcard);
1806 if (NT_STATUS_IS_OK(status) &&
1807 ppath_contains_wcard != NULL &&
1808 path_contains_wcard) {
1809 *ppath_contains_wcard = path_contains_wcard;
1811 return status;