s3/service: convert lp_force_group() to const
[Samba.git] / source3 / smbd / msdfs.c
blobbac9d8f6bf66316c900b55ab44870e1a8cd25ba0
1 /*
2 Unix SMB/Netbios implementation.
3 Version 3.0
4 MSDFS services for Samba
5 Copyright (C) Shirish Kalele 2000
6 Copyright (C) Jeremy Allison 2007
7 Copyright (C) Robin McCorkell 2015
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #define DBGC_CLASS DBGC_MSDFS
25 #include "includes.h"
26 #include "system/filesys.h"
27 #include "smbd/smbd.h"
28 #include "smbd/globals.h"
29 #include "msdfs.h"
30 #include "auth.h"
31 #include "lib/param/loadparm.h"
32 #include "libcli/security/security.h"
33 #include "librpc/gen_ndr/ndr_dfsblobs.h"
34 #include "lib/tsocket/tsocket.h"
36 /**********************************************************************
37 Parse a DFS pathname of the form \hostname\service\reqpath
38 into the dfs_path structure.
39 If POSIX pathnames is true, the pathname may also be of the
40 form /hostname/service/reqpath.
41 We cope with either here.
43 Unfortunately, due to broken clients who might set the
44 SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
45 send a local path, we have to cope with that too....
47 If conn != NULL then ensure the provided service is
48 the one pointed to by the connection.
50 This version does everything using pointers within one copy of the
51 pathname string, talloced on the struct dfs_path pointer (which
52 must be talloced). This may be too clever to live....
53 JRA.
54 **********************************************************************/
56 static NTSTATUS parse_dfs_path(connection_struct *conn,
57 const char *pathname,
58 bool allow_wcards,
59 bool allow_broken_path,
60 struct dfs_path *pdp, /* MUST BE TALLOCED */
61 bool *ppath_contains_wcard)
63 char *pathname_local;
64 char *p,*temp;
65 char *servicename;
66 char *eos_ptr;
67 NTSTATUS status = NT_STATUS_OK;
68 char sepchar;
70 ZERO_STRUCTP(pdp);
73 * This is the only talloc we should need to do
74 * on the struct dfs_path. All the pointers inside
75 * it should point to offsets within this string.
78 pathname_local = talloc_strdup(pdp, pathname);
79 if (!pathname_local) {
80 return NT_STATUS_NO_MEMORY;
82 /* Get a pointer to the terminating '\0' */
83 eos_ptr = &pathname_local[strlen(pathname_local)];
84 p = temp = pathname_local;
87 * Non-broken DFS paths *must* start with the
88 * path separator. For Windows this is always '\\',
89 * for posix paths this is always '/'.
92 if (*pathname == '/') {
93 pdp->posix_path = true;
94 sepchar = '/';
95 } else {
96 pdp->posix_path = false;
97 sepchar = '\\';
100 if (allow_broken_path && (*pathname != sepchar)) {
101 DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
102 pathname, sepchar ));
104 * Possibly client sent a local path by mistake.
105 * Try and convert to a local path.
106 * Note that this is an SMB1-only fallback
107 * to cope with known broken SMB1 clients.
110 pdp->hostname = eos_ptr; /* "" */
111 pdp->servicename = eos_ptr; /* "" */
113 /* We've got no info about separators. */
114 pdp->posix_path = lp_posix_pathnames();
115 p = temp;
116 DEBUG(10,("parse_dfs_path: trying to convert %s to a "
117 "local path\n",
118 temp));
119 goto local_path;
123 * Safe to use on talloc'ed string as it only shrinks.
124 * It also doesn't affect the eos_ptr.
126 trim_char(temp,sepchar,sepchar);
128 DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
129 temp, sepchar));
131 /* Now tokenize. */
132 /* Parse out hostname. */
133 p = strchr_m(temp,sepchar);
134 if(p == NULL) {
135 DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
136 temp));
138 * Possibly client sent a local path by mistake.
139 * Try and convert to a local path.
142 pdp->hostname = eos_ptr; /* "" */
143 pdp->servicename = eos_ptr; /* "" */
145 p = temp;
146 DEBUG(10,("parse_dfs_path: trying to convert %s "
147 "to a local path\n",
148 temp));
149 goto local_path;
151 *p = '\0';
152 pdp->hostname = temp;
154 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
156 /* Parse out servicename. */
157 servicename = p+1;
158 p = strchr_m(servicename,sepchar);
159 if (p) {
160 *p = '\0';
163 /* Is this really our servicename ? */
164 if (conn && !( strequal(servicename, lp_servicename(talloc_tos(), SNUM(conn)))
165 || (strequal(servicename, HOMES_NAME)
166 && strequal(lp_servicename(talloc_tos(), SNUM(conn)),
167 get_current_username()) )) ) {
168 DEBUG(10,("parse_dfs_path: %s is not our servicename\n",
169 servicename));
172 * Possibly client sent a local path by mistake.
173 * Try and convert to a local path.
176 pdp->hostname = eos_ptr; /* "" */
177 pdp->servicename = eos_ptr; /* "" */
179 /* Repair the path - replace the sepchar's
180 we nulled out */
181 servicename--;
182 *servicename = sepchar;
183 if (p) {
184 *p = sepchar;
187 p = temp;
188 DEBUG(10,("parse_dfs_path: trying to convert %s "
189 "to a local path\n",
190 temp));
191 goto local_path;
194 pdp->servicename = servicename;
196 DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
198 if(p == NULL) {
199 /* Client sent self referral \server\share. */
200 pdp->reqpath = eos_ptr; /* "" */
201 return NT_STATUS_OK;
204 p++;
206 local_path:
208 *ppath_contains_wcard = False;
210 pdp->reqpath = p;
212 /* Rest is reqpath. */
213 if (pdp->posix_path) {
214 status = check_path_syntax_posix(pdp->reqpath);
215 } else {
216 if (allow_wcards) {
217 status = check_path_syntax_wcard(pdp->reqpath,
218 ppath_contains_wcard);
219 } else {
220 status = check_path_syntax(pdp->reqpath);
224 if (!NT_STATUS_IS_OK(status)) {
225 DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
226 p, nt_errstr(status) ));
227 return status;
230 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
231 return NT_STATUS_OK;
234 /********************************************************
235 Fake up a connection struct for the VFS layer, for use in
236 applications (such as the python bindings), that do not want the
237 global working directory changed under them.
239 SMB_VFS_CONNECT requires root privileges.
240 *********************************************************/
242 static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx,
243 struct messaging_context *msg,
244 connection_struct **pconn,
245 int snum,
246 const char *path,
247 const struct auth_session_info *session_info)
249 connection_struct *conn;
250 char *connpath;
251 const char *vfs_user;
252 struct smbd_server_connection *sconn;
253 const char *servicename = lp_const_servicename(snum);
255 sconn = talloc_zero(ctx, struct smbd_server_connection);
256 if (sconn == NULL) {
257 return NT_STATUS_NO_MEMORY;
260 sconn->raw_ev_ctx = samba_tevent_context_init(sconn);
261 if (sconn->raw_ev_ctx == NULL) {
262 TALLOC_FREE(sconn);
263 return NT_STATUS_NO_MEMORY;
266 sconn->root_ev_ctx = sconn->raw_ev_ctx;
267 sconn->guest_ev_ctx = sconn->raw_ev_ctx;
268 sconn->msg_ctx = msg;
270 conn = conn_new(sconn);
271 if (conn == NULL) {
272 TALLOC_FREE(sconn);
273 return NT_STATUS_NO_MEMORY;
276 /* Now we have conn, we need to make sconn a child of conn,
277 * for a proper talloc tree */
278 talloc_steal(conn, sconn);
280 if (snum == -1 && servicename == NULL) {
281 servicename = "Unknown Service (snum == -1)";
284 connpath = talloc_strdup(conn, path);
285 if (!connpath) {
286 TALLOC_FREE(conn);
287 return NT_STATUS_NO_MEMORY;
289 connpath = talloc_string_sub(conn,
290 connpath,
291 "%S",
292 servicename);
293 if (!connpath) {
294 TALLOC_FREE(conn);
295 return NT_STATUS_NO_MEMORY;
298 /* needed for smbd_vfs_init() */
300 conn->params->service = snum;
301 conn->cnum = TID_FIELD_INVALID;
303 if (session_info != NULL) {
304 conn->session_info = copy_session_info(conn, session_info);
305 if (conn->session_info == NULL) {
306 DEBUG(0, ("copy_serverinfo failed\n"));
307 TALLOC_FREE(conn);
308 return NT_STATUS_NO_MEMORY;
310 vfs_user = conn->session_info->unix_info->unix_name;
311 } else {
312 /* use current authenticated user in absence of session_info */
313 vfs_user = get_current_username();
316 conn->user_ev_ctx = sconn->raw_ev_ctx;
318 set_conn_connectpath(conn, connpath);
321 * New code to check if there's a share security descriptor
322 * added from NT server manager. This is done after the
323 * smb.conf checks are done as we need a uid and token. JRA.
326 if (conn->session_info) {
327 share_access_check(conn->session_info->security_token,
328 servicename,
329 MAXIMUM_ALLOWED_ACCESS,
330 &conn->share_access);
332 if ((conn->share_access & FILE_WRITE_DATA) == 0) {
333 if ((conn->share_access & FILE_READ_DATA) == 0) {
334 /* No access, read or write. */
335 DEBUG(3,("create_conn_struct: connection to %s "
336 "denied due to security "
337 "descriptor.\n",
338 servicename));
339 conn_free(conn);
340 return NT_STATUS_ACCESS_DENIED;
341 } else {
342 conn->read_only = true;
345 } else {
346 conn->share_access = 0;
347 conn->read_only = true;
350 if (!smbd_vfs_init(conn)) {
351 NTSTATUS status = map_nt_error_from_unix(errno);
352 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
353 conn_free(conn);
354 return status;
357 /* this must be the first filesystem operation that we do */
358 if (SMB_VFS_CONNECT(conn, servicename, vfs_user) < 0) {
359 DEBUG(0,("VFS connect failed!\n"));
360 conn_free(conn);
361 return NT_STATUS_UNSUCCESSFUL;
364 talloc_free(conn->origpath);
365 conn->origpath = talloc_strdup(conn, conn->connectpath);
366 if (conn->origpath == NULL) {
367 conn_free(conn);
368 return NT_STATUS_NO_MEMORY;
371 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
372 conn->tcon_done = true;
373 *pconn = talloc_move(ctx, &conn);
375 return NT_STATUS_OK;
378 static int conn_struct_tos_destructor(struct conn_struct_tos *c)
380 if (c->oldcwd_fname != NULL) {
381 vfs_ChDir(c->conn, c->oldcwd_fname);
382 TALLOC_FREE(c->oldcwd_fname);
384 SMB_VFS_DISCONNECT(c->conn);
385 conn_free(c->conn);
386 return 0;
389 /********************************************************
390 Fake up a connection struct for the VFS layer, for use in
391 applications (such as the python bindings), that do not want the
392 global working directory changed under them.
394 SMB_VFS_CONNECT requires root privileges.
395 This temporary uses become_root() and unbecome_root().
397 But further impersonation has to be cone by the caller.
398 *********************************************************/
399 NTSTATUS create_conn_struct_tos(struct messaging_context *msg,
400 int snum,
401 const char *path,
402 const struct auth_session_info *session_info,
403 struct conn_struct_tos **_c)
405 struct conn_struct_tos *c = NULL;
406 NTSTATUS status;
408 *_c = NULL;
410 c = talloc_zero(talloc_tos(), struct conn_struct_tos);
411 if (c == NULL) {
412 return NT_STATUS_NO_MEMORY;
415 become_root();
416 status = create_conn_struct_as_root(c,
417 msg,
418 &c->conn,
419 snum,
420 path,
421 session_info);
422 unbecome_root();
423 if (!NT_STATUS_IS_OK(status)) {
424 TALLOC_FREE(c);
425 return status;
428 talloc_set_destructor(c, conn_struct_tos_destructor);
430 *_c = c;
431 return NT_STATUS_OK;
434 /********************************************************
435 Fake up a connection struct for the VFS layer.
436 Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
438 See also the comment for create_conn_struct_tos() above!
440 The CWD change is reverted by the destructor of
441 conn_struct_tos when the current talloc_tos() is destroyed.
442 *********************************************************/
443 NTSTATUS create_conn_struct_tos_cwd(struct messaging_context *msg,
444 int snum,
445 const char *path,
446 const struct auth_session_info *session_info,
447 struct conn_struct_tos **_c)
449 struct conn_struct_tos *c = NULL;
450 struct smb_filename smb_fname_connectpath = {0};
451 NTSTATUS status;
453 *_c = NULL;
455 status = create_conn_struct_tos(msg,
456 snum,
457 path,
458 session_info,
459 &c);
460 if (!NT_STATUS_IS_OK(status)) {
461 return status;
465 * Windows seems to insist on doing trans2getdfsreferral() calls on
466 * the IPC$ share as the anonymous user. If we try to chdir as that
467 * user we will fail.... WTF ? JRA.
470 c->oldcwd_fname = vfs_GetWd(c, c->conn);
471 if (c->oldcwd_fname == NULL) {
472 status = map_nt_error_from_unix(errno);
473 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
474 TALLOC_FREE(c);
475 return status;
478 smb_fname_connectpath = (struct smb_filename) {
479 .base_name = c->conn->connectpath
482 if (vfs_ChDir(c->conn, &smb_fname_connectpath) != 0) {
483 status = map_nt_error_from_unix(errno);
484 DBG_NOTICE("Can't ChDir to new conn path %s. "
485 "Error was %s\n",
486 c->conn->connectpath, strerror(errno));
487 TALLOC_FREE(c->oldcwd_fname);
488 TALLOC_FREE(c);
489 return status;
492 *_c = c;
493 return NT_STATUS_OK;
496 static void shuffle_strlist(char **list, int count)
498 int i;
499 uint32_t r;
500 char *tmp;
502 for (i = count; i > 1; i--) {
503 r = generate_random() % i;
505 tmp = list[i-1];
506 list[i-1] = list[r];
507 list[r] = tmp;
511 /**********************************************************************
512 Parse the contents of a symlink to verify if it is an msdfs referral
513 A valid referral is of the form:
515 msdfs:server1\share1,server2\share2
516 msdfs:server1\share1\pathname,server2\share2\pathname
517 msdfs:server1/share1,server2/share2
518 msdfs:server1/share1/pathname,server2/share2/pathname.
520 Note that the alternate paths returned here must be of the canonicalized
521 form:
523 \server\share or
524 \server\share\path\to\file,
526 even in posix path mode. This is because we have no knowledge if the
527 server we're referring to understands posix paths.
528 **********************************************************************/
530 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
531 int snum,
532 const char *target,
533 struct referral **preflist,
534 int *refcount)
536 char *temp = NULL;
537 char *prot;
538 char **alt_path = NULL;
539 int count = 0, i;
540 struct referral *reflist;
541 char *saveptr;
543 temp = talloc_strdup(ctx, target);
544 if (!temp) {
545 return False;
547 prot = strtok_r(temp, ":", &saveptr);
548 if (!prot) {
549 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
550 return False;
553 alt_path = talloc_array(ctx, char *, MAX_REFERRAL_COUNT);
554 if (!alt_path) {
555 return False;
558 /* parse out the alternate paths */
559 while((count<MAX_REFERRAL_COUNT) &&
560 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
561 count++;
564 /* shuffle alternate paths */
565 if (lp_msdfs_shuffle_referrals(snum)) {
566 shuffle_strlist(alt_path, count);
569 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
571 if (count) {
572 reflist = *preflist = talloc_zero_array(ctx,
573 struct referral, count);
574 if(reflist == NULL) {
575 TALLOC_FREE(alt_path);
576 return False;
578 } else {
579 reflist = *preflist = NULL;
582 for(i=0;i<count;i++) {
583 char *p;
585 /* Canonicalize link target.
586 * Replace all /'s in the path by a \ */
587 string_replace(alt_path[i], '/', '\\');
589 /* Remove leading '\\'s */
590 p = alt_path[i];
591 while (*p && (*p == '\\')) {
592 p++;
595 reflist[i].alternate_path = talloc_asprintf(ctx,
596 "\\%s",
598 if (!reflist[i].alternate_path) {
599 return False;
602 reflist[i].proximity = 0;
603 reflist[i].ttl = REFERRAL_TTL;
604 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
605 reflist[i].alternate_path));
608 *refcount = count;
610 TALLOC_FREE(alt_path);
611 return True;
614 /**********************************************************************
615 Returns true if the unix path is a valid msdfs symlink and also
616 returns the target string from inside the link.
617 **********************************************************************/
619 static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
620 connection_struct *conn,
621 struct smb_filename *smb_fname,
622 char **pp_link_target)
624 int referral_len = 0;
625 #if defined(HAVE_BROKEN_READLINK)
626 char link_target_buf[PATH_MAX];
627 #else
628 char link_target_buf[7];
629 #endif
630 size_t bufsize = 0;
631 char *link_target = NULL;
633 if (pp_link_target) {
634 bufsize = 1024;
635 link_target = talloc_array(ctx, char, bufsize);
636 if (!link_target) {
637 return False;
639 *pp_link_target = link_target;
640 } else {
641 bufsize = sizeof(link_target_buf);
642 link_target = link_target_buf;
645 if (SMB_VFS_LSTAT(conn, smb_fname) != 0) {
646 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
647 smb_fname->base_name));
648 goto err;
650 if (!S_ISLNK(smb_fname->st.st_ex_mode)) {
651 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
652 smb_fname->base_name));
653 goto err;
656 referral_len = SMB_VFS_READLINK(conn, smb_fname,
657 link_target, bufsize - 1);
658 if (referral_len == -1) {
659 DEBUG(0,("is_msdfs_link_read_target: Error reading "
660 "msdfs link %s: %s\n",
661 smb_fname->base_name, strerror(errno)));
662 goto err;
664 link_target[referral_len] = '\0';
666 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n", smb_fname->base_name,
667 link_target));
669 if (!strnequal(link_target, "msdfs:", 6)) {
670 goto err;
672 return True;
674 err:
676 if (link_target != link_target_buf) {
677 TALLOC_FREE(link_target);
679 return False;
682 /**********************************************************************
683 Returns true if the unix path is a valid msdfs symlink.
684 **********************************************************************/
686 bool is_msdfs_link(connection_struct *conn,
687 struct smb_filename *smb_fname)
689 return is_msdfs_link_internal(talloc_tos(),
690 conn,
691 smb_fname,
692 NULL);
695 /*****************************************************************
696 Used by other functions to decide if a dfs path is remote,
697 and to get the list of referred locations for that remote path.
699 search_flag: For findfirsts, dfs links themselves are not
700 redirected, but paths beyond the links are. For normal smb calls,
701 even dfs links need to be redirected.
703 consumedcntp: how much of the dfs path is being redirected. the client
704 should try the remaining path on the redirected server.
706 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
707 link redirect are in targetpath.
708 *****************************************************************/
710 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
711 connection_struct *conn,
712 const char *dfspath, /* Incoming complete dfs path */
713 const struct dfs_path *pdp, /* Parsed out
714 server+share+extrapath. */
715 uint32_t ucf_flags,
716 int *consumedcntp,
717 char **pp_targetpath)
719 char *p = NULL;
720 char *q = NULL;
721 NTSTATUS status;
722 struct smb_filename *smb_fname = NULL;
723 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
724 components). */
726 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
727 conn->connectpath, pdp->reqpath));
730 * Note the unix path conversion here we're doing we
731 * throw away. We're looking for a symlink for a dfs
732 * resolution, if we don't find it we'll do another
733 * unix_convert later in the codepath.
736 status = unix_convert(ctx, conn, pdp->reqpath, &smb_fname,
737 ucf_flags);
739 if (!NT_STATUS_IS_OK(status)) {
740 if (!NT_STATUS_EQUAL(status,
741 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
742 return status;
744 if (smb_fname == NULL || smb_fname->base_name == NULL) {
745 return status;
749 /* Optimization - check if we can redirect the whole path. */
751 if (is_msdfs_link_internal(ctx, conn, smb_fname, pp_targetpath)) {
752 /* XX_ALLOW_WCARD_XXX is called from search functions. */
753 if (ucf_flags &
754 (UCF_COND_ALLOW_WCARD_LCOMP|
755 UCF_ALWAYS_ALLOW_WCARD_LCOMP)) {
756 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
757 "for dfs link %s.\n", dfspath));
758 status = NT_STATUS_OK;
759 goto out;
762 DEBUG(6,("dfs_path_lookup: %s resolves to a "
763 "valid dfs link %s.\n", dfspath,
764 pp_targetpath ? *pp_targetpath : ""));
766 if (consumedcntp) {
767 *consumedcntp = strlen(dfspath);
769 status = NT_STATUS_PATH_NOT_COVERED;
770 goto out;
773 /* Prepare to test only for '/' components in the given path,
774 * so if a Windows path replace all '\\' characters with '/'.
775 * For a POSIX DFS path we know all separators are already '/'. */
777 canon_dfspath = talloc_strdup(ctx, dfspath);
778 if (!canon_dfspath) {
779 status = NT_STATUS_NO_MEMORY;
780 goto out;
782 if (!pdp->posix_path) {
783 string_replace(canon_dfspath, '\\', '/');
787 * localpath comes out of unix_convert, so it has
788 * no trailing backslash. Make sure that canon_dfspath hasn't either.
789 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
792 trim_char(canon_dfspath,0,'/');
795 * Redirect if any component in the path is a link.
796 * We do this by walking backwards through the
797 * local path, chopping off the last component
798 * in both the local path and the canonicalized
799 * DFS path. If we hit a DFS link then we're done.
802 p = strrchr_m(smb_fname->base_name, '/');
803 if (consumedcntp) {
804 q = strrchr_m(canon_dfspath, '/');
807 while (p) {
808 *p = '\0';
809 if (q) {
810 *q = '\0';
813 if (is_msdfs_link_internal(ctx, conn,
814 smb_fname, pp_targetpath)) {
815 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
816 "parent %s is dfs link\n", dfspath,
817 smb_fname_str_dbg(smb_fname)));
819 if (consumedcntp) {
820 *consumedcntp = strlen(canon_dfspath);
821 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
822 "(%d)\n",
823 canon_dfspath,
824 *consumedcntp));
827 status = NT_STATUS_PATH_NOT_COVERED;
828 goto out;
831 /* Step back on the filesystem. */
832 p = strrchr_m(smb_fname->base_name, '/');
834 if (consumedcntp) {
835 /* And in the canonicalized dfs path. */
836 q = strrchr_m(canon_dfspath, '/');
840 status = NT_STATUS_OK;
841 out:
842 TALLOC_FREE(smb_fname);
843 return status;
846 /*****************************************************************
847 Decides if a dfs pathname should be redirected or not.
848 If not, the pathname is converted to a tcon-relative local unix path
850 search_wcard_flag: this flag performs 2 functions both related
851 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
852 for details.
854 This function can return NT_STATUS_OK, meaning use the returned path as-is
855 (mapped into a local path).
856 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
857 any other NT_STATUS error which is a genuine error to be
858 returned to the client.
859 *****************************************************************/
861 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
862 connection_struct *conn,
863 const char *path_in,
864 uint32_t ucf_flags,
865 bool allow_broken_path,
866 char **pp_path_out,
867 bool *ppath_contains_wcard)
869 NTSTATUS status;
870 bool search_wcard_flag = (ucf_flags &
871 (UCF_COND_ALLOW_WCARD_LCOMP|UCF_ALWAYS_ALLOW_WCARD_LCOMP));
872 struct dfs_path *pdp = talloc(ctx, struct dfs_path);
874 if (!pdp) {
875 return NT_STATUS_NO_MEMORY;
878 status = parse_dfs_path(conn, path_in, search_wcard_flag,
879 allow_broken_path, pdp,
880 ppath_contains_wcard);
881 if (!NT_STATUS_IS_OK(status)) {
882 TALLOC_FREE(pdp);
883 return status;
886 if (pdp->reqpath[0] == '\0') {
887 TALLOC_FREE(pdp);
888 *pp_path_out = talloc_strdup(ctx, "");
889 if (!*pp_path_out) {
890 return NT_STATUS_NO_MEMORY;
892 DEBUG(5,("dfs_redirect: self-referral.\n"));
893 return NT_STATUS_OK;
896 /* If dfs pathname for a non-dfs share, convert to tcon-relative
897 path and return OK */
899 if (!lp_msdfs_root(SNUM(conn))) {
900 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
901 TALLOC_FREE(pdp);
902 if (!*pp_path_out) {
903 return NT_STATUS_NO_MEMORY;
905 return NT_STATUS_OK;
908 /* If it looked like a local path (zero hostname/servicename)
909 * just treat as a tcon-relative path. */
911 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
912 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
913 TALLOC_FREE(pdp);
914 if (!*pp_path_out) {
915 return NT_STATUS_NO_MEMORY;
917 return NT_STATUS_OK;
920 if (!( strequal(pdp->servicename, lp_servicename(talloc_tos(), SNUM(conn)))
921 || (strequal(pdp->servicename, HOMES_NAME)
922 && strequal(lp_servicename(talloc_tos(), SNUM(conn)),
923 conn->session_info->unix_info->sanitized_username) )) ) {
925 /* The given sharename doesn't match this connection. */
926 TALLOC_FREE(pdp);
928 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
931 status = dfs_path_lookup(ctx, conn, path_in, pdp,
932 ucf_flags, NULL, NULL);
933 if (!NT_STATUS_IS_OK(status)) {
934 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
935 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
936 } else {
937 DEBUG(10,("dfs_redirect: dfs_path_lookup "
938 "failed for %s with %s\n",
939 path_in, nt_errstr(status) ));
941 return status;
944 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
946 /* Form non-dfs tcon-relative path */
947 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
948 TALLOC_FREE(pdp);
949 if (!*pp_path_out) {
950 return NT_STATUS_NO_MEMORY;
953 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
954 path_in,
955 *pp_path_out));
957 return NT_STATUS_OK;
960 /**********************************************************************
961 Return a self referral.
962 **********************************************************************/
964 static NTSTATUS self_ref(TALLOC_CTX *ctx,
965 const char *dfs_path,
966 struct junction_map *jucn,
967 int *consumedcntp,
968 bool *self_referralp)
970 struct referral *ref;
972 *self_referralp = True;
974 jucn->referral_count = 1;
975 if((ref = talloc_zero(ctx, struct referral)) == NULL) {
976 return NT_STATUS_NO_MEMORY;
979 ref->alternate_path = talloc_strdup(ctx, dfs_path);
980 if (!ref->alternate_path) {
981 TALLOC_FREE(ref);
982 return NT_STATUS_NO_MEMORY;
984 ref->proximity = 0;
985 ref->ttl = REFERRAL_TTL;
986 jucn->referral_list = ref;
987 *consumedcntp = strlen(dfs_path);
988 return NT_STATUS_OK;
991 /**********************************************************************
992 Gets valid referrals for a dfs path and fills up the
993 junction_map structure.
994 **********************************************************************/
996 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
997 const char *dfs_path,
998 const struct tsocket_address *remote_address,
999 const struct tsocket_address *local_address,
1000 bool allow_broken_path,
1001 struct junction_map *jucn,
1002 int *consumedcntp,
1003 bool *self_referralp)
1005 TALLOC_CTX *frame = talloc_stackframe();
1006 struct conn_struct_tos *c = NULL;
1007 struct connection_struct *conn = NULL;
1008 char *targetpath = NULL;
1009 int snum;
1010 NTSTATUS status = NT_STATUS_NOT_FOUND;
1011 bool dummy;
1012 struct dfs_path *pdp = talloc_zero(frame, struct dfs_path);
1014 if (!pdp) {
1015 TALLOC_FREE(frame);
1016 return NT_STATUS_NO_MEMORY;
1019 *self_referralp = False;
1021 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1022 pdp, &dummy);
1023 if (!NT_STATUS_IS_OK(status)) {
1024 TALLOC_FREE(frame);
1025 return status;
1028 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1029 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1030 if (!jucn->service_name || !jucn->volume_name) {
1031 TALLOC_FREE(frame);
1032 return NT_STATUS_NO_MEMORY;
1035 /* Verify the share is a dfs root */
1036 snum = lp_servicenumber(jucn->service_name);
1037 if(snum < 0) {
1038 char *service_name = NULL;
1039 if ((snum = find_service(ctx, jucn->service_name, &service_name)) < 0) {
1040 TALLOC_FREE(frame);
1041 return NT_STATUS_NOT_FOUND;
1043 if (!service_name) {
1044 TALLOC_FREE(frame);
1045 return NT_STATUS_NO_MEMORY;
1047 TALLOC_FREE(jucn->service_name);
1048 jucn->service_name = talloc_strdup(ctx, service_name);
1049 if (!jucn->service_name) {
1050 TALLOC_FREE(frame);
1051 return NT_STATUS_NO_MEMORY;
1055 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(talloc_tos(), snum) == '\0')) {
1056 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
1057 "a dfs root.\n",
1058 pdp->servicename, dfs_path));
1059 TALLOC_FREE(frame);
1060 return NT_STATUS_NOT_FOUND;
1064 * Self referrals are tested with a anonymous IPC connection and
1065 * a GET_DFS_REFERRAL call to \\server\share. (which means
1066 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
1067 * into the directory and will fail if it cannot (as the anonymous
1068 * user). Cope with this.
1071 if (pdp->reqpath[0] == '\0') {
1072 char *tmp;
1073 struct referral *ref;
1074 int refcount;
1076 if (*lp_msdfs_proxy(talloc_tos(), snum) == '\0') {
1077 TALLOC_FREE(frame);
1078 return self_ref(ctx,
1079 dfs_path,
1080 jucn,
1081 consumedcntp,
1082 self_referralp);
1086 * It's an msdfs proxy share. Redirect to
1087 * the configured target share.
1090 tmp = talloc_asprintf(frame, "msdfs:%s",
1091 lp_msdfs_proxy(frame, snum));
1092 if (tmp == NULL) {
1093 TALLOC_FREE(frame);
1094 return NT_STATUS_NO_MEMORY;
1097 if (!parse_msdfs_symlink(ctx, snum, tmp, &ref, &refcount)) {
1098 TALLOC_FREE(frame);
1099 return NT_STATUS_INVALID_PARAMETER;
1101 jucn->referral_count = refcount;
1102 jucn->referral_list = ref;
1103 *consumedcntp = strlen(dfs_path);
1104 TALLOC_FREE(frame);
1105 return NT_STATUS_OK;
1108 status = create_conn_struct_tos_cwd(server_messaging_context(),
1109 snum,
1110 lp_path(frame, snum),
1111 NULL,
1112 &c);
1113 if (!NT_STATUS_IS_OK(status)) {
1114 TALLOC_FREE(frame);
1115 return status;
1117 conn = c->conn;
1120 * TODO
1122 * The remote and local address should be passed down to
1123 * create_conn_struct_cwd.
1125 if (conn->sconn->remote_address == NULL) {
1126 conn->sconn->remote_address =
1127 tsocket_address_copy(remote_address, conn->sconn);
1128 if (conn->sconn->remote_address == NULL) {
1129 TALLOC_FREE(frame);
1130 return NT_STATUS_NO_MEMORY;
1133 if (conn->sconn->local_address == NULL) {
1134 conn->sconn->local_address =
1135 tsocket_address_copy(local_address, conn->sconn);
1136 if (conn->sconn->local_address == NULL) {
1137 TALLOC_FREE(frame);
1138 return NT_STATUS_NO_MEMORY;
1142 /* If this is a DFS path dfs_lookup should return
1143 * NT_STATUS_PATH_NOT_COVERED. */
1145 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
1146 0, consumedcntp, &targetpath);
1148 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
1149 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
1150 dfs_path));
1151 if (NT_STATUS_IS_OK(status)) {
1153 * We are in an error path here (we
1154 * know it's not a DFS path), but
1155 * dfs_path_lookup() can return
1156 * NT_STATUS_OK. Ensure we always
1157 * return a valid error code.
1159 * #9588 - ACLs are not inherited to directories
1160 * for DFS shares.
1162 status = NT_STATUS_NOT_FOUND;
1164 goto err_exit;
1167 /* We know this is a valid dfs link. Parse the targetpath. */
1168 if (!parse_msdfs_symlink(ctx, snum, targetpath,
1169 &jucn->referral_list,
1170 &jucn->referral_count)) {
1171 DEBUG(3,("get_referred_path: failed to parse symlink "
1172 "target %s\n", targetpath ));
1173 status = NT_STATUS_NOT_FOUND;
1174 goto err_exit;
1177 status = NT_STATUS_OK;
1178 err_exit:
1179 TALLOC_FREE(frame);
1180 return status;
1183 /******************************************************************
1184 Set up the DFS referral for the dfs pathname. This call returns
1185 the amount of the path covered by this server, and where the
1186 client should be redirected to. This is the meat of the
1187 TRANS2_GET_DFS_REFERRAL call.
1188 ******************************************************************/
1190 int setup_dfs_referral(connection_struct *orig_conn,
1191 const char *dfs_path,
1192 int max_referral_level,
1193 char **ppdata, NTSTATUS *pstatus)
1195 char *pdata = *ppdata;
1196 int reply_size = 0;
1197 struct dfs_GetDFSReferral *r;
1198 DATA_BLOB blob = data_blob_null;
1199 NTSTATUS status;
1200 enum ndr_err_code ndr_err;
1202 r = talloc_zero(talloc_tos(), struct dfs_GetDFSReferral);
1203 if (r == NULL) {
1204 *pstatus = NT_STATUS_NO_MEMORY;
1205 return -1;
1208 r->in.req.max_referral_level = max_referral_level;
1209 r->in.req.servername = talloc_strdup(r, dfs_path);
1210 if (r->in.req.servername == NULL) {
1211 talloc_free(r);
1212 *pstatus = NT_STATUS_NO_MEMORY;
1213 return -1;
1216 status = SMB_VFS_GET_DFS_REFERRALS(orig_conn, r);
1217 if (!NT_STATUS_IS_OK(status)) {
1218 talloc_free(r);
1219 *pstatus = status;
1220 return -1;
1223 ndr_err = ndr_push_struct_blob(&blob, r,
1224 r->out.resp,
1225 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1226 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1227 TALLOC_FREE(r);
1228 *pstatus = NT_STATUS_INVALID_PARAMETER;
1229 return -1;
1232 pdata = (char *)SMB_REALLOC(pdata, blob.length);
1233 if(pdata == NULL) {
1234 TALLOC_FREE(r);
1235 DEBUG(0,("referral setup:"
1236 "malloc failed for Realloc!\n"));
1237 return -1;
1239 *ppdata = pdata;
1240 reply_size = blob.length;
1241 memcpy(pdata, blob.data, blob.length);
1242 TALLOC_FREE(r);
1244 *pstatus = NT_STATUS_OK;
1245 return reply_size;
1248 /**********************************************************************
1249 The following functions are called by the NETDFS RPC pipe functions
1250 **********************************************************************/
1252 /*********************************************************************
1253 Creates a junction structure from a DFS pathname
1254 **********************************************************************/
1256 bool create_junction(TALLOC_CTX *ctx,
1257 const char *dfs_path,
1258 bool allow_broken_path,
1259 struct junction_map *jucn)
1261 int snum;
1262 bool dummy;
1263 struct dfs_path *pdp = talloc(ctx,struct dfs_path);
1264 NTSTATUS status;
1266 if (!pdp) {
1267 return False;
1269 status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1270 pdp, &dummy);
1271 if (!NT_STATUS_IS_OK(status)) {
1272 return False;
1275 /* check if path is dfs : validate first token */
1276 if (!is_myname_or_ipaddr(pdp->hostname)) {
1277 DEBUG(4,("create_junction: Invalid hostname %s "
1278 "in dfs path %s\n",
1279 pdp->hostname, dfs_path));
1280 TALLOC_FREE(pdp);
1281 return False;
1284 /* Check for a non-DFS share */
1285 snum = lp_servicenumber(pdp->servicename);
1287 if(snum < 0 || !lp_msdfs_root(snum)) {
1288 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1289 pdp->servicename));
1290 TALLOC_FREE(pdp);
1291 return False;
1294 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1295 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1296 jucn->comment = lp_comment(ctx, snum);
1298 TALLOC_FREE(pdp);
1299 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1300 return False;
1302 return True;
1305 /**********************************************************************
1306 Forms a valid Unix pathname from the junction
1307 **********************************************************************/
1309 static bool junction_to_local_path_tos(const struct junction_map *jucn,
1310 char **pp_path_out,
1311 connection_struct **conn_out)
1313 struct conn_struct_tos *c = NULL;
1314 int snum;
1315 char *path_out = NULL;
1316 NTSTATUS status;
1318 snum = lp_servicenumber(jucn->service_name);
1319 if(snum < 0) {
1320 return False;
1322 status = create_conn_struct_tos_cwd(server_messaging_context(),
1323 snum,
1324 lp_path(talloc_tos(), snum),
1325 NULL,
1326 &c);
1327 if (!NT_STATUS_IS_OK(status)) {
1328 return False;
1331 path_out = talloc_asprintf(c,
1332 "%s/%s",
1333 lp_path(talloc_tos(), snum),
1334 jucn->volume_name);
1335 if (path_out == NULL) {
1336 TALLOC_FREE(c);
1337 return False;
1339 *pp_path_out = path_out;
1340 *conn_out = c->conn;
1341 return True;
1344 bool create_msdfs_link(const struct junction_map *jucn)
1346 TALLOC_CTX *frame = talloc_stackframe();
1347 char *path = NULL;
1348 char *msdfs_link = NULL;
1349 connection_struct *conn;
1350 int i=0;
1351 bool insert_comma = False;
1352 bool ret = False;
1353 struct smb_filename *smb_fname = NULL;
1354 bool ok;
1356 ok = junction_to_local_path_tos(jucn, &path, &conn);
1357 if (!ok) {
1358 TALLOC_FREE(frame);
1359 return False;
1362 /* Form the msdfs_link contents */
1363 msdfs_link = talloc_strdup(conn, "msdfs:");
1364 if (!msdfs_link) {
1365 goto out;
1367 for(i=0; i<jucn->referral_count; i++) {
1368 char *refpath = jucn->referral_list[i].alternate_path;
1370 /* Alternate paths always use Windows separators. */
1371 trim_char(refpath, '\\', '\\');
1372 if(*refpath == '\0') {
1373 if (i == 0) {
1374 insert_comma = False;
1376 continue;
1378 if (i > 0 && insert_comma) {
1379 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1380 ",%s",
1381 refpath);
1382 } else {
1383 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1384 "%s",
1385 refpath);
1388 if (!msdfs_link) {
1389 goto out;
1391 if (!insert_comma) {
1392 insert_comma = True;
1396 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1397 path, msdfs_link));
1399 smb_fname = synthetic_smb_fname(frame,
1400 path,
1401 NULL,
1402 NULL,
1404 if (smb_fname == NULL) {
1405 errno = ENOMEM;
1406 goto out;
1409 if(SMB_VFS_SYMLINK(conn, msdfs_link, smb_fname) < 0) {
1410 if (errno == EEXIST) {
1411 if(SMB_VFS_UNLINK(conn, smb_fname)!=0) {
1412 TALLOC_FREE(smb_fname);
1413 goto out;
1416 if (SMB_VFS_SYMLINK(conn, msdfs_link, smb_fname) < 0) {
1417 DEBUG(1,("create_msdfs_link: symlink failed "
1418 "%s -> %s\nError: %s\n",
1419 path, msdfs_link, strerror(errno)));
1420 goto out;
1424 ret = True;
1426 out:
1427 TALLOC_FREE(frame);
1428 return ret;
1431 bool remove_msdfs_link(const struct junction_map *jucn)
1433 TALLOC_CTX *frame = talloc_stackframe();
1434 char *path = NULL;
1435 connection_struct *conn;
1436 bool ret = False;
1437 struct smb_filename *smb_fname;
1438 bool ok;
1440 ok = junction_to_local_path_tos(jucn, &path, &conn);
1441 if (!ok) {
1442 TALLOC_FREE(frame);
1443 return false;
1446 smb_fname = synthetic_smb_fname(frame,
1447 path,
1448 NULL,
1449 NULL,
1451 if (smb_fname == NULL) {
1452 TALLOC_FREE(frame);
1453 errno = ENOMEM;
1454 return false;
1457 if( SMB_VFS_UNLINK(conn, smb_fname) == 0 ) {
1458 ret = True;
1461 TALLOC_FREE(frame);
1462 return ret;
1465 /*********************************************************************
1466 Return the number of DFS links at the root of this share.
1467 *********************************************************************/
1469 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1471 TALLOC_CTX *frame = talloc_stackframe();
1472 size_t cnt = 0;
1473 DIR *dirp = NULL;
1474 const char *dname = NULL;
1475 char *talloced = NULL;
1476 const char *connect_path = lp_path(frame, snum);
1477 const char *msdfs_proxy = lp_msdfs_proxy(frame, snum);
1478 struct conn_struct_tos *c = NULL;
1479 connection_struct *conn = NULL;
1480 NTSTATUS status;
1481 struct smb_filename *smb_fname = NULL;
1483 if(*connect_path == '\0') {
1484 TALLOC_FREE(frame);
1485 return 0;
1489 * Fake up a connection struct for the VFS layer.
1492 status = create_conn_struct_tos_cwd(server_messaging_context(),
1493 snum,
1494 connect_path,
1495 NULL,
1496 &c);
1497 if (!NT_STATUS_IS_OK(status)) {
1498 DEBUG(3, ("create_conn_struct failed: %s\n",
1499 nt_errstr(status)));
1500 TALLOC_FREE(frame);
1501 return 0;
1503 conn = c->conn;
1505 /* Count a link for the msdfs root - convention */
1506 cnt = 1;
1508 /* No more links if this is an msdfs proxy. */
1509 if (*msdfs_proxy != '\0') {
1510 goto out;
1513 smb_fname = synthetic_smb_fname(frame,
1514 ".",
1515 NULL,
1516 NULL,
1518 if (smb_fname == NULL) {
1519 goto out;
1522 /* Now enumerate all dfs links */
1523 dirp = SMB_VFS_OPENDIR(conn, smb_fname, NULL, 0);
1524 if(!dirp) {
1525 goto out;
1528 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1529 != NULL) {
1530 struct smb_filename *smb_dname =
1531 synthetic_smb_fname(frame,
1532 dname,
1533 NULL,
1534 NULL,
1536 if (smb_dname == NULL) {
1537 goto out;
1539 if (is_msdfs_link(conn, smb_dname)) {
1540 cnt++;
1542 TALLOC_FREE(talloced);
1543 TALLOC_FREE(smb_dname);
1546 SMB_VFS_CLOSEDIR(conn,dirp);
1548 out:
1549 TALLOC_FREE(frame);
1550 return cnt;
1553 /*********************************************************************
1554 *********************************************************************/
1556 static int form_junctions(TALLOC_CTX *ctx,
1557 int snum,
1558 struct junction_map *jucn,
1559 size_t jn_remain)
1561 TALLOC_CTX *frame = talloc_stackframe();
1562 size_t cnt = 0;
1563 DIR *dirp = NULL;
1564 const char *dname = NULL;
1565 char *talloced = NULL;
1566 const char *connect_path = lp_path(frame, snum);
1567 char *service_name = lp_servicename(frame, snum);
1568 const char *msdfs_proxy = lp_msdfs_proxy(frame, snum);
1569 struct conn_struct_tos *c = NULL;
1570 connection_struct *conn = NULL;
1571 struct referral *ref = NULL;
1572 struct smb_filename *smb_fname = NULL;
1573 NTSTATUS status;
1575 if (jn_remain == 0) {
1576 TALLOC_FREE(frame);
1577 return 0;
1580 if(*connect_path == '\0') {
1581 TALLOC_FREE(frame);
1582 return 0;
1586 * Fake up a connection struct for the VFS layer.
1589 status = create_conn_struct_tos_cwd(server_messaging_context(),
1590 snum,
1591 connect_path,
1592 NULL,
1593 &c);
1594 if (!NT_STATUS_IS_OK(status)) {
1595 DEBUG(3, ("create_conn_struct failed: %s\n",
1596 nt_errstr(status)));
1597 TALLOC_FREE(frame);
1598 return 0;
1600 conn = c->conn;
1602 /* form a junction for the msdfs root - convention
1603 DO NOT REMOVE THIS: NT clients will not work with us
1604 if this is not present
1606 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1607 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1608 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1609 goto out;
1611 jucn[cnt].comment = "";
1612 jucn[cnt].referral_count = 1;
1614 ref = jucn[cnt].referral_list = talloc_zero(ctx, struct referral);
1615 if (jucn[cnt].referral_list == NULL) {
1616 goto out;
1619 ref->proximity = 0;
1620 ref->ttl = REFERRAL_TTL;
1621 if (*msdfs_proxy != '\0') {
1622 ref->alternate_path = talloc_strdup(ctx,
1623 msdfs_proxy);
1624 } else {
1625 ref->alternate_path = talloc_asprintf(ctx,
1626 "\\\\%s\\%s",
1627 get_local_machine_name(),
1628 service_name);
1631 if (!ref->alternate_path) {
1632 goto out;
1634 cnt++;
1636 /* Don't enumerate if we're an msdfs proxy. */
1637 if (*msdfs_proxy != '\0') {
1638 goto out;
1641 smb_fname = synthetic_smb_fname(frame,
1642 ".",
1643 NULL,
1644 NULL,
1646 if (smb_fname == NULL) {
1647 goto out;
1650 /* Now enumerate all dfs links */
1651 dirp = SMB_VFS_OPENDIR(conn, smb_fname, NULL, 0);
1652 if(!dirp) {
1653 goto out;
1656 while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1657 != NULL) {
1658 char *link_target = NULL;
1659 struct smb_filename *smb_dname = NULL;
1661 if (cnt >= jn_remain) {
1662 DEBUG(2, ("form_junctions: ran out of MSDFS "
1663 "junction slots"));
1664 TALLOC_FREE(talloced);
1665 goto out;
1667 smb_dname = synthetic_smb_fname(talloc_tos(),
1668 dname,
1669 NULL,
1670 NULL,
1672 if (smb_dname == NULL) {
1673 TALLOC_FREE(talloced);
1674 goto out;
1676 if (is_msdfs_link_internal(ctx,
1677 conn,
1678 smb_dname, &link_target)) {
1679 if (parse_msdfs_symlink(ctx, snum,
1680 link_target,
1681 &jucn[cnt].referral_list,
1682 &jucn[cnt].referral_count)) {
1684 jucn[cnt].service_name = talloc_strdup(ctx,
1685 service_name);
1686 jucn[cnt].volume_name = talloc_strdup(ctx,
1687 dname);
1688 if (!jucn[cnt].service_name ||
1689 !jucn[cnt].volume_name) {
1690 TALLOC_FREE(talloced);
1691 goto out;
1693 jucn[cnt].comment = "";
1694 cnt++;
1696 TALLOC_FREE(link_target);
1698 TALLOC_FREE(talloced);
1699 TALLOC_FREE(smb_dname);
1702 out:
1704 if (dirp) {
1705 SMB_VFS_CLOSEDIR(conn,dirp);
1708 TALLOC_FREE(frame);
1709 return cnt;
1712 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1714 struct junction_map *jn = NULL;
1715 int i=0;
1716 size_t jn_count = 0;
1717 int sharecount = 0;
1719 *p_num_jn = 0;
1720 if(!lp_host_msdfs()) {
1721 return NULL;
1724 /* Ensure all the usershares are loaded. */
1725 become_root();
1726 load_registry_shares();
1727 sharecount = load_usershare_shares(NULL, connections_snum_used);
1728 unbecome_root();
1730 for(i=0;i < sharecount;i++) {
1731 if(lp_msdfs_root(i)) {
1732 jn_count += count_dfs_links(ctx, i);
1735 if (jn_count == 0) {
1736 return NULL;
1738 jn = talloc_array(ctx, struct junction_map, jn_count);
1739 if (!jn) {
1740 return NULL;
1742 for(i=0; i < sharecount; i++) {
1743 if (*p_num_jn >= jn_count) {
1744 break;
1746 if(lp_msdfs_root(i)) {
1747 *p_num_jn += form_junctions(ctx, i,
1748 &jn[*p_num_jn],
1749 jn_count - *p_num_jn);
1752 return jn;
1755 /******************************************************************************
1756 Core function to resolve a dfs pathname possibly containing a wildcard. If
1757 ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1758 detected during dfs resolution.
1759 ******************************************************************************/
1761 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1762 connection_struct *conn,
1763 const char *name_in,
1764 uint32_t ucf_flags,
1765 bool allow_broken_path,
1766 char **pp_name_out,
1767 bool *ppath_contains_wcard)
1769 bool path_contains_wcard = false;
1770 NTSTATUS status = NT_STATUS_OK;
1772 status = dfs_redirect(ctx,
1773 conn,
1774 name_in,
1775 ucf_flags,
1776 allow_broken_path,
1777 pp_name_out,
1778 &path_contains_wcard);
1780 if (NT_STATUS_IS_OK(status) &&
1781 ppath_contains_wcard != NULL &&
1782 path_contains_wcard) {
1783 *ppath_contains_wcard = path_contains_wcard;
1785 return status;