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