Add tiny tldap test
[Samba/gebeck_regimport.git] / source3 / smbd / msdfs.c
blobe2f31f077c4eef5ea0b374a9e24e1e6df6f0086b
1 /*
2 Unix SMB/Netbios implementation.
3 Version 3.0
4 MSDFS services for Samba
5 Copyright (C) Shirish Kalele 2000
6 Copyright (C) Jeremy Allison 2007
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #define DBGC_CLASS DBGC_MSDFS
24 #include "includes.h"
25 #include "smbd/globals.h"
27 /**********************************************************************
28 Parse a DFS pathname of the form \hostname\service\reqpath
29 into the dfs_path structure.
30 If POSIX pathnames is true, the pathname may also be of the
31 form /hostname/service/reqpath.
32 We cope with either here.
34 Unfortunately, due to broken clients who might set the
35 SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
36 send a local path, we have to cope with that too....
38 If conn != NULL then ensure the provided service is
39 the one pointed to by the connection.
41 This version does everything using pointers within one copy of the
42 pathname string, talloced on the struct dfs_path pointer (which
43 must be talloced). This may be too clever to live....
44 JRA.
45 **********************************************************************/
47 static NTSTATUS parse_dfs_path(connection_struct *conn,
48 const char *pathname,
49 bool allow_wcards,
50 struct dfs_path *pdp, /* MUST BE TALLOCED */
51 bool *ppath_contains_wcard)
53 char *pathname_local;
54 char *p,*temp;
55 char *servicename;
56 char *eos_ptr;
57 NTSTATUS status = NT_STATUS_OK;
58 char sepchar;
60 ZERO_STRUCTP(pdp);
63 * This is the only talloc we should need to do
64 * on the struct dfs_path. All the pointers inside
65 * it should point to offsets within this string.
68 pathname_local = talloc_strdup(pdp, pathname);
69 if (!pathname_local) {
70 return NT_STATUS_NO_MEMORY;
72 /* Get a pointer to the terminating '\0' */
73 eos_ptr = &pathname_local[strlen(pathname_local)];
74 p = temp = pathname_local;
76 pdp->posix_path = (lp_posix_pathnames() && *pathname == '/');
78 sepchar = pdp->posix_path ? '/' : '\\';
80 if (*pathname != sepchar) {
81 DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
82 pathname, sepchar ));
84 * Possibly client sent a local path by mistake.
85 * Try and convert to a local path.
88 pdp->hostname = eos_ptr; /* "" */
89 pdp->servicename = eos_ptr; /* "" */
91 /* We've got no info about separators. */
92 pdp->posix_path = lp_posix_pathnames();
93 p = temp;
94 DEBUG(10,("parse_dfs_path: trying to convert %s to a "
95 "local path\n",
96 temp));
97 goto local_path;
101 * Safe to use on talloc'ed string as it only shrinks.
102 * It also doesn't affect the eos_ptr.
104 trim_char(temp,sepchar,sepchar);
106 DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
107 temp, sepchar));
109 /* Now tokenize. */
110 /* Parse out hostname. */
111 p = strchr_m(temp,sepchar);
112 if(p == NULL) {
113 DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
114 temp));
116 * Possibly client sent a local path by mistake.
117 * Try and convert to a local path.
120 pdp->hostname = eos_ptr; /* "" */
121 pdp->servicename = eos_ptr; /* "" */
123 p = temp;
124 DEBUG(10,("parse_dfs_path: trying to convert %s "
125 "to a local path\n",
126 temp));
127 goto local_path;
129 *p = '\0';
130 pdp->hostname = temp;
132 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
134 /* Parse out servicename. */
135 servicename = p+1;
136 p = strchr_m(servicename,sepchar);
137 if (p) {
138 *p = '\0';
141 /* Is this really our servicename ? */
142 if (conn && !( strequal(servicename, lp_servicename(SNUM(conn)))
143 || (strequal(servicename, HOMES_NAME)
144 && strequal(lp_servicename(SNUM(conn)),
145 get_current_username()) )) ) {
146 DEBUG(10,("parse_dfs_path: %s is not our servicename\n",
147 servicename));
150 * Possibly client sent a local path by mistake.
151 * Try and convert to a local path.
154 pdp->hostname = eos_ptr; /* "" */
155 pdp->servicename = eos_ptr; /* "" */
157 /* Repair the path - replace the sepchar's
158 we nulled out */
159 servicename--;
160 *servicename = sepchar;
161 if (p) {
162 *p = sepchar;
165 p = temp;
166 DEBUG(10,("parse_dfs_path: trying to convert %s "
167 "to a local path\n",
168 temp));
169 goto local_path;
172 pdp->servicename = servicename;
174 DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
176 if(p == NULL) {
177 /* Client sent self referral \server\share. */
178 pdp->reqpath = eos_ptr; /* "" */
179 return NT_STATUS_OK;
182 p++;
184 local_path:
186 *ppath_contains_wcard = False;
188 pdp->reqpath = p;
190 /* Rest is reqpath. */
191 if (pdp->posix_path) {
192 status = check_path_syntax_posix(pdp->reqpath);
193 } else {
194 if (allow_wcards) {
195 status = check_path_syntax_wcard(pdp->reqpath,
196 ppath_contains_wcard);
197 } else {
198 status = check_path_syntax(pdp->reqpath);
202 if (!NT_STATUS_IS_OK(status)) {
203 DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
204 p, nt_errstr(status) ));
205 return status;
208 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
209 return NT_STATUS_OK;
212 /********************************************************
213 Fake up a connection struct for the VFS layer.
214 Note this CHANGES CWD !!!! JRA.
215 *********************************************************/
217 NTSTATUS create_conn_struct(TALLOC_CTX *ctx,
218 connection_struct **pconn,
219 int snum,
220 const char *path,
221 struct auth_serversupplied_info *server_info,
222 char **poldcwd)
224 connection_struct *conn;
225 char *connpath;
226 char *oldcwd;
228 conn = TALLOC_ZERO_P(ctx, connection_struct);
229 if (conn == NULL) {
230 return NT_STATUS_NO_MEMORY;
233 connpath = talloc_strdup(conn, path);
234 if (!connpath) {
235 TALLOC_FREE(conn);
236 return NT_STATUS_NO_MEMORY;
238 connpath = talloc_string_sub(conn,
239 connpath,
240 "%S",
241 lp_servicename(snum));
242 if (!connpath) {
243 TALLOC_FREE(conn);
244 return NT_STATUS_NO_MEMORY;
247 /* needed for smbd_vfs_init() */
249 if (!(conn->params = TALLOC_ZERO_P(conn, struct share_params))) {
250 DEBUG(0, ("TALLOC failed\n"));
251 TALLOC_FREE(conn);
252 return NT_STATUS_NO_MEMORY;
255 conn->params->service = snum;
257 if (server_info != NULL) {
258 conn->server_info = copy_serverinfo(conn, server_info);
259 if (conn->server_info == NULL) {
260 DEBUG(0, ("copy_serverinfo failed\n"));
261 TALLOC_FREE(conn);
262 return NT_STATUS_NO_MEMORY;
266 set_conn_connectpath(conn, connpath);
268 if (!smbd_vfs_init(conn)) {
269 NTSTATUS status = map_nt_error_from_unix(errno);
270 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
271 conn_free_internal(conn);
272 return status;
275 conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn);
278 * Windows seems to insist on doing trans2getdfsreferral() calls on
279 * the IPC$ share as the anonymous user. If we try to chdir as that
280 * user we will fail.... WTF ? JRA.
283 oldcwd = vfs_GetWd(ctx, conn);
284 if (oldcwd == NULL) {
285 NTSTATUS status = map_nt_error_from_unix(errno);
286 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
287 conn_free_internal(conn);
288 return status;
291 if (vfs_ChDir(conn,conn->connectpath) != 0) {
292 NTSTATUS status = map_nt_error_from_unix(errno);
293 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
294 "Error was %s\n",
295 conn->connectpath, strerror(errno) ));
296 conn_free_internal(conn);
297 return status;
300 *pconn = conn;
301 *poldcwd = oldcwd;
303 return NT_STATUS_OK;
306 /**********************************************************************
307 Parse the contents of a symlink to verify if it is an msdfs referral
308 A valid referral is of the form:
310 msdfs:server1\share1,server2\share2
311 msdfs:server1\share1\pathname,server2\share2\pathname
312 msdfs:server1/share1,server2/share2
313 msdfs:server1/share1/pathname,server2/share2/pathname.
315 Note that the alternate paths returned here must be of the canonicalized
316 form:
318 \server\share or
319 \server\share\path\to\file,
321 even in posix path mode. This is because we have no knowledge if the
322 server we're referring to understands posix paths.
323 **********************************************************************/
325 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
326 const char *target,
327 struct referral **preflist,
328 int *refcount)
330 char *temp = NULL;
331 char *prot;
332 char **alt_path = NULL;
333 int count = 0, i;
334 struct referral *reflist;
335 char *saveptr;
337 temp = talloc_strdup(ctx, target);
338 if (!temp) {
339 return False;
341 prot = strtok_r(temp, ":", &saveptr);
342 if (!prot) {
343 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
344 return False;
347 alt_path = TALLOC_ARRAY(ctx, char *, MAX_REFERRAL_COUNT);
348 if (!alt_path) {
349 return False;
352 /* parse out the alternate paths */
353 while((count<MAX_REFERRAL_COUNT) &&
354 ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
355 count++;
358 DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
360 if (count) {
361 reflist = *preflist = TALLOC_ZERO_ARRAY(ctx,
362 struct referral, count);
363 if(reflist == NULL) {
364 TALLOC_FREE(alt_path);
365 return False;
367 } else {
368 reflist = *preflist = NULL;
371 for(i=0;i<count;i++) {
372 char *p;
374 /* Canonicalize link target.
375 * Replace all /'s in the path by a \ */
376 string_replace(alt_path[i], '/', '\\');
378 /* Remove leading '\\'s */
379 p = alt_path[i];
380 while (*p && (*p == '\\')) {
381 p++;
384 reflist[i].alternate_path = talloc_asprintf(ctx,
385 "\\%s",
387 if (!reflist[i].alternate_path) {
388 return False;
391 reflist[i].proximity = 0;
392 reflist[i].ttl = REFERRAL_TTL;
393 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
394 reflist[i].alternate_path));
397 *refcount = count;
399 TALLOC_FREE(alt_path);
400 return True;
403 /**********************************************************************
404 Returns true if the unix path is a valid msdfs symlink and also
405 returns the target string from inside the link.
406 **********************************************************************/
408 static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
409 connection_struct *conn,
410 const char *path,
411 char **pp_link_target,
412 SMB_STRUCT_STAT *sbufp)
414 SMB_STRUCT_STAT st;
415 int referral_len = 0;
416 #if defined(HAVE_BROKEN_READLINK)
417 char link_target_buf[PATH_MAX];
418 #else
419 char link_target_buf[7];
420 #endif
421 size_t bufsize = 0;
422 char *link_target = NULL;
424 if (pp_link_target) {
425 bufsize = 1024;
426 link_target = TALLOC_ARRAY(ctx, char, bufsize);
427 if (!link_target) {
428 return False;
430 *pp_link_target = link_target;
431 } else {
432 bufsize = sizeof(link_target_buf);
433 link_target = link_target_buf;
436 if (sbufp == NULL) {
437 sbufp = &st;
440 if (SMB_VFS_LSTAT(conn, path, sbufp) != 0) {
441 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
442 path));
443 goto err;
446 if (!S_ISLNK(sbufp->st_ex_mode)) {
447 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
448 path));
449 goto err;
452 referral_len = SMB_VFS_READLINK(conn, path, link_target, bufsize - 1);
453 if (referral_len == -1) {
454 DEBUG(0,("is_msdfs_link_read_target: Error reading "
455 "msdfs link %s: %s\n",
456 path, strerror(errno)));
457 goto err;
459 link_target[referral_len] = '\0';
461 DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path,
462 link_target));
464 if (!strnequal(link_target, "msdfs:", 6)) {
465 goto err;
467 return True;
469 err:
471 if (link_target != link_target_buf) {
472 TALLOC_FREE(link_target);
474 return False;
477 /**********************************************************************
478 Returns true if the unix path is a valid msdfs symlink.
479 **********************************************************************/
481 bool is_msdfs_link(connection_struct *conn,
482 const char *path,
483 SMB_STRUCT_STAT *sbufp)
485 return is_msdfs_link_internal(talloc_tos(),
486 conn,
487 path,
488 NULL,
489 sbufp);
492 /*****************************************************************
493 Used by other functions to decide if a dfs path is remote,
494 and to get the list of referred locations for that remote path.
496 search_flag: For findfirsts, dfs links themselves are not
497 redirected, but paths beyond the links are. For normal smb calls,
498 even dfs links need to be redirected.
500 consumedcntp: how much of the dfs path is being redirected. the client
501 should try the remaining path on the redirected server.
503 If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
504 link redirect are in targetpath.
505 *****************************************************************/
507 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
508 connection_struct *conn,
509 const char *dfspath, /* Incoming complete dfs path */
510 const struct dfs_path *pdp, /* Parsed out
511 server+share+extrapath. */
512 bool search_flag, /* Called from a findfirst ? */
513 int *consumedcntp,
514 char **pp_targetpath)
516 char *p = NULL;
517 char *q = NULL;
518 NTSTATUS status;
519 struct smb_filename *smb_fname = NULL;
520 char *localpath = NULL;
521 char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
522 components). */
524 DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
525 conn->connectpath, pdp->reqpath));
528 * Note the unix path conversion here we're doing we can
529 * throw away. We're looking for a symlink for a dfs
530 * resolution, if we don't find it we'll do another
531 * unix_convert later in the codepath.
532 * If we needed to remember what we'd resolved in
533 * dp->reqpath (as the original code did) we'd
534 * copy (localhost, dp->reqpath) on any code
535 * path below that returns True - but I don't
536 * think this is needed. JRA.
539 status = unix_convert(ctx, conn, pdp->reqpath, &smb_fname,
540 search_flag ? UCF_ALLOW_WCARD_LCOMP : 0);
542 if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status,
543 NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
544 return status;
547 status = get_full_smb_filename(ctx, smb_fname, &localpath);
548 if (!NT_STATUS_IS_OK(status)) {
549 TALLOC_FREE(smb_fname);
550 return status;
553 TALLOC_FREE(smb_fname);
555 /* Optimization - check if we can redirect the whole path. */
557 if (is_msdfs_link_internal(ctx, conn, localpath, pp_targetpath, NULL)) {
558 if (search_flag) {
559 DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
560 "for dfs link %s.\n", dfspath));
561 return NT_STATUS_OK;
564 DEBUG(6,("dfs_path_lookup: %s resolves to a "
565 "valid dfs link %s.\n", dfspath,
566 pp_targetpath ? *pp_targetpath : ""));
568 if (consumedcntp) {
569 *consumedcntp = strlen(dfspath);
571 return NT_STATUS_PATH_NOT_COVERED;
574 /* Prepare to test only for '/' components in the given path,
575 * so if a Windows path replace all '\\' characters with '/'.
576 * For a POSIX DFS path we know all separators are already '/'. */
578 canon_dfspath = talloc_strdup(ctx, dfspath);
579 if (!canon_dfspath) {
580 return NT_STATUS_NO_MEMORY;
582 if (!pdp->posix_path) {
583 string_replace(canon_dfspath, '\\', '/');
587 * localpath comes out of unix_convert, so it has
588 * no trailing backslash. Make sure that canon_dfspath hasn't either.
589 * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
592 trim_char(canon_dfspath,0,'/');
595 * Redirect if any component in the path is a link.
596 * We do this by walking backwards through the
597 * local path, chopping off the last component
598 * in both the local path and the canonicalized
599 * DFS path. If we hit a DFS link then we're done.
602 p = strrchr_m(localpath, '/');
603 if (consumedcntp) {
604 q = strrchr_m(canon_dfspath, '/');
607 while (p) {
608 *p = '\0';
609 if (q) {
610 *q = '\0';
613 if (is_msdfs_link_internal(ctx, conn,
614 localpath, pp_targetpath, NULL)) {
615 DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
616 "parent %s is dfs link\n", dfspath, localpath));
618 if (consumedcntp) {
619 *consumedcntp = strlen(canon_dfspath);
620 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
621 "(%d)\n",
622 canon_dfspath,
623 *consumedcntp));
626 return NT_STATUS_PATH_NOT_COVERED;
629 /* Step back on the filesystem. */
630 p = strrchr_m(localpath, '/');
632 if (consumedcntp) {
633 /* And in the canonicalized dfs path. */
634 q = strrchr_m(canon_dfspath, '/');
638 return NT_STATUS_OK;
641 /*****************************************************************
642 Decides if a dfs pathname should be redirected or not.
643 If not, the pathname is converted to a tcon-relative local unix path
645 search_wcard_flag: this flag performs 2 functions both related
646 to searches. See resolve_dfs_path() and parse_dfs_path_XX()
647 for details.
649 This function can return NT_STATUS_OK, meaning use the returned path as-is
650 (mapped into a local path).
651 or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
652 any other NT_STATUS error which is a genuine error to be
653 returned to the client.
654 *****************************************************************/
656 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
657 connection_struct *conn,
658 const char *path_in,
659 bool search_wcard_flag,
660 char **pp_path_out,
661 bool *ppath_contains_wcard)
663 NTSTATUS status;
664 struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
666 if (!pdp) {
667 return NT_STATUS_NO_MEMORY;
670 status = parse_dfs_path(conn, path_in, search_wcard_flag, pdp,
671 ppath_contains_wcard);
672 if (!NT_STATUS_IS_OK(status)) {
673 TALLOC_FREE(pdp);
674 return status;
677 if (pdp->reqpath[0] == '\0') {
678 TALLOC_FREE(pdp);
679 *pp_path_out = talloc_strdup(ctx, "");
680 if (!*pp_path_out) {
681 return NT_STATUS_NO_MEMORY;
683 DEBUG(5,("dfs_redirect: self-referral.\n"));
684 return NT_STATUS_OK;
687 /* If dfs pathname for a non-dfs share, convert to tcon-relative
688 path and return OK */
690 if (!lp_msdfs_root(SNUM(conn))) {
691 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
692 TALLOC_FREE(pdp);
693 if (!*pp_path_out) {
694 return NT_STATUS_NO_MEMORY;
696 return NT_STATUS_OK;
699 /* If it looked like a local path (zero hostname/servicename)
700 * just treat as a tcon-relative path. */
702 if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
703 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
704 TALLOC_FREE(pdp);
705 if (!*pp_path_out) {
706 return NT_STATUS_NO_MEMORY;
708 return NT_STATUS_OK;
711 if (!( strequal(pdp->servicename, lp_servicename(SNUM(conn)))
712 || (strequal(pdp->servicename, HOMES_NAME)
713 && strequal(lp_servicename(SNUM(conn)),
714 conn->server_info->sanitized_username) )) ) {
716 /* The given sharename doesn't match this connection. */
717 TALLOC_FREE(pdp);
719 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
722 status = dfs_path_lookup(ctx, conn, path_in, pdp,
723 search_wcard_flag, NULL, NULL);
724 if (!NT_STATUS_IS_OK(status)) {
725 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
726 DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
727 } else {
728 DEBUG(10,("dfs_redirect: dfs_path_lookup "
729 "failed for %s with %s\n",
730 path_in, nt_errstr(status) ));
732 return status;
735 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
737 /* Form non-dfs tcon-relative path */
738 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
739 TALLOC_FREE(pdp);
740 if (!*pp_path_out) {
741 return NT_STATUS_NO_MEMORY;
744 DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
745 path_in,
746 *pp_path_out));
748 return NT_STATUS_OK;
751 /**********************************************************************
752 Return a self referral.
753 **********************************************************************/
755 static NTSTATUS self_ref(TALLOC_CTX *ctx,
756 const char *dfs_path,
757 struct junction_map *jucn,
758 int *consumedcntp,
759 bool *self_referralp)
761 struct referral *ref;
763 *self_referralp = True;
765 jucn->referral_count = 1;
766 if((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
767 return NT_STATUS_NO_MEMORY;
770 ref->alternate_path = talloc_strdup(ctx, dfs_path);
771 if (!ref->alternate_path) {
772 return NT_STATUS_NO_MEMORY;
774 ref->proximity = 0;
775 ref->ttl = REFERRAL_TTL;
776 jucn->referral_list = ref;
777 *consumedcntp = strlen(dfs_path);
778 return NT_STATUS_OK;
781 /**********************************************************************
782 Gets valid referrals for a dfs path and fills up the
783 junction_map structure.
784 **********************************************************************/
786 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
787 const char *dfs_path,
788 struct junction_map *jucn,
789 int *consumedcntp,
790 bool *self_referralp)
792 struct connection_struct *conn;
793 char *targetpath = NULL;
794 int snum;
795 NTSTATUS status = NT_STATUS_NOT_FOUND;
796 bool dummy;
797 struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
798 char *oldpath;
800 if (!pdp) {
801 return NT_STATUS_NO_MEMORY;
804 *self_referralp = False;
806 status = parse_dfs_path(NULL, dfs_path, False, pdp, &dummy);
807 if (!NT_STATUS_IS_OK(status)) {
808 return status;
811 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
812 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
813 if (!jucn->service_name || !jucn->volume_name) {
814 TALLOC_FREE(pdp);
815 return NT_STATUS_NO_MEMORY;
818 /* Verify the share is a dfs root */
819 snum = lp_servicenumber(jucn->service_name);
820 if(snum < 0) {
821 fstring service_name;
822 fstrcpy(service_name, jucn->service_name);
823 if ((snum = find_service(service_name)) < 0) {
824 return NT_STATUS_NOT_FOUND;
826 TALLOC_FREE(jucn->service_name);
827 jucn->service_name = talloc_strdup(ctx, service_name);
828 if (!jucn->service_name) {
829 TALLOC_FREE(pdp);
830 return NT_STATUS_NO_MEMORY;
834 if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(snum) == '\0')) {
835 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
836 "a dfs root.\n",
837 pdp->servicename, dfs_path));
838 TALLOC_FREE(pdp);
839 return NT_STATUS_NOT_FOUND;
843 * Self referrals are tested with a anonymous IPC connection and
844 * a GET_DFS_REFERRAL call to \\server\share. (which means
845 * dp.reqpath[0] points to an empty string). create_conn_struct cd's
846 * into the directory and will fail if it cannot (as the anonymous
847 * user). Cope with this.
850 if (pdp->reqpath[0] == '\0') {
851 char *tmp;
852 struct referral *ref;
854 if (*lp_msdfs_proxy(snum) == '\0') {
855 TALLOC_FREE(pdp);
856 return self_ref(ctx,
857 dfs_path,
858 jucn,
859 consumedcntp,
860 self_referralp);
864 * It's an msdfs proxy share. Redirect to
865 * the configured target share.
868 jucn->referral_count = 1;
869 if ((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
870 TALLOC_FREE(pdp);
871 return NT_STATUS_NO_MEMORY;
874 if (!(tmp = talloc_strdup(ctx, lp_msdfs_proxy(snum)))) {
875 TALLOC_FREE(pdp);
876 return NT_STATUS_NO_MEMORY;
879 trim_string(tmp, "\\", 0);
881 ref->alternate_path = talloc_asprintf(ctx, "\\%s", tmp);
882 TALLOC_FREE(tmp);
884 if (!ref->alternate_path) {
885 TALLOC_FREE(pdp);
886 return NT_STATUS_NO_MEMORY;
889 if (pdp->reqpath[0] != '\0') {
890 ref->alternate_path = talloc_asprintf_append(
891 ref->alternate_path,
892 "%s",
893 pdp->reqpath);
894 if (!ref->alternate_path) {
895 TALLOC_FREE(pdp);
896 return NT_STATUS_NO_MEMORY;
899 ref->proximity = 0;
900 ref->ttl = REFERRAL_TTL;
901 jucn->referral_list = ref;
902 *consumedcntp = strlen(dfs_path);
903 TALLOC_FREE(pdp);
904 return NT_STATUS_OK;
907 status = create_conn_struct(ctx, &conn, snum, lp_pathname(snum),
908 NULL, &oldpath);
909 if (!NT_STATUS_IS_OK(status)) {
910 TALLOC_FREE(pdp);
911 return status;
914 /* If this is a DFS path dfs_lookup should return
915 * NT_STATUS_PATH_NOT_COVERED. */
917 status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
918 False, consumedcntp, &targetpath);
920 if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
921 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
922 dfs_path));
923 vfs_ChDir(conn, oldpath);
924 conn_free_internal(conn);
925 TALLOC_FREE(pdp);
926 return status;
929 /* We know this is a valid dfs link. Parse the targetpath. */
930 if (!parse_msdfs_symlink(ctx, targetpath,
931 &jucn->referral_list,
932 &jucn->referral_count)) {
933 DEBUG(3,("get_referred_path: failed to parse symlink "
934 "target %s\n", targetpath ));
935 vfs_ChDir(conn, oldpath);
936 conn_free_internal(conn);
937 TALLOC_FREE(pdp);
938 return NT_STATUS_NOT_FOUND;
941 vfs_ChDir(conn, oldpath);
942 conn_free_internal(conn);
943 TALLOC_FREE(pdp);
944 return NT_STATUS_OK;
947 static int setup_ver2_dfs_referral(const char *pathname,
948 char **ppdata,
949 struct junction_map *junction,
950 bool self_referral)
952 char* pdata = *ppdata;
954 smb_ucs2_t *uni_requestedpath = NULL;
955 int uni_reqpathoffset1,uni_reqpathoffset2;
956 int uni_curroffset;
957 int requestedpathlen=0;
958 int offset;
959 int reply_size = 0;
960 int i=0;
962 DEBUG(10,("Setting up version2 referral\nRequested path:\n"));
964 requestedpathlen = rpcstr_push_talloc(talloc_tos(),
965 &uni_requestedpath, pathname);
966 if (uni_requestedpath == NULL || requestedpathlen == 0) {
967 return -1;
970 if (DEBUGLVL(10)) {
971 dump_data(0, (unsigned char *)uni_requestedpath,
972 requestedpathlen);
975 DEBUG(10,("ref count = %u\n",junction->referral_count));
977 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
978 VERSION2_REFERRAL_SIZE * junction->referral_count;
980 uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen;
982 uni_curroffset = uni_reqpathoffset2 + requestedpathlen;
984 reply_size = REFERRAL_HEADER_SIZE +
985 VERSION2_REFERRAL_SIZE*junction->referral_count +
986 2 * requestedpathlen;
987 DEBUG(10,("reply_size: %u\n",reply_size));
989 /* add up the unicode lengths of all the referral paths */
990 for(i=0;i<junction->referral_count;i++) {
991 DEBUG(10,("referral %u : %s\n",
993 junction->referral_list[i].alternate_path));
994 reply_size +=
995 (strlen(junction->referral_list[i].alternate_path)+1)*2;
998 DEBUG(10,("reply_size = %u\n",reply_size));
999 /* add the unexplained 0x16 bytes */
1000 reply_size += 0x16;
1002 pdata = (char *)SMB_REALLOC(pdata,reply_size);
1003 if(pdata == NULL) {
1004 DEBUG(0,("Realloc failed!\n"));
1005 return -1;
1007 *ppdata = pdata;
1009 /* copy in the dfs requested paths.. required for offset calculations */
1010 memcpy(pdata+uni_reqpathoffset1,uni_requestedpath,requestedpathlen);
1011 memcpy(pdata+uni_reqpathoffset2,uni_requestedpath,requestedpathlen);
1013 /* create the header */
1014 SSVAL(pdata,0,requestedpathlen - 2); /* UCS2 of path consumed minus
1015 2 byte null */
1016 /* number of referral in this pkt */
1017 SSVAL(pdata,2,junction->referral_count);
1018 if(self_referral) {
1019 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
1020 } else {
1021 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
1024 offset = 8;
1025 /* add the referral elements */
1026 for(i=0;i<junction->referral_count;i++) {
1027 struct referral* ref = &junction->referral_list[i];
1028 int unilen;
1030 SSVAL(pdata,offset,2); /* version 2 */
1031 SSVAL(pdata,offset+2,VERSION2_REFERRAL_SIZE);
1032 if(self_referral) {
1033 SSVAL(pdata,offset+4,1);
1034 } else {
1035 SSVAL(pdata,offset+4,0);
1038 /* ref_flags :use path_consumed bytes? */
1039 SSVAL(pdata,offset+6,0);
1040 SIVAL(pdata,offset+8,ref->proximity);
1041 SIVAL(pdata,offset+12,ref->ttl);
1043 SSVAL(pdata,offset+16,uni_reqpathoffset1-offset);
1044 SSVAL(pdata,offset+18,uni_reqpathoffset2-offset);
1045 /* copy referred path into current offset */
1046 unilen = rpcstr_push(pdata+uni_curroffset,
1047 ref->alternate_path,
1048 reply_size - uni_curroffset,
1049 STR_UNICODE);
1051 SSVAL(pdata,offset+20,uni_curroffset-offset);
1053 uni_curroffset += unilen;
1054 offset += VERSION2_REFERRAL_SIZE;
1056 /* add in the unexplained 22 (0x16) bytes at the end */
1057 memset(pdata+uni_curroffset,'\0',0x16);
1058 return reply_size;
1061 static int setup_ver3_dfs_referral(const char *pathname,
1062 char **ppdata,
1063 struct junction_map *junction,
1064 bool self_referral)
1066 char *pdata = *ppdata;
1068 smb_ucs2_t *uni_reqpath = NULL;
1069 int uni_reqpathoffset1, uni_reqpathoffset2;
1070 int uni_curroffset;
1071 int reply_size = 0;
1073 int reqpathlen = 0;
1074 int offset,i=0;
1076 DEBUG(10,("setting up version3 referral\n"));
1078 reqpathlen = rpcstr_push_talloc(talloc_tos(), &uni_reqpath, pathname);
1079 if (uni_reqpath == NULL || reqpathlen == 0) {
1080 return -1;
1083 if (DEBUGLVL(10)) {
1084 dump_data(0, (unsigned char *)uni_reqpath,
1085 reqpathlen);
1088 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
1089 VERSION3_REFERRAL_SIZE * junction->referral_count;
1090 uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen;
1091 reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen;
1093 for(i=0;i<junction->referral_count;i++) {
1094 DEBUG(10,("referral %u : %s\n",
1096 junction->referral_list[i].alternate_path));
1097 reply_size +=
1098 (strlen(junction->referral_list[i].alternate_path)+1)*2;
1101 pdata = (char *)SMB_REALLOC(pdata,reply_size);
1102 if(pdata == NULL) {
1103 DEBUG(0,("version3 referral setup:"
1104 "malloc failed for Realloc!\n"));
1105 return -1;
1107 *ppdata = pdata;
1109 /* create the header */
1110 SSVAL(pdata,0,reqpathlen - 2); /* UCS2 of path consumed minus
1111 2 byte null */
1112 SSVAL(pdata,2,junction->referral_count); /* number of referral */
1113 if(self_referral) {
1114 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
1115 } else {
1116 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
1119 /* copy in the reqpaths */
1120 memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen);
1121 memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen);
1123 offset = 8;
1124 for(i=0;i<junction->referral_count;i++) {
1125 struct referral* ref = &(junction->referral_list[i]);
1126 int unilen;
1128 SSVAL(pdata,offset,3); /* version 3 */
1129 SSVAL(pdata,offset+2,VERSION3_REFERRAL_SIZE);
1130 if(self_referral) {
1131 SSVAL(pdata,offset+4,1);
1132 } else {
1133 SSVAL(pdata,offset+4,0);
1136 /* ref_flags :use path_consumed bytes? */
1137 SSVAL(pdata,offset+6,0);
1138 SIVAL(pdata,offset+8,ref->ttl);
1140 SSVAL(pdata,offset+12,uni_reqpathoffset1-offset);
1141 SSVAL(pdata,offset+14,uni_reqpathoffset2-offset);
1142 /* copy referred path into current offset */
1143 unilen = rpcstr_push(pdata+uni_curroffset,ref->alternate_path,
1144 reply_size - uni_curroffset,
1145 STR_UNICODE | STR_TERMINATE);
1146 SSVAL(pdata,offset+16,uni_curroffset-offset);
1147 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
1148 memset(pdata+offset+18,'\0',16);
1150 uni_curroffset += unilen;
1151 offset += VERSION3_REFERRAL_SIZE;
1153 return reply_size;
1156 /******************************************************************
1157 Set up the DFS referral for the dfs pathname. This call returns
1158 the amount of the path covered by this server, and where the
1159 client should be redirected to. This is the meat of the
1160 TRANS2_GET_DFS_REFERRAL call.
1161 ******************************************************************/
1163 int setup_dfs_referral(connection_struct *orig_conn,
1164 const char *dfs_path,
1165 int max_referral_level,
1166 char **ppdata, NTSTATUS *pstatus)
1168 struct junction_map *junction = NULL;
1169 int consumedcnt = 0;
1170 bool self_referral = False;
1171 int reply_size = 0;
1172 char *pathnamep = NULL;
1173 char *local_dfs_path = NULL;
1174 TALLOC_CTX *ctx;
1176 if (!(ctx=talloc_init("setup_dfs_referral"))) {
1177 *pstatus = NT_STATUS_NO_MEMORY;
1178 return -1;
1181 /* get the junction entry */
1182 if (!dfs_path) {
1183 talloc_destroy(ctx);
1184 *pstatus = NT_STATUS_NOT_FOUND;
1185 return -1;
1189 * Trim pathname sent by client so it begins with only one backslash.
1190 * Two backslashes confuse some dfs clients
1193 local_dfs_path = talloc_strdup(ctx,dfs_path);
1194 if (!local_dfs_path) {
1195 *pstatus = NT_STATUS_NO_MEMORY;
1196 talloc_destroy(ctx);
1197 return -1;
1199 pathnamep = local_dfs_path;
1200 while (IS_DIRECTORY_SEP(pathnamep[0]) &&
1201 IS_DIRECTORY_SEP(pathnamep[1])) {
1202 pathnamep++;
1205 junction = TALLOC_ZERO_P(ctx, struct junction_map);
1206 if (!junction) {
1207 *pstatus = NT_STATUS_NO_MEMORY;
1208 talloc_destroy(ctx);
1209 return -1;
1212 /* The following call can change cwd. */
1213 *pstatus = get_referred_path(ctx, pathnamep, junction,
1214 &consumedcnt, &self_referral);
1215 if (!NT_STATUS_IS_OK(*pstatus)) {
1216 vfs_ChDir(orig_conn,orig_conn->connectpath);
1217 talloc_destroy(ctx);
1218 return -1;
1220 vfs_ChDir(orig_conn,orig_conn->connectpath);
1222 if (!self_referral) {
1223 pathnamep[consumedcnt] = '\0';
1225 if( DEBUGLVL( 3 ) ) {
1226 int i=0;
1227 dbgtext("setup_dfs_referral: Path %s to "
1228 "alternate path(s):",
1229 pathnamep);
1230 for(i=0;i<junction->referral_count;i++)
1231 dbgtext(" %s",
1232 junction->referral_list[i].alternate_path);
1233 dbgtext(".\n");
1237 /* create the referral depeding on version */
1238 DEBUG(10,("max_referral_level :%d\n",max_referral_level));
1240 if (max_referral_level < 2) {
1241 max_referral_level = 2;
1243 if (max_referral_level > 3) {
1244 max_referral_level = 3;
1247 switch(max_referral_level) {
1248 case 2:
1249 reply_size = setup_ver2_dfs_referral(pathnamep,
1250 ppdata, junction,
1251 self_referral);
1252 break;
1253 case 3:
1254 reply_size = setup_ver3_dfs_referral(pathnamep, ppdata,
1255 junction, self_referral);
1256 break;
1257 default:
1258 DEBUG(0,("setup_dfs_referral: Invalid dfs referral "
1259 "version: %d\n",
1260 max_referral_level));
1261 talloc_destroy(ctx);
1262 *pstatus = NT_STATUS_INVALID_LEVEL;
1263 return -1;
1266 if (DEBUGLVL(10)) {
1267 DEBUGADD(0,("DFS Referral pdata:\n"));
1268 dump_data(0,(uint8 *)*ppdata,reply_size);
1271 talloc_destroy(ctx);
1272 *pstatus = NT_STATUS_OK;
1273 return reply_size;
1276 /**********************************************************************
1277 The following functions are called by the NETDFS RPC pipe functions
1278 **********************************************************************/
1280 /*********************************************************************
1281 Creates a junction structure from a DFS pathname
1282 **********************************************************************/
1284 bool create_junction(TALLOC_CTX *ctx,
1285 const char *dfs_path,
1286 struct junction_map *jucn)
1288 int snum;
1289 bool dummy;
1290 struct dfs_path *pdp = TALLOC_P(ctx,struct dfs_path);
1291 NTSTATUS status;
1293 if (!pdp) {
1294 return False;
1296 status = parse_dfs_path(NULL, dfs_path, False, pdp, &dummy);
1297 if (!NT_STATUS_IS_OK(status)) {
1298 return False;
1301 /* check if path is dfs : validate first token */
1302 if (!is_myname_or_ipaddr(pdp->hostname)) {
1303 DEBUG(4,("create_junction: Invalid hostname %s "
1304 "in dfs path %s\n",
1305 pdp->hostname, dfs_path));
1306 TALLOC_FREE(pdp);
1307 return False;
1310 /* Check for a non-DFS share */
1311 snum = lp_servicenumber(pdp->servicename);
1313 if(snum < 0 || !lp_msdfs_root(snum)) {
1314 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1315 pdp->servicename));
1316 TALLOC_FREE(pdp);
1317 return False;
1320 jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1321 jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1322 jucn->comment = talloc_strdup(ctx, lp_comment(snum));
1324 TALLOC_FREE(pdp);
1325 if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1326 return False;
1328 return True;
1331 /**********************************************************************
1332 Forms a valid Unix pathname from the junction
1333 **********************************************************************/
1335 static bool junction_to_local_path(const struct junction_map *jucn,
1336 char **pp_path_out,
1337 connection_struct **conn_out,
1338 char **oldpath)
1340 int snum;
1341 NTSTATUS status;
1343 snum = lp_servicenumber(jucn->service_name);
1344 if(snum < 0) {
1345 return False;
1347 status = create_conn_struct(talloc_tos(), conn_out, snum,
1348 lp_pathname(snum), NULL, oldpath);
1349 if (!NT_STATUS_IS_OK(status)) {
1350 return False;
1353 *pp_path_out = talloc_asprintf(*conn_out,
1354 "%s/%s",
1355 lp_pathname(snum),
1356 jucn->volume_name);
1357 if (!*pp_path_out) {
1358 vfs_ChDir(*conn_out, *oldpath);
1359 conn_free_internal(*conn_out);
1360 return False;
1362 return True;
1365 bool create_msdfs_link(const struct junction_map *jucn)
1367 char *path = NULL;
1368 char *cwd;
1369 char *msdfs_link = NULL;
1370 connection_struct *conn;
1371 int i=0;
1372 bool insert_comma = False;
1373 bool ret = False;
1375 if(!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1376 return False;
1379 /* Form the msdfs_link contents */
1380 msdfs_link = talloc_strdup(conn, "msdfs:");
1381 if (!msdfs_link) {
1382 goto out;
1384 for(i=0; i<jucn->referral_count; i++) {
1385 char *refpath = jucn->referral_list[i].alternate_path;
1387 /* Alternate paths always use Windows separators. */
1388 trim_char(refpath, '\\', '\\');
1389 if(*refpath == '\0') {
1390 if (i == 0) {
1391 insert_comma = False;
1393 continue;
1395 if (i > 0 && insert_comma) {
1396 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1397 ",%s",
1398 refpath);
1399 } else {
1400 msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1401 "%s",
1402 refpath);
1405 if (!msdfs_link) {
1406 goto out;
1408 if (!insert_comma) {
1409 insert_comma = True;
1413 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1414 path, msdfs_link));
1416 if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1417 if (errno == EEXIST) {
1418 if(SMB_VFS_UNLINK(conn,path)!=0) {
1419 goto out;
1422 if (SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1423 DEBUG(1,("create_msdfs_link: symlink failed "
1424 "%s -> %s\nError: %s\n",
1425 path, msdfs_link, strerror(errno)));
1426 goto out;
1430 ret = True;
1432 out:
1433 vfs_ChDir(conn, cwd);
1434 conn_free_internal(conn);
1435 return ret;
1438 bool remove_msdfs_link(const struct junction_map *jucn)
1440 char *path = NULL;
1441 char *cwd;
1442 connection_struct *conn;
1443 bool ret = False;
1445 if (!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1446 return false;
1449 if( SMB_VFS_UNLINK(conn, path) == 0 ) {
1450 ret = True;
1453 vfs_ChDir(conn, cwd);
1454 conn_free_internal(conn);
1455 return ret;
1458 /*********************************************************************
1459 Return the number of DFS links at the root of this share.
1460 *********************************************************************/
1462 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1464 size_t cnt = 0;
1465 SMB_STRUCT_DIR *dirp = NULL;
1466 char *dname = NULL;
1467 const char *connect_path = lp_pathname(snum);
1468 const char *msdfs_proxy = lp_msdfs_proxy(snum);
1469 connection_struct *conn;
1470 NTSTATUS status;
1471 char *cwd;
1473 if(*connect_path == '\0') {
1474 return 0;
1478 * Fake up a connection struct for the VFS layer.
1481 status = create_conn_struct(talloc_tos(), &conn, snum, connect_path,
1482 NULL, &cwd);
1483 if (!NT_STATUS_IS_OK(status)) {
1484 DEBUG(3, ("create_conn_struct failed: %s\n",
1485 nt_errstr(status)));
1486 return 0;
1489 /* Count a link for the msdfs root - convention */
1490 cnt = 1;
1492 /* No more links if this is an msdfs proxy. */
1493 if (*msdfs_proxy != '\0') {
1494 goto out;
1497 /* Now enumerate all dfs links */
1498 dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1499 if(!dirp) {
1500 goto out;
1503 while ((dname = vfs_readdirname(conn, dirp, NULL)) != NULL) {
1504 if (is_msdfs_link(conn,
1505 dname,
1506 NULL)) {
1507 cnt++;
1511 SMB_VFS_CLOSEDIR(conn,dirp);
1513 out:
1514 vfs_ChDir(conn, cwd);
1515 conn_free_internal(conn);
1516 return cnt;
1519 /*********************************************************************
1520 *********************************************************************/
1522 static int form_junctions(TALLOC_CTX *ctx,
1523 int snum,
1524 struct junction_map *jucn,
1525 size_t jn_remain)
1527 size_t cnt = 0;
1528 SMB_STRUCT_DIR *dirp = NULL;
1529 char *dname = NULL;
1530 const char *connect_path = lp_pathname(snum);
1531 char *service_name = lp_servicename(snum);
1532 const char *msdfs_proxy = lp_msdfs_proxy(snum);
1533 connection_struct *conn;
1534 struct referral *ref = NULL;
1535 char *cwd;
1536 NTSTATUS status;
1538 if (jn_remain == 0) {
1539 return 0;
1542 if(*connect_path == '\0') {
1543 return 0;
1547 * Fake up a connection struct for the VFS layer.
1550 status = create_conn_struct(ctx, &conn, snum, connect_path, NULL,
1551 &cwd);
1552 if (!NT_STATUS_IS_OK(status)) {
1553 DEBUG(3, ("create_conn_struct failed: %s\n",
1554 nt_errstr(status)));
1555 return 0;
1558 /* form a junction for the msdfs root - convention
1559 DO NOT REMOVE THIS: NT clients will not work with us
1560 if this is not present
1562 jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1563 jucn[cnt].volume_name = talloc_strdup(ctx, "");
1564 if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1565 goto out;
1567 jucn[cnt].comment = "";
1568 jucn[cnt].referral_count = 1;
1570 ref = jucn[cnt].referral_list = TALLOC_ZERO_P(ctx, struct referral);
1571 if (jucn[cnt].referral_list == NULL) {
1572 goto out;
1575 ref->proximity = 0;
1576 ref->ttl = REFERRAL_TTL;
1577 if (*msdfs_proxy != '\0') {
1578 ref->alternate_path = talloc_strdup(ctx,
1579 msdfs_proxy);
1580 } else {
1581 ref->alternate_path = talloc_asprintf(ctx,
1582 "\\\\%s\\%s",
1583 get_local_machine_name(),
1584 service_name);
1587 if (!ref->alternate_path) {
1588 goto out;
1590 cnt++;
1592 /* Don't enumerate if we're an msdfs proxy. */
1593 if (*msdfs_proxy != '\0') {
1594 goto out;
1597 /* Now enumerate all dfs links */
1598 dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1599 if(!dirp) {
1600 goto out;
1603 while ((dname = vfs_readdirname(conn, dirp, NULL)) != NULL) {
1604 char *link_target = NULL;
1605 if (cnt >= jn_remain) {
1606 DEBUG(2, ("form_junctions: ran out of MSDFS "
1607 "junction slots"));
1608 goto out;
1610 if (is_msdfs_link_internal(ctx,
1611 conn,
1612 dname, &link_target,
1613 NULL)) {
1614 if (parse_msdfs_symlink(ctx,
1615 link_target,
1616 &jucn[cnt].referral_list,
1617 &jucn[cnt].referral_count)) {
1619 jucn[cnt].service_name = talloc_strdup(ctx,
1620 service_name);
1621 jucn[cnt].volume_name = talloc_strdup(ctx,
1622 dname);
1623 if (!jucn[cnt].service_name ||
1624 !jucn[cnt].volume_name) {
1625 goto out;
1627 jucn[cnt].comment = "";
1628 cnt++;
1630 TALLOC_FREE(link_target);
1634 out:
1636 if (dirp) {
1637 SMB_VFS_CLOSEDIR(conn,dirp);
1640 vfs_ChDir(conn, cwd);
1641 conn_free_internal(conn);
1642 return cnt;
1645 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1647 struct junction_map *jn = NULL;
1648 int i=0;
1649 size_t jn_count = 0;
1650 int sharecount = 0;
1652 *p_num_jn = 0;
1653 if(!lp_host_msdfs()) {
1654 return NULL;
1657 /* Ensure all the usershares are loaded. */
1658 become_root();
1659 load_registry_shares();
1660 sharecount = load_usershare_shares();
1661 unbecome_root();
1663 for(i=0;i < sharecount;i++) {
1664 if(lp_msdfs_root(i)) {
1665 jn_count += count_dfs_links(ctx, i);
1668 if (jn_count == 0) {
1669 return NULL;
1671 jn = TALLOC_ARRAY(ctx, struct junction_map, jn_count);
1672 if (!jn) {
1673 return NULL;
1675 for(i=0; i < sharecount; i++) {
1676 if (*p_num_jn >= jn_count) {
1677 break;
1679 if(lp_msdfs_root(i)) {
1680 *p_num_jn += form_junctions(ctx, i,
1681 &jn[*p_num_jn],
1682 jn_count - *p_num_jn);
1685 return jn;
1688 /******************************************************************************
1689 Core function to resolve a dfs pathname.
1690 ******************************************************************************/
1692 NTSTATUS resolve_dfspath(TALLOC_CTX *ctx,
1693 connection_struct *conn,
1694 bool dfs_pathnames,
1695 const char *name_in,
1696 char **pp_name_out)
1698 NTSTATUS status = NT_STATUS_OK;
1699 bool dummy;
1700 if (dfs_pathnames) {
1701 status = dfs_redirect(ctx,
1702 conn,
1703 name_in,
1704 False,
1705 pp_name_out,
1706 &dummy);
1707 } else {
1709 * Cheat and just return a copy of the in ptr.
1710 * Once srvstr_get_path() uses talloc it'll
1711 * be a talloced ptr anyway.
1713 *pp_name_out = CONST_DISCARD(char *,name_in);
1715 return status;
1718 /******************************************************************************
1719 Core function to resolve a dfs pathname possibly containing a wildcard.
1720 This function is identical to the above except for the bool param to
1721 dfs_redirect but I need this to be separate so it's really clear when
1722 we're allowing wildcards and when we're not. JRA.
1723 ******************************************************************************/
1725 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1726 connection_struct *conn,
1727 bool dfs_pathnames,
1728 const char *name_in,
1729 char **pp_name_out,
1730 bool *ppath_contains_wcard)
1732 NTSTATUS status = NT_STATUS_OK;
1733 if (dfs_pathnames) {
1734 status = dfs_redirect(ctx,
1735 conn,
1736 name_in,
1737 True,
1738 pp_name_out,
1739 ppath_contains_wcard);
1740 } else {
1742 * Cheat and just return a copy of the in ptr.
1743 * Once srvstr_get_path() uses talloc it'll
1744 * be a talloced ptr anyway.
1746 *pp_name_out = CONST_DISCARD(char *,name_in);
1748 return status;