smbd: Return "blocker_pid" from do_lock()
[Samba.git] / source3 / smbd / msdfs.c
blob19cb301f56b3404331ae25e121944d44c3626472
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_READLINK(conn, smb_fname,
659 link_target, bufsize - 1);
660 if (referral_len == -1) {
661 DEBUG(0,("is_msdfs_link_read_target: Error reading "
662 "msdfs link %s: %s\n",
663 smb_fname->base_name, strerror(errno)));
664 goto err;
666 link_target[referral_len] = '\0';
668 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n", smb_fname->base_name,
669 link_target));
671 if (!strnequal(link_target, "msdfs:", 6)) {
672 goto err;
674 return True;
676 err:
678 if (link_target != link_target_buf) {
679 TALLOC_FREE(link_target);
681 return False;
684 /**********************************************************************
685 Returns true if the unix path is a valid msdfs symlink.
686 **********************************************************************/
688 bool is_msdfs_link(connection_struct *conn,
689 struct smb_filename *smb_fname)
691 return is_msdfs_link_internal(talloc_tos(),
692 conn,
693 smb_fname,
694 NULL);
697 /*****************************************************************
698 Used by other functions to decide if a dfs path is remote,
699 and to get the list of referred locations for that remote path.
701 search_flag: For findfirsts, dfs links themselves are not
702 redirected, but paths beyond the links are. For normal smb calls,
703 even dfs links need to be redirected.
705 consumedcntp: how much of the dfs path is being redirected. the client
706 should try the remaining path on the redirected server.
708 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
709 link redirect are in targetpath.
710 *****************************************************************/
712 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
713 connection_struct *conn,
714 const char *dfspath, /* Incoming complete dfs path */
715 const struct dfs_path *pdp, /* Parsed out
716 server+share+extrapath. */
717 uint32_t ucf_flags,
718 int *consumedcntp,
719 char **pp_targetpath)
721 char *p = NULL;
722 char *q = NULL;
723 NTSTATUS status;
724 struct smb_filename *smb_fname = NULL;
725 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
726 components). */
728 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
729 conn->connectpath, pdp->reqpath));
732 * Note the unix path conversion here we're doing we
733 * throw away. We're looking for a symlink for a dfs
734 * resolution, if we don't find it we'll do another
735 * unix_convert later in the codepath.
738 status = unix_convert(ctx, conn, pdp->reqpath, &smb_fname,
739 ucf_flags);
741 if (!NT_STATUS_IS_OK(status)) {
742 if (!NT_STATUS_EQUAL(status,
743 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
744 return status;
746 if (smb_fname == NULL || smb_fname->base_name == NULL) {
747 return status;
751 /* Optimization - check if we can redirect the whole path. */
753 if (is_msdfs_link_internal(ctx, conn, smb_fname, pp_targetpath)) {
754 /* XX_ALLOW_WCARD_XXX is called from search functions. */
755 if (ucf_flags &
756 (UCF_COND_ALLOW_WCARD_LCOMP|
757 UCF_ALWAYS_ALLOW_WCARD_LCOMP)) {
758 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
759 "for dfs link %s.\n", dfspath));
760 status = NT_STATUS_OK;
761 goto out;
764 DEBUG(6,("dfs_path_lookup: %s resolves to a "
765 "valid dfs link %s.\n", dfspath,
766 pp_targetpath ? *pp_targetpath : ""));
768 if (consumedcntp) {
769 *consumedcntp = strlen(dfspath);
771 status = NT_STATUS_PATH_NOT_COVERED;
772 goto out;
775 /* Prepare to test only for '/' components in the given path,
776 * so if a Windows path replace all '\\' characters with '/'.
777 * For a POSIX DFS path we know all separators are already '/'. */
779 canon_dfspath = talloc_strdup(ctx, dfspath);
780 if (!canon_dfspath) {
781 status = NT_STATUS_NO_MEMORY;
782 goto out;
784 if (!pdp->posix_path) {
785 string_replace(canon_dfspath, '\\', '/');
789 * localpath comes out of unix_convert, so it has
790 * no trailing backslash. Make sure that canon_dfspath hasn't either.
791 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
794 trim_char(canon_dfspath,0,'/');
797 * Redirect if any component in the path is a link.
798 * We do this by walking backwards through the
799 * local path, chopping off the last component
800 * in both the local path and the canonicalized
801 * DFS path. If we hit a DFS link then we're done.
804 p = strrchr_m(smb_fname->base_name, '/');
805 if (consumedcntp) {
806 q = strrchr_m(canon_dfspath, '/');
809 while (p) {
810 *p = '\0';
811 if (q) {
812 *q = '\0';
815 if (is_msdfs_link_internal(ctx, conn,
816 smb_fname, pp_targetpath)) {
817 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
818 "parent %s is dfs link\n", dfspath,
819 smb_fname_str_dbg(smb_fname)));
821 if (consumedcntp) {
822 *consumedcntp = strlen(canon_dfspath);
823 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
824 "(%d)\n",
825 canon_dfspath,
826 *consumedcntp));
829 status = NT_STATUS_PATH_NOT_COVERED;
830 goto out;
833 /* Step back on the filesystem. */
834 p = strrchr_m(smb_fname->base_name, '/');
836 if (consumedcntp) {
837 /* And in the canonicalized dfs path. */
838 q = strrchr_m(canon_dfspath, '/');
842 status = NT_STATUS_OK;
843 out:
844 TALLOC_FREE(smb_fname);
845 return status;
848 /*****************************************************************
849 Decides if a dfs pathname should be redirected or not.
850 If not, the pathname is converted to a tcon-relative local unix path
852 search_wcard_flag: this flag performs 2 functions both related
853 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
854 for details.
856 This function can return NT_STATUS_OK, meaning use the returned path as-is
857 (mapped into a local path).
858 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
859 any other NT_STATUS error which is a genuine error to be
860 returned to the client.
861 *****************************************************************/
863 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
864 connection_struct *conn,
865 const char *path_in,
866 uint32_t ucf_flags,
867 bool allow_broken_path,
868 char **pp_path_out,
869 bool *ppath_contains_wcard)
871 NTSTATUS status;
872 bool search_wcard_flag = (ucf_flags &
873 (UCF_COND_ALLOW_WCARD_LCOMP|UCF_ALWAYS_ALLOW_WCARD_LCOMP));
874 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
876 if (!pdp) {
877 return NT_STATUS_NO_MEMORY;
880 status = parse_dfs_path(conn, path_in, search_wcard_flag,
881 allow_broken_path, pdp,
882 ppath_contains_wcard);
883 if (!NT_STATUS_IS_OK(status)) {
884 TALLOC_FREE(pdp);
885 return status;
888 if (pdp->reqpath[0] == '\0') {
889 TALLOC_FREE(pdp);
890 *pp_path_out = talloc_strdup(ctx, "");
891 if (!*pp_path_out) {
892 return NT_STATUS_NO_MEMORY;
894 DEBUG(5,("dfs_redirect: self-referral.\n"));
895 return NT_STATUS_OK;
898 /* If dfs pathname for a non-dfs share, convert to tcon-relative
899 path and return OK */
901 if (!lp_msdfs_root(SNUM(conn))) {
902 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
903 TALLOC_FREE(pdp);
904 if (!*pp_path_out) {
905 return NT_STATUS_NO_MEMORY;
907 return NT_STATUS_OK;
910 /* If it looked like a local path (zero hostname/servicename)
911 * just treat as a tcon-relative path. */
913 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
914 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
915 TALLOC_FREE(pdp);
916 if (!*pp_path_out) {
917 return NT_STATUS_NO_MEMORY;
919 return NT_STATUS_OK;
922 if (!( strequal(pdp->servicename, lp_servicename(talloc_tos(), SNUM(conn)))
923 || (strequal(pdp->servicename, HOMES_NAME)
924 && strequal(lp_servicename(talloc_tos(), SNUM(conn)),
925 conn->session_info->unix_info->sanitized_username) )) ) {
927 /* The given sharename doesn't match this connection. */
928 TALLOC_FREE(pdp);
930 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
933 status = dfs_path_lookup(ctx, conn, path_in, pdp,
934 ucf_flags, NULL, NULL);
935 if (!NT_STATUS_IS_OK(status)) {
936 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
937 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
938 } else {
939 DEBUG(10,("dfs_redirect: dfs_path_lookup "
940 "failed for %s with %s\n",
941 path_in, nt_errstr(status) ));
943 return status;
946 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
948 /* Form non-dfs tcon-relative path */
949 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
950 TALLOC_FREE(pdp);
951 if (!*pp_path_out) {
952 return NT_STATUS_NO_MEMORY;
955 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
956 path_in,
957 *pp_path_out));
959 return NT_STATUS_OK;
962 /**********************************************************************
963 Return a self referral.
964 **********************************************************************/
966 static NTSTATUS self_ref(TALLOC_CTX *ctx,
967 const char *dfs_path,
968 struct junction_map *jucn,
969 int *consumedcntp,
970 bool *self_referralp)
972 struct referral *ref;
974 *self_referralp = True;
976 jucn->referral_count = 1;
977 if((ref = talloc_zero(ctx, struct referral)) == NULL) {
978 return NT_STATUS_NO_MEMORY;
981 ref->alternate_path = talloc_strdup(ctx, dfs_path);
982 if (!ref->alternate_path) {
983 TALLOC_FREE(ref);
984 return NT_STATUS_NO_MEMORY;
986 ref->proximity = 0;
987 ref->ttl = REFERRAL_TTL;
988 jucn->referral_list = ref;
989 *consumedcntp = strlen(dfs_path);
990 return NT_STATUS_OK;
993 /**********************************************************************
994 Gets valid referrals for a dfs path and fills up the
995 junction_map structure.
996 **********************************************************************/
998 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
999 const char *dfs_path,
1000 const struct tsocket_address *remote_address,
1001 const struct tsocket_address *local_address,
1002 bool allow_broken_path,
1003 struct junction_map *jucn,
1004 int *consumedcntp,
1005 bool *self_referralp)
1007 TALLOC_CTX *frame = talloc_stackframe();
1008 struct conn_struct_tos *c = NULL;
1009 struct connection_struct *conn = NULL;
1010 char *targetpath = NULL;
1011 int snum;
1012 NTSTATUS status = NT_STATUS_NOT_FOUND;
1013 bool dummy;
1014 struct dfs_path *pdp = talloc_zero(frame, struct dfs_path);
1016 if (!pdp) {
1017 TALLOC_FREE(frame);
1018 return NT_STATUS_NO_MEMORY;
1021 *self_referralp = False;
1023 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1024 pdp, &dummy);
1025 if (!NT_STATUS_IS_OK(status)) {
1026 TALLOC_FREE(frame);
1027 return status;
1030 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1031 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1032 if (!jucn->service_name || !jucn->volume_name) {
1033 TALLOC_FREE(frame);
1034 return NT_STATUS_NO_MEMORY;
1037 /* Verify the share is a dfs root */
1038 snum = lp_servicenumber(jucn->service_name);
1039 if(snum < 0) {
1040 char *service_name = NULL;
1041 if ((snum = find_service(ctx, jucn->service_name, &service_name)) < 0) {
1042 TALLOC_FREE(frame);
1043 return NT_STATUS_NOT_FOUND;
1045 if (!service_name) {
1046 TALLOC_FREE(frame);
1047 return NT_STATUS_NO_MEMORY;
1049 TALLOC_FREE(jucn->service_name);
1050 jucn->service_name = talloc_strdup(ctx, service_name);
1051 if (!jucn->service_name) {
1052 TALLOC_FREE(frame);
1053 return NT_STATUS_NO_MEMORY;
1057 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(talloc_tos(), snum) == '\0')) {
1058 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
1059 "a dfs root.\n",
1060 pdp->servicename, dfs_path));
1061 TALLOC_FREE(frame);
1062 return NT_STATUS_NOT_FOUND;
1066 * Self referrals are tested with a anonymous IPC connection and
1067 * a GET_DFS_REFERRAL call to \\server\share. (which means
1068 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
1069 * into the directory and will fail if it cannot (as the anonymous
1070 * user). Cope with this.
1073 if (pdp->reqpath[0] == '\0') {
1074 char *tmp;
1075 struct referral *ref;
1076 int refcount;
1078 if (*lp_msdfs_proxy(talloc_tos(), snum) == '\0') {
1079 TALLOC_FREE(frame);
1080 return self_ref(ctx,
1081 dfs_path,
1082 jucn,
1083 consumedcntp,
1084 self_referralp);
1088 * It's an msdfs proxy share. Redirect to
1089 * the configured target share.
1092 tmp = talloc_asprintf(frame, "msdfs:%s",
1093 lp_msdfs_proxy(frame, snum));
1094 if (tmp == NULL) {
1095 TALLOC_FREE(frame);
1096 return NT_STATUS_NO_MEMORY;
1099 if (!parse_msdfs_symlink(ctx, snum, tmp, &ref, &refcount)) {
1100 TALLOC_FREE(frame);
1101 return NT_STATUS_INVALID_PARAMETER;
1103 jucn->referral_count = refcount;
1104 jucn->referral_list = ref;
1105 *consumedcntp = strlen(dfs_path);
1106 TALLOC_FREE(frame);
1107 return NT_STATUS_OK;
1110 status = create_conn_struct_tos_cwd(global_messaging_context(),
1111 snum,
1112 lp_path(frame, snum),
1113 NULL,
1114 &c);
1115 if (!NT_STATUS_IS_OK(status)) {
1116 TALLOC_FREE(frame);
1117 return status;
1119 conn = c->conn;
1122 * TODO
1124 * The remote and local address should be passed down to
1125 * create_conn_struct_cwd.
1127 if (conn->sconn->remote_address == NULL) {
1128 conn->sconn->remote_address =
1129 tsocket_address_copy(remote_address, conn->sconn);
1130 if (conn->sconn->remote_address == NULL) {
1131 TALLOC_FREE(frame);
1132 return NT_STATUS_NO_MEMORY;
1135 if (conn->sconn->local_address == NULL) {
1136 conn->sconn->local_address =
1137 tsocket_address_copy(local_address, conn->sconn);
1138 if (conn->sconn->local_address == NULL) {
1139 TALLOC_FREE(frame);
1140 return NT_STATUS_NO_MEMORY;
1144 /* If this is a DFS path dfs_lookup should return
1145 * NT_STATUS_PATH_NOT_COVERED. */
1147 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
1148 0, consumedcntp, &targetpath);
1150 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
1151 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
1152 dfs_path));
1153 if (NT_STATUS_IS_OK(status)) {
1155 * We are in an error path here (we
1156 * know it's not a DFS path), but
1157 * dfs_path_lookup() can return
1158 * NT_STATUS_OK. Ensure we always
1159 * return a valid error code.
1161 * #9588 - ACLs are not inherited to directories
1162 * for DFS shares.
1164 status = NT_STATUS_NOT_FOUND;
1166 goto err_exit;
1169 /* We know this is a valid dfs link. Parse the targetpath. */
1170 if (!parse_msdfs_symlink(ctx, snum, targetpath,
1171 &jucn->referral_list,
1172 &jucn->referral_count)) {
1173 DEBUG(3,("get_referred_path: failed to parse symlink "
1174 "target %s\n", targetpath ));
1175 status = NT_STATUS_NOT_FOUND;
1176 goto err_exit;
1179 status = NT_STATUS_OK;
1180 err_exit:
1181 TALLOC_FREE(frame);
1182 return status;
1185 /******************************************************************
1186 Set up the DFS referral for the dfs pathname. This call returns
1187 the amount of the path covered by this server, and where the
1188 client should be redirected to. This is the meat of the
1189 TRANS2_GET_DFS_REFERRAL call.
1190 ******************************************************************/
1192 int setup_dfs_referral(connection_struct *orig_conn,
1193 const char *dfs_path,
1194 int max_referral_level,
1195 char **ppdata, NTSTATUS *pstatus)
1197 char *pdata = *ppdata;
1198 int reply_size = 0;
1199 struct dfs_GetDFSReferral *r;
1200 DATA_BLOB blob = data_blob_null;
1201 NTSTATUS status;
1202 enum ndr_err_code ndr_err;
1204 r = talloc_zero(talloc_tos(), struct dfs_GetDFSReferral);
1205 if (r == NULL) {
1206 *pstatus = NT_STATUS_NO_MEMORY;
1207 return -1;
1210 r->in.req.max_referral_level = max_referral_level;
1211 r->in.req.servername = talloc_strdup(r, dfs_path);
1212 if (r->in.req.servername == NULL) {
1213 talloc_free(r);
1214 *pstatus = NT_STATUS_NO_MEMORY;
1215 return -1;
1218 status = SMB_VFS_GET_DFS_REFERRALS(orig_conn, r);
1219 if (!NT_STATUS_IS_OK(status)) {
1220 talloc_free(r);
1221 *pstatus = status;
1222 return -1;
1225 ndr_err = ndr_push_struct_blob(&blob, r,
1226 r->out.resp,
1227 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1228 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1229 TALLOC_FREE(r);
1230 *pstatus = NT_STATUS_INVALID_PARAMETER;
1231 return -1;
1234 pdata = (char *)SMB_REALLOC(pdata, blob.length);
1235 if(pdata == NULL) {
1236 TALLOC_FREE(r);
1237 DEBUG(0,("referral setup:"
1238 "malloc failed for Realloc!\n"));
1239 return -1;
1241 *ppdata = pdata;
1242 reply_size = blob.length;
1243 memcpy(pdata, blob.data, blob.length);
1244 TALLOC_FREE(r);
1246 *pstatus = NT_STATUS_OK;
1247 return reply_size;
1250 /**********************************************************************
1251 The following functions are called by the NETDFS RPC pipe functions
1252 **********************************************************************/
1254 /*********************************************************************
1255 Creates a junction structure from a DFS pathname
1256 **********************************************************************/
1258 bool create_junction(TALLOC_CTX *ctx,
1259 const char *dfs_path,
1260 bool allow_broken_path,
1261 struct junction_map *jucn)
1263 int snum;
1264 bool dummy;
1265 struct dfs_path *pdp = talloc(ctx,struct dfs_path);
1266 NTSTATUS status;
1268 if (!pdp) {
1269 return False;
1271 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1272 pdp, &dummy);
1273 if (!NT_STATUS_IS_OK(status)) {
1274 return False;
1277 /* check if path is dfs : validate first token */
1278 if (!is_myname_or_ipaddr(pdp->hostname)) {
1279 DEBUG(4,("create_junction: Invalid hostname %s "
1280 "in dfs path %s\n",
1281 pdp->hostname, dfs_path));
1282 TALLOC_FREE(pdp);
1283 return False;
1286 /* Check for a non-DFS share */
1287 snum = lp_servicenumber(pdp->servicename);
1289 if(snum < 0 || !lp_msdfs_root(snum)) {
1290 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1291 pdp->servicename));
1292 TALLOC_FREE(pdp);
1293 return False;
1296 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1297 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1298 jucn->comment = lp_comment(ctx, snum);
1300 TALLOC_FREE(pdp);
1301 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1302 return False;
1304 return True;
1307 /**********************************************************************
1308 Forms a valid Unix pathname from the junction
1309 **********************************************************************/
1311 static bool junction_to_local_path_tos(const struct junction_map *jucn,
1312 char **pp_path_out,
1313 connection_struct **conn_out)
1315 struct conn_struct_tos *c = NULL;
1316 int snum;
1317 char *path_out = NULL;
1318 NTSTATUS status;
1320 snum = lp_servicenumber(jucn->service_name);
1321 if(snum < 0) {
1322 return False;
1324 status = create_conn_struct_tos_cwd(global_messaging_context(),
1325 snum,
1326 lp_path(talloc_tos(), snum),
1327 NULL,
1328 &c);
1329 if (!NT_STATUS_IS_OK(status)) {
1330 return False;
1333 path_out = talloc_asprintf(c,
1334 "%s/%s",
1335 lp_path(talloc_tos(), snum),
1336 jucn->volume_name);
1337 if (path_out == NULL) {
1338 TALLOC_FREE(c);
1339 return False;
1341 *pp_path_out = path_out;
1342 *conn_out = c->conn;
1343 return True;
1346 bool create_msdfs_link(const struct junction_map *jucn)
1348 TALLOC_CTX *frame = talloc_stackframe();
1349 char *path = NULL;
1350 char *msdfs_link = NULL;
1351 connection_struct *conn;
1352 int i=0;
1353 bool insert_comma = False;
1354 bool ret = False;
1355 struct smb_filename *smb_fname = NULL;
1356 bool ok;
1358 ok = junction_to_local_path_tos(jucn, &path, &conn);
1359 if (!ok) {
1360 TALLOC_FREE(frame);
1361 return False;
1364 /* Form the msdfs_link contents */
1365 msdfs_link = talloc_strdup(conn, "msdfs:");
1366 if (!msdfs_link) {
1367 goto out;
1369 for(i=0; i<jucn->referral_count; i++) {
1370 char *refpath = jucn->referral_list[i].alternate_path;
1372 /* Alternate paths always use Windows separators. */
1373 trim_char(refpath, '\\', '\\');
1374 if(*refpath == '\0') {
1375 if (i == 0) {
1376 insert_comma = False;
1378 continue;
1380 if (i > 0 && insert_comma) {
1381 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1382 ",%s",
1383 refpath);
1384 } else {
1385 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1386 "%s",
1387 refpath);
1390 if (!msdfs_link) {
1391 goto out;
1393 if (!insert_comma) {
1394 insert_comma = True;
1398 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1399 path, msdfs_link));
1401 smb_fname = synthetic_smb_fname(frame,
1402 path,
1403 NULL,
1404 NULL,
1406 if (smb_fname == NULL) {
1407 errno = ENOMEM;
1408 goto out;
1411 if(SMB_VFS_SYMLINK(conn, msdfs_link, smb_fname) < 0) {
1412 if (errno == EEXIST) {
1413 if(SMB_VFS_UNLINK(conn, smb_fname)!=0) {
1414 TALLOC_FREE(smb_fname);
1415 goto out;
1418 if (SMB_VFS_SYMLINK(conn, msdfs_link, smb_fname) < 0) {
1419 DEBUG(1,("create_msdfs_link: symlink failed "
1420 "%s -> %s\nError: %s\n",
1421 path, msdfs_link, strerror(errno)));
1422 goto out;
1426 ret = True;
1428 out:
1429 TALLOC_FREE(frame);
1430 return ret;
1433 bool remove_msdfs_link(const struct junction_map *jucn)
1435 TALLOC_CTX *frame = talloc_stackframe();
1436 char *path = NULL;
1437 connection_struct *conn;
1438 bool ret = False;
1439 struct smb_filename *smb_fname;
1440 bool ok;
1442 ok = junction_to_local_path_tos(jucn, &path, &conn);
1443 if (!ok) {
1444 TALLOC_FREE(frame);
1445 return false;
1448 smb_fname = synthetic_smb_fname(frame,
1449 path,
1450 NULL,
1451 NULL,
1453 if (smb_fname == NULL) {
1454 TALLOC_FREE(frame);
1455 errno = ENOMEM;
1456 return false;
1459 if( SMB_VFS_UNLINK(conn, smb_fname) == 0 ) {
1460 ret = True;
1463 TALLOC_FREE(frame);
1464 return ret;
1467 /*********************************************************************
1468 Return the number of DFS links at the root of this share.
1469 *********************************************************************/
1471 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1473 TALLOC_CTX *frame = talloc_stackframe();
1474 size_t cnt = 0;
1475 DIR *dirp = NULL;
1476 const char *dname = NULL;
1477 char *talloced = NULL;
1478 const char *connect_path = lp_path(frame, snum);
1479 const char *msdfs_proxy = lp_msdfs_proxy(frame, snum);
1480 struct conn_struct_tos *c = NULL;
1481 connection_struct *conn = NULL;
1482 NTSTATUS status;
1483 struct smb_filename *smb_fname = NULL;
1485 if(*connect_path == '\0') {
1486 TALLOC_FREE(frame);
1487 return 0;
1491 * Fake up a connection struct for the VFS layer.
1494 status = create_conn_struct_tos_cwd(global_messaging_context(),
1495 snum,
1496 connect_path,
1497 NULL,
1498 &c);
1499 if (!NT_STATUS_IS_OK(status)) {
1500 DEBUG(3, ("create_conn_struct failed: %s\n",
1501 nt_errstr(status)));
1502 TALLOC_FREE(frame);
1503 return 0;
1505 conn = c->conn;
1507 /* Count a link for the msdfs root - convention */
1508 cnt = 1;
1510 /* No more links if this is an msdfs proxy. */
1511 if (*msdfs_proxy != '\0') {
1512 goto out;
1515 smb_fname = synthetic_smb_fname(frame,
1516 ".",
1517 NULL,
1518 NULL,
1520 if (smb_fname == NULL) {
1521 goto out;
1524 /* Now enumerate all dfs links */
1525 dirp = SMB_VFS_OPENDIR(conn, smb_fname, NULL, 0);
1526 if(!dirp) {
1527 goto out;
1530 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1531 != NULL) {
1532 struct smb_filename *smb_dname =
1533 synthetic_smb_fname(frame,
1534 dname,
1535 NULL,
1536 NULL,
1538 if (smb_dname == NULL) {
1539 goto out;
1541 if (is_msdfs_link(conn, smb_dname)) {
1542 cnt++;
1544 TALLOC_FREE(talloced);
1545 TALLOC_FREE(smb_dname);
1548 SMB_VFS_CLOSEDIR(conn,dirp);
1550 out:
1551 TALLOC_FREE(frame);
1552 return cnt;
1555 /*********************************************************************
1556 *********************************************************************/
1558 static int form_junctions(TALLOC_CTX *ctx,
1559 int snum,
1560 struct junction_map *jucn,
1561 size_t jn_remain)
1563 TALLOC_CTX *frame = talloc_stackframe();
1564 size_t cnt = 0;
1565 DIR *dirp = NULL;
1566 const char *dname = NULL;
1567 char *talloced = NULL;
1568 const char *connect_path = lp_path(frame, snum);
1569 char *service_name = lp_servicename(frame, snum);
1570 const char *msdfs_proxy = lp_msdfs_proxy(frame, snum);
1571 struct conn_struct_tos *c = NULL;
1572 connection_struct *conn = NULL;
1573 struct referral *ref = NULL;
1574 struct smb_filename *smb_fname = NULL;
1575 NTSTATUS status;
1577 if (jn_remain == 0) {
1578 TALLOC_FREE(frame);
1579 return 0;
1582 if(*connect_path == '\0') {
1583 TALLOC_FREE(frame);
1584 return 0;
1588 * Fake up a connection struct for the VFS layer.
1591 status = create_conn_struct_tos_cwd(global_messaging_context(),
1592 snum,
1593 connect_path,
1594 NULL,
1595 &c);
1596 if (!NT_STATUS_IS_OK(status)) {
1597 DEBUG(3, ("create_conn_struct failed: %s\n",
1598 nt_errstr(status)));
1599 TALLOC_FREE(frame);
1600 return 0;
1602 conn = c->conn;
1604 /* form a junction for the msdfs root - convention
1605 DO NOT REMOVE THIS: NT clients will not work with us
1606 if this is not present
1608 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1609 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1610 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1611 goto out;
1613 jucn[cnt].comment = "";
1614 jucn[cnt].referral_count = 1;
1616 ref = jucn[cnt].referral_list = talloc_zero(ctx, struct referral);
1617 if (jucn[cnt].referral_list == NULL) {
1618 goto out;
1621 ref->proximity = 0;
1622 ref->ttl = REFERRAL_TTL;
1623 if (*msdfs_proxy != '\0') {
1624 ref->alternate_path = talloc_strdup(ctx,
1625 msdfs_proxy);
1626 } else {
1627 ref->alternate_path = talloc_asprintf(ctx,
1628 "\\\\%s\\%s",
1629 get_local_machine_name(),
1630 service_name);
1633 if (!ref->alternate_path) {
1634 goto out;
1636 cnt++;
1638 /* Don't enumerate if we're an msdfs proxy. */
1639 if (*msdfs_proxy != '\0') {
1640 goto out;
1643 smb_fname = synthetic_smb_fname(frame,
1644 ".",
1645 NULL,
1646 NULL,
1648 if (smb_fname == NULL) {
1649 goto out;
1652 /* Now enumerate all dfs links */
1653 dirp = SMB_VFS_OPENDIR(conn, smb_fname, NULL, 0);
1654 if(!dirp) {
1655 goto out;
1658 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1659 != NULL) {
1660 char *link_target = NULL;
1661 struct smb_filename *smb_dname = NULL;
1663 if (cnt >= jn_remain) {
1664 DEBUG(2, ("form_junctions: ran out of MSDFS "
1665 "junction slots"));
1666 TALLOC_FREE(talloced);
1667 goto out;
1669 smb_dname = synthetic_smb_fname(talloc_tos(),
1670 dname,
1671 NULL,
1672 NULL,
1674 if (smb_dname == NULL) {
1675 TALLOC_FREE(talloced);
1676 goto out;
1678 if (is_msdfs_link_internal(ctx,
1679 conn,
1680 smb_dname, &link_target)) {
1681 if (parse_msdfs_symlink(ctx, snum,
1682 link_target,
1683 &jucn[cnt].referral_list,
1684 &jucn[cnt].referral_count)) {
1686 jucn[cnt].service_name = talloc_strdup(ctx,
1687 service_name);
1688 jucn[cnt].volume_name = talloc_strdup(ctx,
1689 dname);
1690 if (!jucn[cnt].service_name ||
1691 !jucn[cnt].volume_name) {
1692 TALLOC_FREE(talloced);
1693 goto out;
1695 jucn[cnt].comment = "";
1696 cnt++;
1698 TALLOC_FREE(link_target);
1700 TALLOC_FREE(talloced);
1701 TALLOC_FREE(smb_dname);
1704 out:
1706 if (dirp) {
1707 SMB_VFS_CLOSEDIR(conn,dirp);
1710 TALLOC_FREE(frame);
1711 return cnt;
1714 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1716 struct junction_map *jn = NULL;
1717 int i=0;
1718 size_t jn_count = 0;
1719 int sharecount = 0;
1721 *p_num_jn = 0;
1722 if(!lp_host_msdfs()) {
1723 return NULL;
1726 /* Ensure all the usershares are loaded. */
1727 become_root();
1728 load_registry_shares();
1729 sharecount = load_usershare_shares(NULL, connections_snum_used);
1730 unbecome_root();
1732 for(i=0;i < sharecount;i++) {
1733 if(lp_msdfs_root(i)) {
1734 jn_count += count_dfs_links(ctx, i);
1737 if (jn_count == 0) {
1738 return NULL;
1740 jn = talloc_array(ctx, struct junction_map, jn_count);
1741 if (!jn) {
1742 return NULL;
1744 for(i=0; i < sharecount; i++) {
1745 if (*p_num_jn >= jn_count) {
1746 break;
1748 if(lp_msdfs_root(i)) {
1749 *p_num_jn += form_junctions(ctx, i,
1750 &jn[*p_num_jn],
1751 jn_count - *p_num_jn);
1754 return jn;
1757 /******************************************************************************
1758 Core function to resolve a dfs pathname possibly containing a wildcard. If
1759 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1760 detected during dfs resolution.
1761 ******************************************************************************/
1763 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1764 connection_struct *conn,
1765 const char *name_in,
1766 uint32_t ucf_flags,
1767 bool allow_broken_path,
1768 char **pp_name_out,
1769 bool *ppath_contains_wcard)
1771 bool path_contains_wcard = false;
1772 NTSTATUS status = NT_STATUS_OK;
1774 status = dfs_redirect(ctx,
1775 conn,
1776 name_in,
1777 ucf_flags,
1778 allow_broken_path,
1779 pp_name_out,
1780 &path_contains_wcard);
1782 if (NT_STATUS_IS_OK(status) &&
1783 ppath_contains_wcard != NULL &&
1784 path_contains_wcard) {
1785 *ppath_contains_wcard = path_contains_wcard;
1787 return status;