Fix bug #7781 (Samba transforms "ShareName" to lowercase when adding new share via...
[samba.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(conn);
272                 return status;
273         }
274
275         conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
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(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(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         int referral_len = 0;
415 #if defined(HAVE_BROKEN_READLINK)
416         char link_target_buf[PATH_MAX];
417 #else
418         char link_target_buf[7];
419 #endif
420         size_t bufsize = 0;
421         char *link_target = NULL;
422         struct smb_filename smb_fname;
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         ZERO_STRUCT(smb_fname);
437         smb_fname.base_name = discard_const_p(char, path);
438
439         if (SMB_VFS_LSTAT(conn, &smb_fname) != 0) {
440                 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
441                         path));
442                 goto err;
443         }
444         if (!S_ISLNK(smb_fname.st.st_ex_mode)) {
445                 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
446                                         path));
447                 goto err;
448         }
449         if (sbufp != NULL) {
450                 *sbufp = smb_fname.st;
451         }
452
453         referral_len = SMB_VFS_READLINK(conn, path, link_target, bufsize - 1);
454         if (referral_len == -1) {
455                 DEBUG(0,("is_msdfs_link_read_target: Error reading "
456                         "msdfs link %s: %s\n",
457                         path, strerror(errno)));
458                 goto err;
459         }
460         link_target[referral_len] = '\0';
461
462         DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path,
463                                 link_target));
464
465         if (!strnequal(link_target, "msdfs:", 6)) {
466                 goto err;
467         }
468         return True;
469
470   err:
471
472         if (link_target != link_target_buf) {
473                 TALLOC_FREE(link_target);
474         }
475         return False;
476 }
477
478 /**********************************************************************
479  Returns true if the unix path is a valid msdfs symlink.
480 **********************************************************************/
481
482 bool is_msdfs_link(connection_struct *conn,
483                 const char *path,
484                 SMB_STRUCT_STAT *sbufp)
485 {
486         return is_msdfs_link_internal(talloc_tos(),
487                                         conn,
488                                         path,
489                                         NULL,
490                                         sbufp);
491 }
492
493 /*****************************************************************
494  Used by other functions to decide if a dfs path is remote,
495  and to get the list of referred locations for that remote path.
496
497  search_flag: For findfirsts, dfs links themselves are not
498  redirected, but paths beyond the links are. For normal smb calls,
499  even dfs links need to be redirected.
500
501  consumedcntp: how much of the dfs path is being redirected. the client
502  should try the remaining path on the redirected server.
503
504  If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
505  link redirect are in targetpath.
506 *****************************************************************/
507
508 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
509                 connection_struct *conn,
510                 const char *dfspath, /* Incoming complete dfs path */
511                 const struct dfs_path *pdp, /* Parsed out
512                                                server+share+extrapath. */
513                 bool search_flag, /* Called from a findfirst ? */
514                 int *consumedcntp,
515                 char **pp_targetpath)
516 {
517         char *p = NULL;
518         char *q = NULL;
519         NTSTATUS status;
520         struct smb_filename *smb_fname = 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
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          */
533
534         status = unix_convert(ctx, conn, pdp->reqpath, &smb_fname,
535                               search_flag ? UCF_ALWAYS_ALLOW_WCARD_LCOMP : 0);
536
537         if (!NT_STATUS_IS_OK(status)) {
538                 if (!NT_STATUS_EQUAL(status,
539                                      NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
540                         return status;
541                 }
542                 if (smb_fname == NULL || smb_fname->base_name == NULL) {
543                         return status;
544                 }
545         }
546
547         /* Optimization - check if we can redirect the whole path. */
548
549         if (is_msdfs_link_internal(ctx, conn, smb_fname->base_name,
550                                    pp_targetpath, NULL)) {
551                 if (search_flag) {
552                         DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
553                                  "for dfs link %s.\n", dfspath));
554                         status = NT_STATUS_OK;
555                         goto out;
556                 }
557
558                 DEBUG(6,("dfs_path_lookup: %s resolves to a "
559                         "valid dfs link %s.\n", dfspath,
560                         pp_targetpath ? *pp_targetpath : ""));
561
562                 if (consumedcntp) {
563                         *consumedcntp = strlen(dfspath);
564                 }
565                 status = NT_STATUS_PATH_NOT_COVERED;
566                 goto out;
567         }
568
569         /* Prepare to test only for '/' components in the given path,
570          * so if a Windows path replace all '\\' characters with '/'.
571          * For a POSIX DFS path we know all separators are already '/'. */
572
573         canon_dfspath = talloc_strdup(ctx, dfspath);
574         if (!canon_dfspath) {
575                 status = NT_STATUS_NO_MEMORY;
576                 goto out;
577         }
578         if (!pdp->posix_path) {
579                 string_replace(canon_dfspath, '\\', '/');
580         }
581
582         /*
583          * localpath comes out of unix_convert, so it has
584          * no trailing backslash. Make sure that canon_dfspath hasn't either.
585          * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
586          */
587
588         trim_char(canon_dfspath,0,'/');
589
590         /*
591          * Redirect if any component in the path is a link.
592          * We do this by walking backwards through the
593          * local path, chopping off the last component
594          * in both the local path and the canonicalized
595          * DFS path. If we hit a DFS link then we're done.
596          */
597
598         p = strrchr_m(smb_fname->base_name, '/');
599         if (consumedcntp) {
600                 q = strrchr_m(canon_dfspath, '/');
601         }
602
603         while (p) {
604                 *p = '\0';
605                 if (q) {
606                         *q = '\0';
607                 }
608
609                 if (is_msdfs_link_internal(ctx, conn,
610                                            smb_fname->base_name, pp_targetpath,
611                                            NULL)) {
612                         DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
613                                   "parent %s is dfs link\n", dfspath,
614                                   smb_fname_str_dbg(smb_fname)));
615
616                         if (consumedcntp) {
617                                 *consumedcntp = strlen(canon_dfspath);
618                                 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
619                                         "(%d)\n",
620                                         canon_dfspath,
621                                         *consumedcntp));
622                         }
623
624                         status = NT_STATUS_PATH_NOT_COVERED;
625                         goto out;
626                 }
627
628                 /* Step back on the filesystem. */
629                 p = strrchr_m(smb_fname->base_name, '/');
630
631                 if (consumedcntp) {
632                         /* And in the canonicalized dfs path. */
633                         q = strrchr_m(canon_dfspath, '/');
634                 }
635         }
636
637         status = NT_STATUS_OK;
638  out:
639         TALLOC_FREE(smb_fname);
640         return status;
641 }
642
643 /*****************************************************************
644  Decides if a dfs pathname should be redirected or not.
645  If not, the pathname is converted to a tcon-relative local unix path
646
647  search_wcard_flag: this flag performs 2 functions both related
648  to searches.  See resolve_dfs_path() and parse_dfs_path_XX()
649  for details.
650
651  This function can return NT_STATUS_OK, meaning use the returned path as-is
652  (mapped into a local path).
653  or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
654  any other NT_STATUS error which is a genuine error to be
655  returned to the client.
656 *****************************************************************/
657
658 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
659                         connection_struct *conn,
660                         const char *path_in,
661                         bool search_wcard_flag,
662                         char **pp_path_out,
663                         bool *ppath_contains_wcard)
664 {
665         NTSTATUS status;
666         struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
667
668         if (!pdp) {
669                 return NT_STATUS_NO_MEMORY;
670         }
671
672         status = parse_dfs_path(conn, path_in, search_wcard_flag, pdp,
673                         ppath_contains_wcard);
674         if (!NT_STATUS_IS_OK(status)) {
675                 TALLOC_FREE(pdp);
676                 return status;
677         }
678
679         if (pdp->reqpath[0] == '\0') {
680                 TALLOC_FREE(pdp);
681                 *pp_path_out = talloc_strdup(ctx, "");
682                 if (!*pp_path_out) {
683                         return NT_STATUS_NO_MEMORY;
684                 }
685                 DEBUG(5,("dfs_redirect: self-referral.\n"));
686                 return NT_STATUS_OK;
687         }
688
689         /* If dfs pathname for a non-dfs share, convert to tcon-relative
690            path and return OK */
691
692         if (!lp_msdfs_root(SNUM(conn))) {
693                 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
694                 TALLOC_FREE(pdp);
695                 if (!*pp_path_out) {
696                         return NT_STATUS_NO_MEMORY;
697                 }
698                 return NT_STATUS_OK;
699         }
700
701         /* If it looked like a local path (zero hostname/servicename)
702          * just treat as a tcon-relative path. */
703
704         if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
705                 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
706                 TALLOC_FREE(pdp);
707                 if (!*pp_path_out) {
708                         return NT_STATUS_NO_MEMORY;
709                 }
710                 return NT_STATUS_OK;
711         }
712
713         if (!( strequal(pdp->servicename, lp_servicename(SNUM(conn)))
714                         || (strequal(pdp->servicename, HOMES_NAME)
715                         && strequal(lp_servicename(SNUM(conn)),
716                                 conn->server_info->sanitized_username) )) ) {
717
718                 /* The given sharename doesn't match this connection. */
719                 TALLOC_FREE(pdp);
720
721                 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
722         }
723
724         status = dfs_path_lookup(ctx, conn, path_in, pdp,
725                         search_wcard_flag, NULL, NULL);
726         if (!NT_STATUS_IS_OK(status)) {
727                 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
728                         DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
729                 } else {
730                         DEBUG(10,("dfs_redirect: dfs_path_lookup "
731                                 "failed for %s with %s\n",
732                                 path_in, nt_errstr(status) ));
733                 }
734                 return status;
735         }
736
737         DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
738
739         /* Form non-dfs tcon-relative path */
740         *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
741         TALLOC_FREE(pdp);
742         if (!*pp_path_out) {
743                 return NT_STATUS_NO_MEMORY;
744         }
745
746         DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
747                                 path_in,
748                                 *pp_path_out));
749
750         return NT_STATUS_OK;
751 }
752
753 /**********************************************************************
754  Return a self referral.
755 **********************************************************************/
756
757 static NTSTATUS self_ref(TALLOC_CTX *ctx,
758                         const char *dfs_path,
759                         struct junction_map *jucn,
760                         int *consumedcntp,
761                         bool *self_referralp)
762 {
763         struct referral *ref;
764
765         *self_referralp = True;
766
767         jucn->referral_count = 1;
768         if((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
769                 return NT_STATUS_NO_MEMORY;
770         }
771
772         ref->alternate_path = talloc_strdup(ctx, dfs_path);
773         if (!ref->alternate_path) {
774                 return NT_STATUS_NO_MEMORY;
775         }
776         ref->proximity = 0;
777         ref->ttl = REFERRAL_TTL;
778         jucn->referral_list = ref;
779         *consumedcntp = strlen(dfs_path);
780         return NT_STATUS_OK;
781 }
782
783 /**********************************************************************
784  Gets valid referrals for a dfs path and fills up the
785  junction_map structure.
786 **********************************************************************/
787
788 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
789                         struct auth_serversupplied_info *server_info,
790                         const char *dfs_path,
791                         struct junction_map *jucn,
792                         int *consumedcntp,
793                         bool *self_referralp)
794 {
795         struct connection_struct *conn;
796         char *targetpath = NULL;
797         int snum;
798         NTSTATUS status = NT_STATUS_NOT_FOUND;
799         bool dummy;
800         struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
801         char *oldpath;
802
803         if (!pdp) {
804                 return NT_STATUS_NO_MEMORY;
805         }
806
807         *self_referralp = False;
808
809         status = parse_dfs_path(NULL, dfs_path, False, pdp, &dummy);
810         if (!NT_STATUS_IS_OK(status)) {
811                 return status;
812         }
813
814         jucn->service_name = talloc_strdup(ctx, pdp->servicename);
815         jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
816         if (!jucn->service_name || !jucn->volume_name) {
817                 TALLOC_FREE(pdp);
818                 return NT_STATUS_NO_MEMORY;
819         }
820
821         /* Verify the share is a dfs root */
822         snum = lp_servicenumber(jucn->service_name);
823         if(snum < 0) {
824                 fstring service_name;
825                 if ((snum = find_service(jucn->service_name, service_name)) < 0) {
826                         return NT_STATUS_NOT_FOUND;
827                 }
828                 TALLOC_FREE(jucn->service_name);
829                 jucn->service_name = talloc_strdup(ctx, service_name);
830                 if (!jucn->service_name) {
831                         TALLOC_FREE(pdp);
832                         return NT_STATUS_NO_MEMORY;
833                 }
834         }
835
836         if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(snum) == '\0')) {
837                 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
838                         "a dfs root.\n",
839                         pdp->servicename, dfs_path));
840                 TALLOC_FREE(pdp);
841                 return NT_STATUS_NOT_FOUND;
842         }
843
844         /*
845          * Self referrals are tested with a anonymous IPC connection and
846          * a GET_DFS_REFERRAL call to \\server\share. (which means
847          * dp.reqpath[0] points to an empty string). create_conn_struct cd's
848          * into the directory and will fail if it cannot (as the anonymous
849          * user). Cope with this.
850          */
851
852         if (pdp->reqpath[0] == '\0') {
853                 char *tmp;
854                 struct referral *ref;
855
856                 if (*lp_msdfs_proxy(snum) == '\0') {
857                         TALLOC_FREE(pdp);
858                         return self_ref(ctx,
859                                         dfs_path,
860                                         jucn,
861                                         consumedcntp,
862                                         self_referralp);
863                 }
864
865                 /*
866                  * It's an msdfs proxy share. Redirect to
867                  * the configured target share.
868                  */
869
870                 jucn->referral_count = 1;
871                 if ((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
872                         TALLOC_FREE(pdp);
873                         return NT_STATUS_NO_MEMORY;
874                 }
875
876                 if (!(tmp = talloc_strdup(ctx, lp_msdfs_proxy(snum)))) {
877                         TALLOC_FREE(pdp);
878                         return NT_STATUS_NO_MEMORY;
879                 }
880
881                 trim_string(tmp, "\\", 0);
882
883                 ref->alternate_path = talloc_asprintf(ctx, "\\%s", tmp);
884                 TALLOC_FREE(tmp);
885
886                 if (!ref->alternate_path) {
887                         TALLOC_FREE(pdp);
888                         return NT_STATUS_NO_MEMORY;
889                 }
890
891                 if (pdp->reqpath[0] != '\0') {
892                         ref->alternate_path = talloc_asprintf_append(
893                                         ref->alternate_path,
894                                         "%s",
895                                         pdp->reqpath);
896                         if (!ref->alternate_path) {
897                                 TALLOC_FREE(pdp);
898                                 return NT_STATUS_NO_MEMORY;
899                         }
900                 }
901                 ref->proximity = 0;
902                 ref->ttl = REFERRAL_TTL;
903                 jucn->referral_list = ref;
904                 *consumedcntp = strlen(dfs_path);
905                 TALLOC_FREE(pdp);
906                 return NT_STATUS_OK;
907         }
908
909         status = create_conn_struct(ctx, &conn, snum, lp_pathname(snum),
910                                     server_info, &oldpath);
911         if (!NT_STATUS_IS_OK(status)) {
912                 TALLOC_FREE(pdp);
913                 return status;
914         }
915
916         /* If this is a DFS path dfs_lookup should return
917          * NT_STATUS_PATH_NOT_COVERED. */
918
919         status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
920                         False, consumedcntp, &targetpath);
921
922         if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
923                 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
924                         dfs_path));
925                 vfs_ChDir(conn, oldpath);
926                 conn_free(conn);
927                 TALLOC_FREE(pdp);
928                 return status;
929         }
930
931         /* We know this is a valid dfs link. Parse the targetpath. */
932         if (!parse_msdfs_symlink(ctx, targetpath,
933                                 &jucn->referral_list,
934                                 &jucn->referral_count)) {
935                 DEBUG(3,("get_referred_path: failed to parse symlink "
936                         "target %s\n", targetpath ));
937                 vfs_ChDir(conn, oldpath);
938                 conn_free(conn);
939                 TALLOC_FREE(pdp);
940                 return NT_STATUS_NOT_FOUND;
941         }
942
943         vfs_ChDir(conn, oldpath);
944         conn_free(conn);
945         TALLOC_FREE(pdp);
946         return NT_STATUS_OK;
947 }
948
949 static int setup_ver2_dfs_referral(const char *pathname,
950                                 char **ppdata,
951                                 struct junction_map *junction,
952                                 bool self_referral)
953 {
954         char* pdata = *ppdata;
955
956         smb_ucs2_t *uni_requestedpath = NULL;
957         int uni_reqpathoffset1,uni_reqpathoffset2;
958         int uni_curroffset;
959         int requestedpathlen=0;
960         int offset;
961         int reply_size = 0;
962         int i=0;
963
964         DEBUG(10,("Setting up version2 referral\nRequested path:\n"));
965
966         requestedpathlen = rpcstr_push_talloc(talloc_tos(),
967                                         &uni_requestedpath, pathname);
968         if (uni_requestedpath == NULL || requestedpathlen == 0) {
969                 return -1;
970         }
971
972         if (DEBUGLVL(10)) {
973                 dump_data(0, (unsigned char *)uni_requestedpath,
974                         requestedpathlen);
975         }
976
977         DEBUG(10,("ref count = %u\n",junction->referral_count));
978
979         uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
980                         VERSION2_REFERRAL_SIZE * junction->referral_count;
981
982         uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen;
983
984         uni_curroffset = uni_reqpathoffset2 + requestedpathlen;
985
986         reply_size = REFERRAL_HEADER_SIZE +
987                         VERSION2_REFERRAL_SIZE*junction->referral_count +
988                         2 * requestedpathlen;
989         DEBUG(10,("reply_size: %u\n",reply_size));
990
991         /* add up the unicode lengths of all the referral paths */
992         for(i=0;i<junction->referral_count;i++) {
993                 DEBUG(10,("referral %u : %s\n",
994                         i,
995                         junction->referral_list[i].alternate_path));
996                 reply_size +=
997                         (strlen(junction->referral_list[i].alternate_path)+1)*2;
998         }
999
1000         DEBUG(10,("reply_size = %u\n",reply_size));
1001         /* add the unexplained 0x16 bytes */
1002         reply_size += 0x16;
1003
1004         pdata = (char *)SMB_REALLOC(pdata,reply_size);
1005         if(pdata == NULL) {
1006                 DEBUG(0,("Realloc failed!\n"));
1007                 return -1;
1008         }
1009         *ppdata = pdata;
1010
1011         /* copy in the dfs requested paths.. required for offset calculations */
1012         memcpy(pdata+uni_reqpathoffset1,uni_requestedpath,requestedpathlen);
1013         memcpy(pdata+uni_reqpathoffset2,uni_requestedpath,requestedpathlen);
1014
1015         /* create the header */
1016         SSVAL(pdata,0,requestedpathlen - 2); /* UCS2 of path consumed minus
1017                                                 2 byte null */
1018         /* number of referral in this pkt */
1019         SSVAL(pdata,2,junction->referral_count);
1020         if(self_referral) {
1021                 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
1022         } else {
1023                 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
1024         }
1025
1026         offset = 8;
1027         /* add the referral elements */
1028         for(i=0;i<junction->referral_count;i++) {
1029                 struct referral* ref = &junction->referral_list[i];
1030                 int unilen;
1031
1032                 SSVAL(pdata,offset,2); /* version 2 */
1033                 SSVAL(pdata,offset+2,VERSION2_REFERRAL_SIZE);
1034                 if(self_referral) {
1035                         SSVAL(pdata,offset+4,1);
1036                 } else {
1037                         SSVAL(pdata,offset+4,0);
1038                 }
1039
1040                 /* ref_flags :use path_consumed bytes? */
1041                 SSVAL(pdata,offset+6,0);
1042                 SIVAL(pdata,offset+8,ref->proximity);
1043                 SIVAL(pdata,offset+12,ref->ttl);
1044
1045                 SSVAL(pdata,offset+16,uni_reqpathoffset1-offset);
1046                 SSVAL(pdata,offset+18,uni_reqpathoffset2-offset);
1047                 /* copy referred path into current offset */
1048                 unilen = rpcstr_push(pdata+uni_curroffset,
1049                                         ref->alternate_path,
1050                                         reply_size - uni_curroffset,
1051                                         STR_UNICODE);
1052
1053                 SSVAL(pdata,offset+20,uni_curroffset-offset);
1054
1055                 uni_curroffset += unilen;
1056                 offset += VERSION2_REFERRAL_SIZE;
1057         }
1058         /* add in the unexplained 22 (0x16) bytes at the end */
1059         memset(pdata+uni_curroffset,'\0',0x16);
1060         return reply_size;
1061 }
1062
1063 static int setup_ver3_dfs_referral(const char *pathname,
1064                                 char **ppdata,
1065                                 struct junction_map *junction,
1066                                 bool self_referral)
1067 {
1068         char *pdata = *ppdata;
1069
1070         smb_ucs2_t *uni_reqpath = NULL;
1071         int uni_reqpathoffset1, uni_reqpathoffset2;
1072         int uni_curroffset;
1073         int reply_size = 0;
1074
1075         int reqpathlen = 0;
1076         int offset,i=0;
1077
1078         DEBUG(10,("setting up version3 referral\n"));
1079
1080         reqpathlen = rpcstr_push_talloc(talloc_tos(), &uni_reqpath, pathname);
1081         if (uni_reqpath == NULL || reqpathlen == 0) {
1082                 return -1;
1083         }
1084
1085         if (DEBUGLVL(10)) {
1086                 dump_data(0, (unsigned char *)uni_reqpath,
1087                         reqpathlen);
1088         }
1089
1090         uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
1091                         VERSION3_REFERRAL_SIZE * junction->referral_count;
1092         uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen;
1093         reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen;
1094
1095         for(i=0;i<junction->referral_count;i++) {
1096                 DEBUG(10,("referral %u : %s\n",
1097                         i,
1098                         junction->referral_list[i].alternate_path));
1099                 reply_size +=
1100                         (strlen(junction->referral_list[i].alternate_path)+1)*2;
1101         }
1102
1103         pdata = (char *)SMB_REALLOC(pdata,reply_size);
1104         if(pdata == NULL) {
1105                 DEBUG(0,("version3 referral setup:"
1106                         "malloc failed for Realloc!\n"));
1107                 return -1;
1108         }
1109         *ppdata = pdata;
1110
1111         /* create the header */
1112         SSVAL(pdata,0,reqpathlen - 2); /* UCS2 of path consumed minus
1113                                           2 byte null */
1114         SSVAL(pdata,2,junction->referral_count); /* number of referral */
1115         if(self_referral) {
1116                 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
1117         } else {
1118                 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
1119         }
1120
1121         /* copy in the reqpaths */
1122         memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen);
1123         memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen);
1124
1125         offset = 8;
1126         for(i=0;i<junction->referral_count;i++) {
1127                 struct referral* ref = &(junction->referral_list[i]);
1128                 int unilen;
1129
1130                 SSVAL(pdata,offset,3); /* version 3 */
1131                 SSVAL(pdata,offset+2,VERSION3_REFERRAL_SIZE);
1132                 if(self_referral) {
1133                         SSVAL(pdata,offset+4,1);
1134                 } else {
1135                         SSVAL(pdata,offset+4,0);
1136                 }
1137
1138                 /* ref_flags :use path_consumed bytes? */
1139                 SSVAL(pdata,offset+6,0);
1140                 SIVAL(pdata,offset+8,ref->ttl);
1141
1142                 SSVAL(pdata,offset+12,uni_reqpathoffset1-offset);
1143                 SSVAL(pdata,offset+14,uni_reqpathoffset2-offset);
1144                 /* copy referred path into current offset */
1145                 unilen = rpcstr_push(pdata+uni_curroffset,ref->alternate_path,
1146                                         reply_size - uni_curroffset,
1147                                         STR_UNICODE | STR_TERMINATE);
1148                 SSVAL(pdata,offset+16,uni_curroffset-offset);
1149                 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
1150                 memset(pdata+offset+18,'\0',16);
1151
1152                 uni_curroffset += unilen;
1153                 offset += VERSION3_REFERRAL_SIZE;
1154         }
1155         return reply_size;
1156 }
1157
1158 /******************************************************************
1159  Set up the DFS referral for the dfs pathname. This call returns
1160  the amount of the path covered by this server, and where the
1161  client should be redirected to. This is the meat of the
1162  TRANS2_GET_DFS_REFERRAL call.
1163 ******************************************************************/
1164
1165 int setup_dfs_referral(connection_struct *orig_conn,
1166                         const char *dfs_path,
1167                         int max_referral_level,
1168                         char **ppdata, NTSTATUS *pstatus)
1169 {
1170         struct junction_map *junction = NULL;
1171         int consumedcnt = 0;
1172         bool self_referral = False;
1173         int reply_size = 0;
1174         char *pathnamep = NULL;
1175         char *local_dfs_path = NULL;
1176         TALLOC_CTX *ctx;
1177
1178         if (!(ctx=talloc_init("setup_dfs_referral"))) {
1179                 *pstatus = NT_STATUS_NO_MEMORY;
1180                 return -1;
1181         }
1182
1183         /* get the junction entry */
1184         if (!dfs_path) {
1185                 talloc_destroy(ctx);
1186                 *pstatus = NT_STATUS_NOT_FOUND;
1187                 return -1;
1188         }
1189
1190         /*
1191          * Trim pathname sent by client so it begins with only one backslash.
1192          * Two backslashes confuse some dfs clients
1193          */
1194
1195         local_dfs_path = talloc_strdup(ctx,dfs_path);
1196         if (!local_dfs_path) {
1197                 *pstatus = NT_STATUS_NO_MEMORY;
1198                 talloc_destroy(ctx);
1199                 return -1;
1200         }
1201         pathnamep = local_dfs_path;
1202         while (IS_DIRECTORY_SEP(pathnamep[0]) &&
1203                         IS_DIRECTORY_SEP(pathnamep[1])) {
1204                 pathnamep++;
1205         }
1206
1207         junction = TALLOC_ZERO_P(ctx, struct junction_map);
1208         if (!junction) {
1209                 *pstatus = NT_STATUS_NO_MEMORY;
1210                 talloc_destroy(ctx);
1211                 return -1;
1212         }
1213
1214         /* The following call can change cwd. */
1215         *pstatus = get_referred_path(ctx, orig_conn->server_info,
1216                                      pathnamep, junction,
1217                                      &consumedcnt, &self_referral);
1218         if (!NT_STATUS_IS_OK(*pstatus)) {
1219                 vfs_ChDir(orig_conn,orig_conn->connectpath);
1220                 talloc_destroy(ctx);
1221                 return -1;
1222         }
1223         vfs_ChDir(orig_conn,orig_conn->connectpath);
1224
1225         if (!self_referral) {
1226                 pathnamep[consumedcnt] = '\0';
1227
1228                 if( DEBUGLVL( 3 ) ) {
1229                         int i=0;
1230                         dbgtext("setup_dfs_referral: Path %s to "
1231                                 "alternate path(s):",
1232                                 pathnamep);
1233                         for(i=0;i<junction->referral_count;i++)
1234                                 dbgtext(" %s",
1235                                 junction->referral_list[i].alternate_path);
1236                         dbgtext(".\n");
1237                 }
1238         }
1239
1240         /* create the referral depeding on version */
1241         DEBUG(10,("max_referral_level :%d\n",max_referral_level));
1242
1243         if (max_referral_level < 2) {
1244                 max_referral_level = 2;
1245         }
1246         if (max_referral_level > 3) {
1247                 max_referral_level = 3;
1248         }
1249
1250         switch(max_referral_level) {
1251         case 2:
1252                 reply_size = setup_ver2_dfs_referral(pathnamep,
1253                                         ppdata, junction,
1254                                         self_referral);
1255                 break;
1256         case 3:
1257                 reply_size = setup_ver3_dfs_referral(pathnamep, ppdata,
1258                                         junction, self_referral);
1259                 break;
1260         default:
1261                 DEBUG(0,("setup_dfs_referral: Invalid dfs referral "
1262                         "version: %d\n",
1263                         max_referral_level));
1264                 talloc_destroy(ctx);
1265                 *pstatus = NT_STATUS_INVALID_LEVEL;
1266                 return -1;
1267         }
1268
1269         if (DEBUGLVL(10)) {
1270                 DEBUGADD(0,("DFS Referral pdata:\n"));
1271                 dump_data(0,(uint8 *)*ppdata,reply_size);
1272         }
1273
1274         talloc_destroy(ctx);
1275         *pstatus = NT_STATUS_OK;
1276         return reply_size;
1277 }
1278
1279 /**********************************************************************
1280  The following functions are called by the NETDFS RPC pipe functions
1281  **********************************************************************/
1282
1283 /*********************************************************************
1284  Creates a junction structure from a DFS pathname
1285 **********************************************************************/
1286
1287 bool create_junction(TALLOC_CTX *ctx,
1288                 const char *dfs_path,
1289                 struct junction_map *jucn)
1290 {
1291         int snum;
1292         bool dummy;
1293         struct dfs_path *pdp = TALLOC_P(ctx,struct dfs_path);
1294         NTSTATUS status;
1295
1296         if (!pdp) {
1297                 return False;
1298         }
1299         status = parse_dfs_path(NULL, dfs_path, False, pdp, &dummy);
1300         if (!NT_STATUS_IS_OK(status)) {
1301                 return False;
1302         }
1303
1304         /* check if path is dfs : validate first token */
1305         if (!is_myname_or_ipaddr(pdp->hostname)) {
1306                 DEBUG(4,("create_junction: Invalid hostname %s "
1307                         "in dfs path %s\n",
1308                         pdp->hostname, dfs_path));
1309                 TALLOC_FREE(pdp);
1310                 return False;
1311         }
1312
1313         /* Check for a non-DFS share */
1314         snum = lp_servicenumber(pdp->servicename);
1315
1316         if(snum < 0 || !lp_msdfs_root(snum)) {
1317                 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1318                         pdp->servicename));
1319                 TALLOC_FREE(pdp);
1320                 return False;
1321         }
1322
1323         jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1324         jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1325         jucn->comment = talloc_strdup(ctx, lp_comment(snum));
1326
1327         TALLOC_FREE(pdp);
1328         if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1329                 return False;
1330         }
1331         return True;
1332 }
1333
1334 /**********************************************************************
1335  Forms a valid Unix pathname from the junction
1336  **********************************************************************/
1337
1338 static bool junction_to_local_path(const struct junction_map *jucn,
1339                                    char **pp_path_out,
1340                                    connection_struct **conn_out,
1341                                    char **oldpath)
1342 {
1343         int snum;
1344         NTSTATUS status;
1345
1346         snum = lp_servicenumber(jucn->service_name);
1347         if(snum < 0) {
1348                 return False;
1349         }
1350         status = create_conn_struct(talloc_tos(), conn_out, snum,
1351                                     lp_pathname(snum), NULL, oldpath);
1352         if (!NT_STATUS_IS_OK(status)) {
1353                 return False;
1354         }
1355
1356         *pp_path_out = talloc_asprintf(*conn_out,
1357                         "%s/%s",
1358                         lp_pathname(snum),
1359                         jucn->volume_name);
1360         if (!*pp_path_out) {
1361                 vfs_ChDir(*conn_out, *oldpath);
1362                 conn_free(*conn_out);
1363                 return False;
1364         }
1365         return True;
1366 }
1367
1368 bool create_msdfs_link(const struct junction_map *jucn)
1369 {
1370         char *path = NULL;
1371         char *cwd;
1372         char *msdfs_link = NULL;
1373         connection_struct *conn;
1374         int i=0;
1375         bool insert_comma = False;
1376         bool ret = False;
1377
1378         if(!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1379                 return False;
1380         }
1381
1382         /* Form the msdfs_link contents */
1383         msdfs_link = talloc_strdup(conn, "msdfs:");
1384         if (!msdfs_link) {
1385                 goto out;
1386         }
1387         for(i=0; i<jucn->referral_count; i++) {
1388                 char *refpath = jucn->referral_list[i].alternate_path;
1389
1390                 /* Alternate paths always use Windows separators. */
1391                 trim_char(refpath, '\\', '\\');
1392                 if(*refpath == '\0') {
1393                         if (i == 0) {
1394                                 insert_comma = False;
1395                         }
1396                         continue;
1397                 }
1398                 if (i > 0 && insert_comma) {
1399                         msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1400                                         ",%s",
1401                                         refpath);
1402                 } else {
1403                         msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1404                                         "%s",
1405                                         refpath);
1406                 }
1407
1408                 if (!msdfs_link) {
1409                         goto out;
1410                 }
1411                 if (!insert_comma) {
1412                         insert_comma = True;
1413                 }
1414         }
1415
1416         DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1417                 path, msdfs_link));
1418
1419         if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1420                 if (errno == EEXIST) {
1421                         struct smb_filename *smb_fname = NULL;
1422                         NTSTATUS status;
1423
1424                         status = create_synthetic_smb_fname(talloc_tos(), path,
1425                                                             NULL, NULL,
1426                                                             &smb_fname);
1427                         if (!NT_STATUS_IS_OK(status)) {
1428                                 errno = map_errno_from_nt_status(status);
1429                                 goto out;
1430                         }
1431
1432                         if(SMB_VFS_UNLINK(conn, smb_fname)!=0) {
1433                                 TALLOC_FREE(smb_fname);
1434                                 goto out;
1435                         }
1436                         TALLOC_FREE(smb_fname);
1437                 }
1438                 if (SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1439                         DEBUG(1,("create_msdfs_link: symlink failed "
1440                                  "%s -> %s\nError: %s\n",
1441                                  path, msdfs_link, strerror(errno)));
1442                         goto out;
1443                 }
1444         }
1445
1446         ret = True;
1447
1448 out:
1449         vfs_ChDir(conn, cwd);
1450         conn_free(conn);
1451         return ret;
1452 }
1453
1454 bool remove_msdfs_link(const struct junction_map *jucn)
1455 {
1456         char *path = NULL;
1457         char *cwd;
1458         connection_struct *conn;
1459         bool ret = False;
1460         struct smb_filename *smb_fname = NULL;
1461         NTSTATUS status;
1462
1463         if (!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1464                 return false;
1465         }
1466
1467         status = create_synthetic_smb_fname(talloc_tos(), path,
1468                                             NULL, NULL,
1469                                             &smb_fname);
1470         if (!NT_STATUS_IS_OK(status)) {
1471                 errno = map_errno_from_nt_status(status);
1472                 return false;
1473         }
1474
1475         if( SMB_VFS_UNLINK(conn, smb_fname) == 0 ) {
1476                 ret = True;
1477         }
1478
1479         TALLOC_FREE(smb_fname);
1480         vfs_ChDir(conn, cwd);
1481         conn_free(conn);
1482         return ret;
1483 }
1484
1485 /*********************************************************************
1486  Return the number of DFS links at the root of this share.
1487 *********************************************************************/
1488
1489 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1490 {
1491         size_t cnt = 0;
1492         SMB_STRUCT_DIR *dirp = NULL;
1493         const char *dname = NULL;
1494         char *talloced = NULL;
1495         const char *connect_path = lp_pathname(snum);
1496         const char *msdfs_proxy = lp_msdfs_proxy(snum);
1497         connection_struct *conn;
1498         NTSTATUS status;
1499         char *cwd;
1500
1501         if(*connect_path == '\0') {
1502                 return 0;
1503         }
1504
1505         /*
1506          * Fake up a connection struct for the VFS layer.
1507          */
1508
1509         status = create_conn_struct(talloc_tos(), &conn, snum, connect_path,
1510                                     NULL, &cwd);
1511         if (!NT_STATUS_IS_OK(status)) {
1512                 DEBUG(3, ("create_conn_struct failed: %s\n",
1513                           nt_errstr(status)));
1514                 return 0;
1515         }
1516
1517         /* Count a link for the msdfs root - convention */
1518         cnt = 1;
1519
1520         /* No more links if this is an msdfs proxy. */
1521         if (*msdfs_proxy != '\0') {
1522                 goto out;
1523         }
1524
1525         /* Now enumerate all dfs links */
1526         dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1527         if(!dirp) {
1528                 goto out;
1529         }
1530
1531         while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1532                != NULL) {
1533                 if (is_msdfs_link(conn,
1534                                 dname,
1535                                 NULL)) {
1536                         cnt++;
1537                 }
1538                 TALLOC_FREE(talloced);
1539         }
1540
1541         SMB_VFS_CLOSEDIR(conn,dirp);
1542
1543 out:
1544         vfs_ChDir(conn, cwd);
1545         conn_free(conn);
1546         return cnt;
1547 }
1548
1549 /*********************************************************************
1550 *********************************************************************/
1551
1552 static int form_junctions(TALLOC_CTX *ctx,
1553                                 int snum,
1554                                 struct junction_map *jucn,
1555                                 size_t jn_remain)
1556 {
1557         size_t cnt = 0;
1558         SMB_STRUCT_DIR *dirp = NULL;
1559         const char *dname = NULL;
1560         char *talloced = NULL;
1561         const char *connect_path = lp_pathname(snum);
1562         char *service_name = lp_servicename(snum);
1563         const char *msdfs_proxy = lp_msdfs_proxy(snum);
1564         connection_struct *conn;
1565         struct referral *ref = NULL;
1566         char *cwd;
1567         NTSTATUS status;
1568
1569         if (jn_remain == 0) {
1570                 return 0;
1571         }
1572
1573         if(*connect_path == '\0') {
1574                 return 0;
1575         }
1576
1577         /*
1578          * Fake up a connection struct for the VFS layer.
1579          */
1580
1581         status = create_conn_struct(ctx, &conn, snum, connect_path, NULL,
1582                                     &cwd);
1583         if (!NT_STATUS_IS_OK(status)) {
1584                 DEBUG(3, ("create_conn_struct failed: %s\n",
1585                           nt_errstr(status)));
1586                 return 0;
1587         }
1588
1589         /* form a junction for the msdfs root - convention
1590            DO NOT REMOVE THIS: NT clients will not work with us
1591            if this is not present
1592         */
1593         jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1594         jucn[cnt].volume_name = talloc_strdup(ctx, "");
1595         if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1596                 goto out;
1597         }
1598         jucn[cnt].comment = "";
1599         jucn[cnt].referral_count = 1;
1600
1601         ref = jucn[cnt].referral_list = TALLOC_ZERO_P(ctx, struct referral);
1602         if (jucn[cnt].referral_list == NULL) {
1603                 goto out;
1604         }
1605
1606         ref->proximity = 0;
1607         ref->ttl = REFERRAL_TTL;
1608         if (*msdfs_proxy != '\0') {
1609                 ref->alternate_path = talloc_strdup(ctx,
1610                                                 msdfs_proxy);
1611         } else {
1612                 ref->alternate_path = talloc_asprintf(ctx,
1613                         "\\\\%s\\%s",
1614                         get_local_machine_name(),
1615                         service_name);
1616         }
1617
1618         if (!ref->alternate_path) {
1619                 goto out;
1620         }
1621         cnt++;
1622
1623         /* Don't enumerate if we're an msdfs proxy. */
1624         if (*msdfs_proxy != '\0') {
1625                 goto out;
1626         }
1627
1628         /* Now enumerate all dfs links */
1629         dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1630         if(!dirp) {
1631                 goto out;
1632         }
1633
1634         while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1635                != NULL) {
1636                 char *link_target = NULL;
1637                 if (cnt >= jn_remain) {
1638                         DEBUG(2, ("form_junctions: ran out of MSDFS "
1639                                 "junction slots"));
1640                         TALLOC_FREE(talloced);
1641                         goto out;
1642                 }
1643                 if (is_msdfs_link_internal(ctx,
1644                                         conn,
1645                                         dname, &link_target,
1646                                         NULL)) {
1647                         if (parse_msdfs_symlink(ctx,
1648                                         link_target,
1649                                         &jucn[cnt].referral_list,
1650                                         &jucn[cnt].referral_count)) {
1651
1652                                 jucn[cnt].service_name = talloc_strdup(ctx,
1653                                                                 service_name);
1654                                 jucn[cnt].volume_name = talloc_strdup(ctx,
1655                                                                 dname);
1656                                 if (!jucn[cnt].service_name ||
1657                                                 !jucn[cnt].volume_name) {
1658                                         TALLOC_FREE(talloced);
1659                                         goto out;
1660                                 }
1661                                 jucn[cnt].comment = "";
1662                                 cnt++;
1663                         }
1664                         TALLOC_FREE(link_target);
1665                 }
1666                 TALLOC_FREE(talloced);
1667         }
1668
1669 out:
1670
1671         if (dirp) {
1672                 SMB_VFS_CLOSEDIR(conn,dirp);
1673         }
1674
1675         vfs_ChDir(conn, cwd);
1676         conn_free(conn);
1677         return cnt;
1678 }
1679
1680 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1681 {
1682         struct junction_map *jn = NULL;
1683         int i=0;
1684         size_t jn_count = 0;
1685         int sharecount = 0;
1686
1687         *p_num_jn = 0;
1688         if(!lp_host_msdfs()) {
1689                 return NULL;
1690         }
1691
1692         /* Ensure all the usershares are loaded. */
1693         become_root();
1694         load_registry_shares();
1695         sharecount = load_usershare_shares();
1696         unbecome_root();
1697
1698         for(i=0;i < sharecount;i++) {
1699                 if(lp_msdfs_root(i)) {
1700                         jn_count += count_dfs_links(ctx, i);
1701                 }
1702         }
1703         if (jn_count == 0) {
1704                 return NULL;
1705         }
1706         jn = TALLOC_ARRAY(ctx,  struct junction_map, jn_count);
1707         if (!jn) {
1708                 return NULL;
1709         }
1710         for(i=0; i < sharecount; i++) {
1711                 if (*p_num_jn >= jn_count) {
1712                         break;
1713                 }
1714                 if(lp_msdfs_root(i)) {
1715                         *p_num_jn += form_junctions(ctx, i,
1716                                         &jn[*p_num_jn],
1717                                         jn_count - *p_num_jn);
1718                 }
1719         }
1720         return jn;
1721 }
1722
1723 /******************************************************************************
1724  Core function to resolve a dfs pathname possibly containing a wildcard.  If
1725  ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1726  detected during dfs resolution.
1727 ******************************************************************************/
1728
1729 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1730                                 connection_struct *conn,
1731                                 bool dfs_pathnames,
1732                                 const char *name_in,
1733                                 bool allow_wcards,
1734                                 char **pp_name_out,
1735                                 bool *ppath_contains_wcard)
1736 {
1737         bool path_contains_wcard;
1738         NTSTATUS status = NT_STATUS_OK;
1739
1740         if (dfs_pathnames) {
1741                 status = dfs_redirect(ctx,
1742                                         conn,
1743                                         name_in,
1744                                         allow_wcards,
1745                                         pp_name_out,
1746                                         &path_contains_wcard);
1747
1748                 if (NT_STATUS_IS_OK(status) && ppath_contains_wcard != NULL) {
1749                         *ppath_contains_wcard = path_contains_wcard;
1750                 }
1751         } else {
1752                 /*
1753                  * Cheat and just return a copy of the in ptr.
1754                  * Once srvstr_get_path() uses talloc it'll
1755                  * be a talloced ptr anyway.
1756                  */
1757                 *pp_name_out = CONST_DISCARD(char *,name_in);
1758         }
1759         return status;
1760 }