s3: Plumb smb_filename through SMB_VFS_STAT and SMB_VFS_LSTAT
[metze/samba/wip.git] / source3 / smbd / msdfs.c
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
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.
12
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.
17
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/>.
20
21 */
22
23 #define DBGC_CLASS DBGC_MSDFS
24 #include "includes.h"
25 #include "smbd/globals.h"
26
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.
33
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....
37
38  If conn != NULL then ensure the provided service is
39  the one pointed to by the connection.
40
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 **********************************************************************/
46
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)
52 {
53         char *pathname_local;
54         char *p,*temp;
55         char *servicename;
56         char *eos_ptr;
57         NTSTATUS status = NT_STATUS_OK;
58         char sepchar;
59
60         ZERO_STRUCTP(pdp);
61
62         /*
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.
66          */
67
68         pathname_local = talloc_strdup(pdp, pathname);
69         if (!pathname_local) {
70                 return NT_STATUS_NO_MEMORY;
71         }
72         /* Get a pointer to the terminating '\0' */
73         eos_ptr = &pathname_local[strlen(pathname_local)];
74         p = temp = pathname_local;
75
76         pdp->posix_path = (lp_posix_pathnames() && *pathname == '/');
77
78         sepchar = pdp->posix_path ? '/' : '\\';
79
80         if (*pathname != sepchar) {
81                 DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
82                         pathname, sepchar ));
83                 /*
84                  * Possibly client sent a local path by mistake.
85                  * Try and convert to a local path.
86                  */
87
88                 pdp->hostname = eos_ptr; /* "" */
89                 pdp->servicename = eos_ptr; /* "" */
90
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;
98         }
99
100         /*
101          * Safe to use on talloc'ed string as it only shrinks.
102          * It also doesn't affect the eos_ptr.
103          */
104         trim_char(temp,sepchar,sepchar);
105
106         DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
107                 temp, sepchar));
108
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));
115                 /*
116                  * Possibly client sent a local path by mistake.
117                  * Try and convert to a local path.
118                  */
119
120                 pdp->hostname = eos_ptr; /* "" */
121                 pdp->servicename = eos_ptr; /* "" */
122
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;
128         }
129         *p = '\0';
130         pdp->hostname = temp;
131
132         DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
133
134         /* Parse out servicename. */
135         servicename = p+1;
136         p = strchr_m(servicename,sepchar);
137         if (p) {
138                 *p = '\0';
139         }
140
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));
148
149                 /*
150                  * Possibly client sent a local path by mistake.
151                  * Try and convert to a local path.
152                  */
153
154                 pdp->hostname = eos_ptr; /* "" */
155                 pdp->servicename = eos_ptr; /* "" */
156
157                 /* Repair the path - replace the sepchar's
158                    we nulled out */
159                 servicename--;
160                 *servicename = sepchar;
161                 if (p) {
162                         *p = sepchar;
163                 }
164
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;
170         }
171
172         pdp->servicename = servicename;
173
174         DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
175
176         if(p == NULL) {
177                 /* Client sent self referral \server\share. */
178                 pdp->reqpath = eos_ptr; /* "" */
179                 return NT_STATUS_OK;
180         }
181
182         p++;
183
184   local_path:
185
186         *ppath_contains_wcard = False;
187
188         pdp->reqpath = p;
189
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);
199                 }
200         }
201
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;
206         }
207
208         DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
209         return NT_STATUS_OK;
210 }
211
212 /********************************************************
213  Fake up a connection struct for the VFS layer.
214  Note this CHANGES CWD !!!! JRA.
215 *********************************************************/
216
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)
223 {
224         connection_struct *conn;
225         char *connpath;
226         char *oldcwd;
227
228         conn = TALLOC_ZERO_P(ctx, connection_struct);
229         if (conn == NULL) {
230                 return NT_STATUS_NO_MEMORY;
231         }
232
233         connpath = talloc_strdup(conn, path);
234         if (!connpath) {
235                 TALLOC_FREE(conn);
236                 return NT_STATUS_NO_MEMORY;
237         }
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;
245         }
246
247         /* needed for smbd_vfs_init() */
248
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;
253         }
254
255         conn->params->service = snum;
256
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;
263                 }
264         }
265
266         set_conn_connectpath(conn, connpath);
267
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;
273         }
274
275         conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn);
276
277         /*
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.
281          */
282
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;
289         }
290
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;
298         }
299
300         *pconn = conn;
301         *poldcwd = oldcwd;
302
303         return NT_STATUS_OK;
304 }
305
306 /**********************************************************************
307  Parse the contents of a symlink to verify if it is an msdfs referral
308  A valid referral is of the form:
309
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.
314
315  Note that the alternate paths returned here must be of the canonicalized
316  form:
317
318  \server\share or
319  \server\share\path\to\file,
320
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  **********************************************************************/
324
325 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
326                                 const char *target,
327                                 struct referral **preflist,
328                                 int *refcount)
329 {
330         char *temp = NULL;
331         char *prot;
332         char **alt_path = NULL;
333         int count = 0, i;
334         struct referral *reflist;
335         char *saveptr;
336
337         temp = talloc_strdup(ctx, target);
338         if (!temp) {
339                 return False;
340         }
341         prot = strtok_r(temp, ":", &saveptr);
342         if (!prot) {
343                 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
344                 return False;
345         }
346
347         alt_path = TALLOC_ARRAY(ctx, char *, MAX_REFERRAL_COUNT);
348         if (!alt_path) {
349                 return False;
350         }
351
352         /* parse out the alternate paths */
353         while((count<MAX_REFERRAL_COUNT) &&
354               ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
355                 count++;
356         }
357
358         DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
359
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;
366                 }
367         } else {
368                 reflist = *preflist = NULL;
369         }
370
371         for(i=0;i<count;i++) {
372                 char *p;
373
374                 /* Canonicalize link target.
375                  * Replace all /'s in the path by a \ */
376                 string_replace(alt_path[i], '/', '\\');
377
378                 /* Remove leading '\\'s */
379                 p = alt_path[i];
380                 while (*p && (*p == '\\')) {
381                         p++;
382                 }
383
384                 reflist[i].alternate_path = talloc_asprintf(ctx,
385                                 "\\%s",
386                                 p);
387                 if (!reflist[i].alternate_path) {
388                         return False;
389                 }
390
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));
395         }
396
397         *refcount = count;
398
399         TALLOC_FREE(alt_path);
400         return True;
401 }
402
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 **********************************************************************/
407
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)
413 {
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;
423
424         if (pp_link_target) {
425                 bufsize = 1024;
426                 link_target = TALLOC_ARRAY(ctx, char, bufsize);
427                 if (!link_target) {
428                         return False;
429                 }
430                 *pp_link_target = link_target;
431         } else {
432                 bufsize = sizeof(link_target_buf);
433                 link_target = link_target_buf;
434         }
435
436         if (sbufp == NULL) {
437                 sbufp = &st;
438         }
439
440         if (vfs_lstat_smb_fname(conn, path, sbufp) != 0) {
441                 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
442                         path));
443                 goto err;
444         }
445
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;
450         }
451
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;
458         }
459         link_target[referral_len] = '\0';
460
461         DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path,
462                                 link_target));
463
464         if (!strnequal(link_target, "msdfs:", 6)) {
465                 goto err;
466         }
467         return True;
468
469   err:
470
471         if (link_target != link_target_buf) {
472                 TALLOC_FREE(link_target);
473         }
474         return False;
475 }
476
477 /**********************************************************************
478  Returns true if the unix path is a valid msdfs symlink.
479 **********************************************************************/
480
481 bool is_msdfs_link(connection_struct *conn,
482                 const char *path,
483                 SMB_STRUCT_STAT *sbufp)
484 {
485         return is_msdfs_link_internal(talloc_tos(),
486                                         conn,
487                                         path,
488                                         NULL,
489                                         sbufp);
490 }
491
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.
495
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.
499
500  consumedcntp: how much of the dfs path is being redirected. the client
501  should try the remaining path on the redirected server.
502
503  If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
504  link redirect are in targetpath.
505 *****************************************************************/
506
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)
515 {
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). */
523
524         DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
525                 conn->connectpath, pdp->reqpath));
526
527         /*
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.
537          */
538
539         status = unix_convert(ctx, conn, pdp->reqpath, &smb_fname,
540                               search_flag ? UCF_ALLOW_WCARD_LCOMP : 0);
541
542         if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status,
543                                         NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
544                 return status;
545         }
546
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;
551         }
552
553         TALLOC_FREE(smb_fname);
554
555         /* Optimization - check if we can redirect the whole path. */
556
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;
562                 }
563
564                 DEBUG(6,("dfs_path_lookup: %s resolves to a "
565                         "valid dfs link %s.\n", dfspath,
566                         pp_targetpath ? *pp_targetpath : ""));
567
568                 if (consumedcntp) {
569                         *consumedcntp = strlen(dfspath);
570                 }
571                 return NT_STATUS_PATH_NOT_COVERED;
572         }
573
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 '/'. */
577
578         canon_dfspath = talloc_strdup(ctx, dfspath);
579         if (!canon_dfspath) {
580                 return NT_STATUS_NO_MEMORY;
581         }
582         if (!pdp->posix_path) {
583                 string_replace(canon_dfspath, '\\', '/');
584         }
585
586         /*
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>.
590          */
591
592         trim_char(canon_dfspath,0,'/');
593
594         /*
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.
600          */
601
602         p = strrchr_m(localpath, '/');
603         if (consumedcntp) {
604                 q = strrchr_m(canon_dfspath, '/');
605         }
606
607         while (p) {
608                 *p = '\0';
609                 if (q) {
610                         *q = '\0';
611                 }
612
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));
617
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));
624                         }
625
626                         return NT_STATUS_PATH_NOT_COVERED;
627                 }
628
629                 /* Step back on the filesystem. */
630                 p = strrchr_m(localpath, '/');
631
632                 if (consumedcntp) {
633                         /* And in the canonicalized dfs path. */
634                         q = strrchr_m(canon_dfspath, '/');
635                 }
636         }
637
638         return NT_STATUS_OK;
639 }
640
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
644
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.
648
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 *****************************************************************/
655
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)
662 {
663         NTSTATUS status;
664         struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
665
666         if (!pdp) {
667                 return NT_STATUS_NO_MEMORY;
668         }
669
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;
675         }
676
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;
682                 }
683                 DEBUG(5,("dfs_redirect: self-referral.\n"));
684                 return NT_STATUS_OK;
685         }
686
687         /* If dfs pathname for a non-dfs share, convert to tcon-relative
688            path and return OK */
689
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;
695                 }
696                 return NT_STATUS_OK;
697         }
698
699         /* If it looked like a local path (zero hostname/servicename)
700          * just treat as a tcon-relative path. */
701
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;
707                 }
708                 return NT_STATUS_OK;
709         }
710
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) )) ) {
715
716                 /* The given sharename doesn't match this connection. */
717                 TALLOC_FREE(pdp);
718
719                 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
720         }
721
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) ));
731                 }
732                 return status;
733         }
734
735         DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
736
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;
742         }
743
744         DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
745                                 path_in,
746                                 *pp_path_out));
747
748         return NT_STATUS_OK;
749 }
750
751 /**********************************************************************
752  Return a self referral.
753 **********************************************************************/
754
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)
760 {
761         struct referral *ref;
762
763         *self_referralp = True;
764
765         jucn->referral_count = 1;
766         if((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
767                 return NT_STATUS_NO_MEMORY;
768         }
769
770         ref->alternate_path = talloc_strdup(ctx, dfs_path);
771         if (!ref->alternate_path) {
772                 return NT_STATUS_NO_MEMORY;
773         }
774         ref->proximity = 0;
775         ref->ttl = REFERRAL_TTL;
776         jucn->referral_list = ref;
777         *consumedcntp = strlen(dfs_path);
778         return NT_STATUS_OK;
779 }
780
781 /**********************************************************************
782  Gets valid referrals for a dfs path and fills up the
783  junction_map structure.
784 **********************************************************************/
785
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)
791 {
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;
799
800         if (!pdp) {
801                 return NT_STATUS_NO_MEMORY;
802         }
803
804         *self_referralp = False;
805
806         status = parse_dfs_path(NULL, dfs_path, False, pdp, &dummy);
807         if (!NT_STATUS_IS_OK(status)) {
808                 return status;
809         }
810
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;
816         }
817
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;
825                 }
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;
831                 }
832         }
833
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;
840         }
841
842         /*
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.
848          */
849
850         if (pdp->reqpath[0] == '\0') {
851                 char *tmp;
852                 struct referral *ref;
853
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);
861                 }
862
863                 /*
864                  * It's an msdfs proxy share. Redirect to
865                  * the configured target share.
866                  */
867
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;
872                 }
873
874                 if (!(tmp = talloc_strdup(ctx, lp_msdfs_proxy(snum)))) {
875                         TALLOC_FREE(pdp);
876                         return NT_STATUS_NO_MEMORY;
877                 }
878
879                 trim_string(tmp, "\\", 0);
880
881                 ref->alternate_path = talloc_asprintf(ctx, "\\%s", tmp);
882                 TALLOC_FREE(tmp);
883
884                 if (!ref->alternate_path) {
885                         TALLOC_FREE(pdp);
886                         return NT_STATUS_NO_MEMORY;
887                 }
888
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;
897                         }
898                 }
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;
905         }
906
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;
912         }
913
914         /* If this is a DFS path dfs_lookup should return
915          * NT_STATUS_PATH_NOT_COVERED. */
916
917         status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
918                         False, consumedcntp, &targetpath);
919
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;
927         }
928
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;
939         }
940
941         vfs_ChDir(conn, oldpath);
942         conn_free_internal(conn);
943         TALLOC_FREE(pdp);
944         return NT_STATUS_OK;
945 }
946
947 static int setup_ver2_dfs_referral(const char *pathname,
948                                 char **ppdata,
949                                 struct junction_map *junction,
950                                 bool self_referral)
951 {
952         char* pdata = *ppdata;
953
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;
961
962         DEBUG(10,("Setting up version2 referral\nRequested path:\n"));
963
964         requestedpathlen = rpcstr_push_talloc(talloc_tos(),
965                                         &uni_requestedpath, pathname);
966         if (uni_requestedpath == NULL || requestedpathlen == 0) {
967                 return -1;
968         }
969
970         if (DEBUGLVL(10)) {
971                 dump_data(0, (unsigned char *)uni_requestedpath,
972                         requestedpathlen);
973         }
974
975         DEBUG(10,("ref count = %u\n",junction->referral_count));
976
977         uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
978                         VERSION2_REFERRAL_SIZE * junction->referral_count;
979
980         uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen;
981
982         uni_curroffset = uni_reqpathoffset2 + requestedpathlen;
983
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));
988
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",
992                         i,
993                         junction->referral_list[i].alternate_path));
994                 reply_size +=
995                         (strlen(junction->referral_list[i].alternate_path)+1)*2;
996         }
997
998         DEBUG(10,("reply_size = %u\n",reply_size));
999         /* add the unexplained 0x16 bytes */
1000         reply_size += 0x16;
1001
1002         pdata = (char *)SMB_REALLOC(pdata,reply_size);
1003         if(pdata == NULL) {
1004                 DEBUG(0,("Realloc failed!\n"));
1005                 return -1;
1006         }
1007         *ppdata = pdata;
1008
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);
1012
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);
1022         }
1023
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;
1029
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);
1036                 }
1037
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);
1042
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);
1050
1051                 SSVAL(pdata,offset+20,uni_curroffset-offset);
1052
1053                 uni_curroffset += unilen;
1054                 offset += VERSION2_REFERRAL_SIZE;
1055         }
1056         /* add in the unexplained 22 (0x16) bytes at the end */
1057         memset(pdata+uni_curroffset,'\0',0x16);
1058         return reply_size;
1059 }
1060
1061 static int setup_ver3_dfs_referral(const char *pathname,
1062                                 char **ppdata,
1063                                 struct junction_map *junction,
1064                                 bool self_referral)
1065 {
1066         char *pdata = *ppdata;
1067
1068         smb_ucs2_t *uni_reqpath = NULL;
1069         int uni_reqpathoffset1, uni_reqpathoffset2;
1070         int uni_curroffset;
1071         int reply_size = 0;
1072
1073         int reqpathlen = 0;
1074         int offset,i=0;
1075
1076         DEBUG(10,("setting up version3 referral\n"));
1077
1078         reqpathlen = rpcstr_push_talloc(talloc_tos(), &uni_reqpath, pathname);
1079         if (uni_reqpath == NULL || reqpathlen == 0) {
1080                 return -1;
1081         }
1082
1083         if (DEBUGLVL(10)) {
1084                 dump_data(0, (unsigned char *)uni_reqpath,
1085                         reqpathlen);
1086         }
1087
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;
1092
1093         for(i=0;i<junction->referral_count;i++) {
1094                 DEBUG(10,("referral %u : %s\n",
1095                         i,
1096                         junction->referral_list[i].alternate_path));
1097                 reply_size +=
1098                         (strlen(junction->referral_list[i].alternate_path)+1)*2;
1099         }
1100
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;
1106         }
1107         *ppdata = pdata;
1108
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);
1117         }
1118
1119         /* copy in the reqpaths */
1120         memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen);
1121         memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen);
1122
1123         offset = 8;
1124         for(i=0;i<junction->referral_count;i++) {
1125                 struct referral* ref = &(junction->referral_list[i]);
1126                 int unilen;
1127
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);
1134                 }
1135
1136                 /* ref_flags :use path_consumed bytes? */
1137                 SSVAL(pdata,offset+6,0);
1138                 SIVAL(pdata,offset+8,ref->ttl);
1139
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);
1149
1150                 uni_curroffset += unilen;
1151                 offset += VERSION3_REFERRAL_SIZE;
1152         }
1153         return reply_size;
1154 }
1155
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 ******************************************************************/
1162
1163 int setup_dfs_referral(connection_struct *orig_conn,
1164                         const char *dfs_path,
1165                         int max_referral_level,
1166                         char **ppdata, NTSTATUS *pstatus)
1167 {
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;
1175
1176         if (!(ctx=talloc_init("setup_dfs_referral"))) {
1177                 *pstatus = NT_STATUS_NO_MEMORY;
1178                 return -1;
1179         }
1180
1181         /* get the junction entry */
1182         if (!dfs_path) {
1183                 talloc_destroy(ctx);
1184                 *pstatus = NT_STATUS_NOT_FOUND;
1185                 return -1;
1186         }
1187
1188         /*
1189          * Trim pathname sent by client so it begins with only one backslash.
1190          * Two backslashes confuse some dfs clients
1191          */
1192
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;
1198         }
1199         pathnamep = local_dfs_path;
1200         while (IS_DIRECTORY_SEP(pathnamep[0]) &&
1201                         IS_DIRECTORY_SEP(pathnamep[1])) {
1202                 pathnamep++;
1203         }
1204
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;
1210         }
1211
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;
1219         }
1220         vfs_ChDir(orig_conn,orig_conn->connectpath);
1221
1222         if (!self_referral) {
1223                 pathnamep[consumedcnt] = '\0';
1224
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");
1234                 }
1235         }
1236
1237         /* create the referral depeding on version */
1238         DEBUG(10,("max_referral_level :%d\n",max_referral_level));
1239
1240         if (max_referral_level < 2) {
1241                 max_referral_level = 2;
1242         }
1243         if (max_referral_level > 3) {
1244                 max_referral_level = 3;
1245         }
1246
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;
1264         }
1265
1266         if (DEBUGLVL(10)) {
1267                 DEBUGADD(0,("DFS Referral pdata:\n"));
1268                 dump_data(0,(uint8 *)*ppdata,reply_size);
1269         }
1270
1271         talloc_destroy(ctx);
1272         *pstatus = NT_STATUS_OK;
1273         return reply_size;
1274 }
1275
1276 /**********************************************************************
1277  The following functions are called by the NETDFS RPC pipe functions
1278  **********************************************************************/
1279
1280 /*********************************************************************
1281  Creates a junction structure from a DFS pathname
1282 **********************************************************************/
1283
1284 bool create_junction(TALLOC_CTX *ctx,
1285                 const char *dfs_path,
1286                 struct junction_map *jucn)
1287 {
1288         int snum;
1289         bool dummy;
1290         struct dfs_path *pdp = TALLOC_P(ctx,struct dfs_path);
1291         NTSTATUS status;
1292
1293         if (!pdp) {
1294                 return False;
1295         }
1296         status = parse_dfs_path(NULL, dfs_path, False, pdp, &dummy);
1297         if (!NT_STATUS_IS_OK(status)) {
1298                 return False;
1299         }
1300
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;
1308         }
1309
1310         /* Check for a non-DFS share */
1311         snum = lp_servicenumber(pdp->servicename);
1312
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;
1318         }
1319
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));
1323
1324         TALLOC_FREE(pdp);
1325         if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1326                 return False;
1327         }
1328         return True;
1329 }
1330
1331 /**********************************************************************
1332  Forms a valid Unix pathname from the junction
1333  **********************************************************************/
1334
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)
1339 {
1340         int snum;
1341         NTSTATUS status;
1342
1343         snum = lp_servicenumber(jucn->service_name);
1344         if(snum < 0) {
1345                 return False;
1346         }
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;
1351         }
1352
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;
1361         }
1362         return True;
1363 }
1364
1365 bool create_msdfs_link(const struct junction_map *jucn)
1366 {
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;
1374
1375         if(!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1376                 return False;
1377         }
1378
1379         /* Form the msdfs_link contents */
1380         msdfs_link = talloc_strdup(conn, "msdfs:");
1381         if (!msdfs_link) {
1382                 goto out;
1383         }
1384         for(i=0; i<jucn->referral_count; i++) {
1385                 char *refpath = jucn->referral_list[i].alternate_path;
1386
1387                 /* Alternate paths always use Windows separators. */
1388                 trim_char(refpath, '\\', '\\');
1389                 if(*refpath == '\0') {
1390                         if (i == 0) {
1391                                 insert_comma = False;
1392                         }
1393                         continue;
1394                 }
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);
1403                 }
1404
1405                 if (!msdfs_link) {
1406                         goto out;
1407                 }
1408                 if (!insert_comma) {
1409                         insert_comma = True;
1410                 }
1411         }
1412
1413         DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1414                 path, msdfs_link));
1415
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;
1420                         }
1421                 }
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;
1427                 }
1428         }
1429
1430         ret = True;
1431
1432 out:
1433         vfs_ChDir(conn, cwd);
1434         conn_free_internal(conn);
1435         return ret;
1436 }
1437
1438 bool remove_msdfs_link(const struct junction_map *jucn)
1439 {
1440         char *path = NULL;
1441         char *cwd;
1442         connection_struct *conn;
1443         bool ret = False;
1444
1445         if (!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1446                 return false;
1447         }
1448
1449         if( SMB_VFS_UNLINK(conn, path) == 0 ) {
1450                 ret = True;
1451         }
1452
1453         vfs_ChDir(conn, cwd);
1454         conn_free_internal(conn);
1455         return ret;
1456 }
1457
1458 /*********************************************************************
1459  Return the number of DFS links at the root of this share.
1460 *********************************************************************/
1461
1462 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1463 {
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;
1472
1473         if(*connect_path == '\0') {
1474                 return 0;
1475         }
1476
1477         /*
1478          * Fake up a connection struct for the VFS layer.
1479          */
1480
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;
1487         }
1488
1489         /* Count a link for the msdfs root - convention */
1490         cnt = 1;
1491
1492         /* No more links if this is an msdfs proxy. */
1493         if (*msdfs_proxy != '\0') {
1494                 goto out;
1495         }
1496
1497         /* Now enumerate all dfs links */
1498         dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1499         if(!dirp) {
1500                 goto out;
1501         }
1502
1503         while ((dname = vfs_readdirname(conn, dirp, NULL)) != NULL) {
1504                 if (is_msdfs_link(conn,
1505                                 dname,
1506                                 NULL)) {
1507                         cnt++;
1508                 }
1509         }
1510
1511         SMB_VFS_CLOSEDIR(conn,dirp);
1512
1513 out:
1514         vfs_ChDir(conn, cwd);
1515         conn_free_internal(conn);
1516         return cnt;
1517 }
1518
1519 /*********************************************************************
1520 *********************************************************************/
1521
1522 static int form_junctions(TALLOC_CTX *ctx,
1523                                 int snum,
1524                                 struct junction_map *jucn,
1525                                 size_t jn_remain)
1526 {
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;
1537
1538         if (jn_remain == 0) {
1539                 return 0;
1540         }
1541
1542         if(*connect_path == '\0') {
1543                 return 0;
1544         }
1545
1546         /*
1547          * Fake up a connection struct for the VFS layer.
1548          */
1549
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;
1556         }
1557
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
1561         */
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;
1566         }
1567         jucn[cnt].comment = "";
1568         jucn[cnt].referral_count = 1;
1569
1570         ref = jucn[cnt].referral_list = TALLOC_ZERO_P(ctx, struct referral);
1571         if (jucn[cnt].referral_list == NULL) {
1572                 goto out;
1573         }
1574
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);
1585         }
1586
1587         if (!ref->alternate_path) {
1588                 goto out;
1589         }
1590         cnt++;
1591
1592         /* Don't enumerate if we're an msdfs proxy. */
1593         if (*msdfs_proxy != '\0') {
1594                 goto out;
1595         }
1596
1597         /* Now enumerate all dfs links */
1598         dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1599         if(!dirp) {
1600                 goto out;
1601         }
1602
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;
1609                 }
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)) {
1618
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;
1626                                 }
1627                                 jucn[cnt].comment = "";
1628                                 cnt++;
1629                         }
1630                         TALLOC_FREE(link_target);
1631                 }
1632         }
1633
1634 out:
1635
1636         if (dirp) {
1637                 SMB_VFS_CLOSEDIR(conn,dirp);
1638         }
1639
1640         vfs_ChDir(conn, cwd);
1641         conn_free_internal(conn);
1642         return cnt;
1643 }
1644
1645 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1646 {
1647         struct junction_map *jn = NULL;
1648         int i=0;
1649         size_t jn_count = 0;
1650         int sharecount = 0;
1651
1652         *p_num_jn = 0;
1653         if(!lp_host_msdfs()) {
1654                 return NULL;
1655         }
1656
1657         /* Ensure all the usershares are loaded. */
1658         become_root();
1659         load_registry_shares();
1660         sharecount = load_usershare_shares();
1661         unbecome_root();
1662
1663         for(i=0;i < sharecount;i++) {
1664                 if(lp_msdfs_root(i)) {
1665                         jn_count += count_dfs_links(ctx, i);
1666                 }
1667         }
1668         if (jn_count == 0) {
1669                 return NULL;
1670         }
1671         jn = TALLOC_ARRAY(ctx,  struct junction_map, jn_count);
1672         if (!jn) {
1673                 return NULL;
1674         }
1675         for(i=0; i < sharecount; i++) {
1676                 if (*p_num_jn >= jn_count) {
1677                         break;
1678                 }
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);
1683                 }
1684         }
1685         return jn;
1686 }
1687
1688 /******************************************************************************
1689  Core function to resolve a dfs pathname.
1690 ******************************************************************************/
1691
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)
1697 {
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 {
1708                 /*
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.
1712                  */
1713                 *pp_name_out = CONST_DISCARD(char *,name_in);
1714         }
1715         return status;
1716 }
1717
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 ******************************************************************************/
1724
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)
1731 {
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 {
1741                 /*
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.
1745                  */
1746                 *pp_name_out = CONST_DISCARD(char *,name_in);
1747         }
1748         return status;
1749 }