Merge branch 'master' of ssh://git.samba.org/data/git/samba
[sfrench/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
26 extern uint32 global_client_caps;
27
28 /**********************************************************************
29  Parse a DFS pathname of the form \hostname\service\reqpath
30  into the dfs_path structure.
31  If POSIX pathnames is true, the pathname may also be of the
32  form /hostname/service/reqpath.
33  We cope with either here.
34
35  Unfortunately, due to broken clients who might set the
36  SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
37  send a local path, we have to cope with that too....
38
39  If conn != NULL then ensure the provided service is
40  the one pointed to by the connection.
41
42  This version does everything using pointers within one copy of the
43  pathname string, talloced on the struct dfs_path pointer (which
44  must be talloced). This may be too clever to live....
45  JRA.
46 **********************************************************************/
47
48 static NTSTATUS parse_dfs_path(connection_struct *conn,
49                                 const char *pathname,
50                                 bool allow_wcards,
51                                 struct dfs_path *pdp, /* MUST BE TALLOCED */
52                                 bool *ppath_contains_wcard)
53 {
54         char *pathname_local;
55         char *p,*temp;
56         char *servicename;
57         char *eos_ptr;
58         NTSTATUS status = NT_STATUS_OK;
59         char sepchar;
60
61         ZERO_STRUCTP(pdp);
62
63         /*
64          * This is the only talloc we should need to do
65          * on the struct dfs_path. All the pointers inside
66          * it should point to offsets within this string.
67          */
68
69         pathname_local = talloc_strdup(pdp, pathname);
70         if (!pathname_local) {
71                 return NT_STATUS_NO_MEMORY;
72         }
73         /* Get a pointer to the terminating '\0' */
74         eos_ptr = &pathname_local[strlen(pathname_local)];
75         p = temp = pathname_local;
76
77         pdp->posix_path = (lp_posix_pathnames() && *pathname == '/');
78
79         sepchar = pdp->posix_path ? '/' : '\\';
80
81         if (*pathname != sepchar) {
82                 DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
83                         pathname, sepchar ));
84                 /*
85                  * Possibly client sent a local path by mistake.
86                  * Try and convert to a local path.
87                  */
88
89                 pdp->hostname = eos_ptr; /* "" */
90                 pdp->servicename = eos_ptr; /* "" */
91
92                 /* We've got no info about separators. */
93                 pdp->posix_path = lp_posix_pathnames();
94                 p = temp;
95                 DEBUG(10,("parse_dfs_path: trying to convert %s to a "
96                         "local path\n",
97                         temp));
98                 goto local_path;
99         }
100
101         /*
102          * Safe to use on talloc'ed string as it only shrinks.
103          * It also doesn't affect the eos_ptr.
104          */
105         trim_char(temp,sepchar,sepchar);
106
107         DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
108                 temp, sepchar));
109
110         /* Now tokenize. */
111         /* Parse out hostname. */
112         p = strchr_m(temp,sepchar);
113         if(p == NULL) {
114                 DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
115                         temp));
116                 /*
117                  * Possibly client sent a local path by mistake.
118                  * Try and convert to a local path.
119                  */
120
121                 pdp->hostname = eos_ptr; /* "" */
122                 pdp->servicename = eos_ptr; /* "" */
123
124                 p = temp;
125                 DEBUG(10,("parse_dfs_path: trying to convert %s "
126                         "to a local path\n",
127                         temp));
128                 goto local_path;
129         }
130         *p = '\0';
131         pdp->hostname = temp;
132
133         DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
134
135         /* Parse out servicename. */
136         servicename = p+1;
137         p = strchr_m(servicename,sepchar);
138         if (p) {
139                 *p = '\0';
140         }
141
142         /* Is this really our servicename ? */
143         if (conn && !( strequal(servicename, lp_servicename(SNUM(conn)))
144                         || (strequal(servicename, HOMES_NAME)
145                         && strequal(lp_servicename(SNUM(conn)),
146                                 get_current_username()) )) ) {
147                 DEBUG(10,("parse_dfs_path: %s is not our servicename\n",
148                         servicename));
149
150                 /*
151                  * Possibly client sent a local path by mistake.
152                  * Try and convert to a local path.
153                  */
154
155                 pdp->hostname = eos_ptr; /* "" */
156                 pdp->servicename = eos_ptr; /* "" */
157
158                 /* Repair the path - replace the sepchar's
159                    we nulled out */
160                 servicename--;
161                 *servicename = sepchar;
162                 if (p) {
163                         *p = sepchar;
164                 }
165
166                 p = temp;
167                 DEBUG(10,("parse_dfs_path: trying to convert %s "
168                         "to a local path\n",
169                         temp));
170                 goto local_path;
171         }
172
173         pdp->servicename = servicename;
174
175         DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
176
177         if(p == NULL) {
178                 /* Client sent self referral \server\share. */
179                 pdp->reqpath = eos_ptr; /* "" */
180                 return NT_STATUS_OK;
181         }
182
183         p++;
184
185   local_path:
186
187         *ppath_contains_wcard = False;
188
189         pdp->reqpath = p;
190
191         /* Rest is reqpath. */
192         if (pdp->posix_path) {
193                 status = check_path_syntax_posix(pdp->reqpath);
194         } else {
195                 if (allow_wcards) {
196                         status = check_path_syntax_wcard(pdp->reqpath,
197                                         ppath_contains_wcard);
198                 } else {
199                         status = check_path_syntax(pdp->reqpath);
200                 }
201         }
202
203         if (!NT_STATUS_IS_OK(status)) {
204                 DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
205                         p, nt_errstr(status) ));
206                 return status;
207         }
208
209         DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
210         return NT_STATUS_OK;
211 }
212
213 /********************************************************
214  Fake up a connection struct for the VFS layer.
215  Note this CHANGES CWD !!!! JRA.
216 *********************************************************/
217
218 NTSTATUS create_conn_struct(TALLOC_CTX *ctx,
219                                 connection_struct **pconn,
220                                 int snum,
221                                 const char *path,
222                                 struct auth_serversupplied_info *server_info,
223                                 char **poldcwd)
224 {
225         connection_struct *conn;
226         char *connpath;
227         char *oldcwd;
228
229         conn = TALLOC_ZERO_P(ctx, connection_struct);
230         if (conn == NULL) {
231                 return NT_STATUS_NO_MEMORY;
232         }
233
234         connpath = talloc_strdup(conn, path);
235         if (!connpath) {
236                 TALLOC_FREE(conn);
237                 return NT_STATUS_NO_MEMORY;
238         }
239         connpath = talloc_string_sub(conn,
240                                 connpath,
241                                 "%S",
242                                 lp_servicename(snum));
243         if (!connpath) {
244                 TALLOC_FREE(conn);
245                 return NT_STATUS_NO_MEMORY;
246         }
247
248         /* needed for smbd_vfs_init() */
249
250         if (!(conn->params = TALLOC_ZERO_P(conn, struct share_params))) {
251                 DEBUG(0, ("TALLOC failed\n"));
252                 TALLOC_FREE(conn);
253                 return NT_STATUS_NO_MEMORY;
254         }
255
256         conn->params->service = snum;
257
258         if (server_info != NULL) {
259                 conn->server_info = copy_serverinfo(conn, server_info);
260                 if (conn->server_info == NULL) {
261                         DEBUG(0, ("copy_serverinfo failed\n"));
262                         TALLOC_FREE(conn);
263                         return NT_STATUS_NO_MEMORY;
264                 }
265         }
266
267         set_conn_connectpath(conn, connpath);
268
269         if (!smbd_vfs_init(conn)) {
270                 NTSTATUS status = map_nt_error_from_unix(errno);
271                 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
272                 conn_free_internal(conn);
273                 return status;
274         }
275
276         /*
277          * Windows seems to insist on doing trans2getdfsreferral() calls on
278          * the IPC$ share as the anonymous user. If we try to chdir as that
279          * user we will fail.... WTF ? JRA.
280          */
281
282         oldcwd = vfs_GetWd(ctx, conn);
283         if (oldcwd == NULL) {
284                 NTSTATUS status = map_nt_error_from_unix(errno);
285                 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
286                 conn_free_internal(conn);
287                 return status;
288         }
289
290         if (vfs_ChDir(conn,conn->connectpath) != 0) {
291                 NTSTATUS status = map_nt_error_from_unix(errno);
292                 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
293                         "Error was %s\n",
294                         conn->connectpath, strerror(errno) ));
295                 conn_free_internal(conn);
296                 return status;
297         }
298
299         *pconn = conn;
300         *poldcwd = oldcwd;
301
302         return NT_STATUS_OK;
303 }
304
305 /**********************************************************************
306  Parse the contents of a symlink to verify if it is an msdfs referral
307  A valid referral is of the form:
308
309  msdfs:server1\share1,server2\share2
310  msdfs:server1\share1\pathname,server2\share2\pathname
311  msdfs:server1/share1,server2/share2
312  msdfs:server1/share1/pathname,server2/share2/pathname.
313
314  Note that the alternate paths returned here must be of the canonicalized
315  form:
316
317  \server\share or
318  \server\share\path\to\file,
319
320  even in posix path mode. This is because we have no knowledge if the
321  server we're referring to understands posix paths.
322  **********************************************************************/
323
324 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
325                                 const char *target,
326                                 struct referral **preflist,
327                                 int *refcount)
328 {
329         char *temp = NULL;
330         char *prot;
331         char **alt_path = NULL;
332         int count = 0, i;
333         struct referral *reflist;
334         char *saveptr;
335
336         temp = talloc_strdup(ctx, target);
337         if (!temp) {
338                 return False;
339         }
340         prot = strtok_r(temp, ":", &saveptr);
341         if (!prot) {
342                 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
343                 return False;
344         }
345
346         alt_path = TALLOC_ARRAY(ctx, char *, MAX_REFERRAL_COUNT);
347         if (!alt_path) {
348                 return False;
349         }
350
351         /* parse out the alternate paths */
352         while((count<MAX_REFERRAL_COUNT) &&
353               ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
354                 count++;
355         }
356
357         DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
358
359         if (count) {
360                 reflist = *preflist = TALLOC_ZERO_ARRAY(ctx,
361                                 struct referral, count);
362                 if(reflist == NULL) {
363                         TALLOC_FREE(alt_path);
364                         return False;
365                 }
366         } else {
367                 reflist = *preflist = NULL;
368         }
369
370         for(i=0;i<count;i++) {
371                 char *p;
372
373                 /* Canonicalize link target.
374                  * Replace all /'s in the path by a \ */
375                 string_replace(alt_path[i], '/', '\\');
376
377                 /* Remove leading '\\'s */
378                 p = alt_path[i];
379                 while (*p && (*p == '\\')) {
380                         p++;
381                 }
382
383                 reflist[i].alternate_path = talloc_asprintf(ctx,
384                                 "\\%s",
385                                 p);
386                 if (!reflist[i].alternate_path) {
387                         return False;
388                 }
389
390                 reflist[i].proximity = 0;
391                 reflist[i].ttl = REFERRAL_TTL;
392                 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
393                                         reflist[i].alternate_path));
394         }
395
396         *refcount = count;
397
398         TALLOC_FREE(alt_path);
399         return True;
400 }
401
402 /**********************************************************************
403  Returns true if the unix path is a valid msdfs symlink and also
404  returns the target string from inside the link.
405 **********************************************************************/
406
407 static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
408                         connection_struct *conn,
409                         const char *path,
410                         char **pp_link_target,
411                         SMB_STRUCT_STAT *sbufp)
412 {
413         SMB_STRUCT_STAT st;
414         int referral_len = 0;
415         char link_target_buf[7];
416         size_t bufsize = 0;
417         char *link_target = NULL;
418
419         if (pp_link_target) {
420                 bufsize = 1024;
421                 link_target = TALLOC_ARRAY(ctx, char, bufsize);
422                 if (!link_target) {
423                         return False;
424                 }
425                 *pp_link_target = link_target;
426         } else {
427                 bufsize = sizeof(link_target_buf);
428                 link_target = link_target_buf;
429         }
430
431         if (sbufp == NULL) {
432                 sbufp = &st;
433         }
434
435         if (SMB_VFS_LSTAT(conn, path, sbufp) != 0) {
436                 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
437                         path));
438                 goto err;
439         }
440
441         if (!S_ISLNK(sbufp->st_mode)) {
442                 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
443                                         path));
444                 goto err;
445         }
446
447         referral_len = SMB_VFS_READLINK(conn, path, link_target, bufsize - 1);
448         if (referral_len == -1) {
449                 DEBUG(0,("is_msdfs_link_read_target: Error reading "
450                         "msdfs link %s: %s\n",
451                         path, strerror(errno)));
452                 goto err;
453         }
454         link_target[referral_len] = '\0';
455
456         DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path,
457                                 link_target));
458
459         if (!strnequal(link_target, "msdfs:", 6)) {
460                 goto err;
461         }
462         return True;
463
464   err:
465
466         if (link_target != link_target_buf) {
467                 TALLOC_FREE(link_target);
468         }
469         return False;
470 }
471
472 /**********************************************************************
473  Returns true if the unix path is a valid msdfs symlink.
474 **********************************************************************/
475
476 bool is_msdfs_link(connection_struct *conn,
477                 const char *path,
478                 SMB_STRUCT_STAT *sbufp)
479 {
480         return is_msdfs_link_internal(talloc_tos(),
481                                         conn,
482                                         path,
483                                         NULL,
484                                         sbufp);
485 }
486
487 /*****************************************************************
488  Used by other functions to decide if a dfs path is remote,
489  and to get the list of referred locations for that remote path.
490
491  search_flag: For findfirsts, dfs links themselves are not
492  redirected, but paths beyond the links are. For normal smb calls,
493  even dfs links need to be redirected.
494
495  consumedcntp: how much of the dfs path is being redirected. the client
496  should try the remaining path on the redirected server.
497
498  If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
499  link redirect are in targetpath.
500 *****************************************************************/
501
502 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
503                 connection_struct *conn,
504                 const char *dfspath, /* Incoming complete dfs path */
505                 const struct dfs_path *pdp, /* Parsed out
506                                                server+share+extrapath. */
507                 bool search_flag, /* Called from a findfirst ? */
508                 int *consumedcntp,
509                 char **pp_targetpath)
510 {
511         char *p = NULL;
512         char *q = NULL;
513         SMB_STRUCT_STAT sbuf;
514         NTSTATUS status;
515         char *localpath = NULL;
516         char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
517                                   components). */
518
519         DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
520                 conn->connectpath, pdp->reqpath));
521
522         /*
523          * Note the unix path conversion here we're doing we can
524          * throw away. We're looking for a symlink for a dfs
525          * resolution, if we don't find it we'll do another
526          * unix_convert later in the codepath.
527          * If we needed to remember what we'd resolved in
528          * dp->reqpath (as the original code did) we'd
529          * copy (localhost, dp->reqpath) on any code
530          * path below that returns True - but I don't
531          * think this is needed. JRA.
532          */
533
534         status = unix_convert(ctx, conn, pdp->reqpath, search_flag, &localpath,
535                         NULL, &sbuf);
536         if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status,
537                                         NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
538                 return status;
539         }
540
541         /* Optimization - check if we can redirect the whole path. */
542
543         if (is_msdfs_link_internal(ctx, conn, localpath, pp_targetpath, NULL)) {
544                 if (search_flag) {
545                         DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
546                                  "for dfs link %s.\n", dfspath));
547                         return NT_STATUS_OK;
548                 }
549
550                 DEBUG(6,("dfs_path_lookup: %s resolves to a "
551                         "valid dfs link %s.\n", dfspath,
552                         pp_targetpath ? *pp_targetpath : ""));
553
554                 if (consumedcntp) {
555                         *consumedcntp = strlen(dfspath);
556                 }
557                 return NT_STATUS_PATH_NOT_COVERED;
558         }
559
560         /* Prepare to test only for '/' components in the given path,
561          * so if a Windows path replace all '\\' characters with '/'.
562          * For a POSIX DFS path we know all separators are already '/'. */
563
564         canon_dfspath = talloc_strdup(ctx, dfspath);
565         if (!canon_dfspath) {
566                 return NT_STATUS_NO_MEMORY;
567         }
568         if (!pdp->posix_path) {
569                 string_replace(canon_dfspath, '\\', '/');
570         }
571
572         /*
573          * localpath comes out of unix_convert, so it has
574          * no trailing backslash. Make sure that canon_dfspath hasn't either.
575          * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
576          */
577
578         trim_char(canon_dfspath,0,'/');
579
580         /*
581          * Redirect if any component in the path is a link.
582          * We do this by walking backwards through the
583          * local path, chopping off the last component
584          * in both the local path and the canonicalized
585          * DFS path. If we hit a DFS link then we're done.
586          */
587
588         p = strrchr_m(localpath, '/');
589         if (consumedcntp) {
590                 q = strrchr_m(canon_dfspath, '/');
591         }
592
593         while (p) {
594                 *p = '\0';
595                 if (q) {
596                         *q = '\0';
597                 }
598
599                 if (is_msdfs_link_internal(ctx, conn,
600                                         localpath, pp_targetpath, NULL)) {
601                         DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
602                                 "parent %s is dfs link\n", dfspath, localpath));
603
604                         if (consumedcntp) {
605                                 *consumedcntp = strlen(canon_dfspath);
606                                 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
607                                         "(%d)\n",
608                                         canon_dfspath,
609                                         *consumedcntp));
610                         }
611
612                         return NT_STATUS_PATH_NOT_COVERED;
613                 }
614
615                 /* Step back on the filesystem. */
616                 p = strrchr_m(localpath, '/');
617
618                 if (consumedcntp) {
619                         /* And in the canonicalized dfs path. */
620                         q = strrchr_m(canon_dfspath, '/');
621                 }
622         }
623
624         return NT_STATUS_OK;
625 }
626
627 /*****************************************************************
628  Decides if a dfs pathname should be redirected or not.
629  If not, the pathname is converted to a tcon-relative local unix path
630
631  search_wcard_flag: this flag performs 2 functions both related
632  to searches.  See resolve_dfs_path() and parse_dfs_path_XX()
633  for details.
634
635  This function can return NT_STATUS_OK, meaning use the returned path as-is
636  (mapped into a local path).
637  or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
638  any other NT_STATUS error which is a genuine error to be
639  returned to the client.
640 *****************************************************************/
641
642 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
643                         connection_struct *conn,
644                         const char *path_in,
645                         bool search_wcard_flag,
646                         char **pp_path_out,
647                         bool *ppath_contains_wcard)
648 {
649         NTSTATUS status;
650         struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
651
652         if (!pdp) {
653                 return NT_STATUS_NO_MEMORY;
654         }
655
656         status = parse_dfs_path(conn, path_in, search_wcard_flag, pdp,
657                         ppath_contains_wcard);
658         if (!NT_STATUS_IS_OK(status)) {
659                 TALLOC_FREE(pdp);
660                 return status;
661         }
662
663         if (pdp->reqpath[0] == '\0') {
664                 TALLOC_FREE(pdp);
665                 *pp_path_out = talloc_strdup(ctx, "");
666                 if (!*pp_path_out) {
667                         return NT_STATUS_NO_MEMORY;
668                 }
669                 DEBUG(5,("dfs_redirect: self-referral.\n"));
670                 return NT_STATUS_OK;
671         }
672
673         /* If dfs pathname for a non-dfs share, convert to tcon-relative
674            path and return OK */
675
676         if (!lp_msdfs_root(SNUM(conn))) {
677                 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
678                 TALLOC_FREE(pdp);
679                 if (!*pp_path_out) {
680                         return NT_STATUS_NO_MEMORY;
681                 }
682                 return NT_STATUS_OK;
683         }
684
685         /* If it looked like a local path (zero hostname/servicename)
686          * just treat as a tcon-relative path. */
687
688         if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
689                 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
690                 TALLOC_FREE(pdp);
691                 if (!*pp_path_out) {
692                         return NT_STATUS_NO_MEMORY;
693                 }
694                 return NT_STATUS_OK;
695         }
696
697         if (!( strequal(pdp->servicename, lp_servicename(SNUM(conn)))
698                         || (strequal(pdp->servicename, HOMES_NAME)
699                         && strequal(lp_servicename(SNUM(conn)),
700                                 conn->server_info->sanitized_username) )) ) {
701
702                 /* The given sharename doesn't match this connection. */
703                 TALLOC_FREE(pdp);
704
705                 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
706         }
707
708         status = dfs_path_lookup(ctx, conn, path_in, pdp,
709                         search_wcard_flag, NULL, NULL);
710         if (!NT_STATUS_IS_OK(status)) {
711                 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
712                         DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
713                 } else {
714                         DEBUG(10,("dfs_redirect: dfs_path_lookup "
715                                 "failed for %s with %s\n",
716                                 path_in, nt_errstr(status) ));
717                 }
718                 return status;
719         }
720
721         DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
722
723         /* Form non-dfs tcon-relative path */
724         *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
725         TALLOC_FREE(pdp);
726         if (!*pp_path_out) {
727                 return NT_STATUS_NO_MEMORY;
728         }
729
730         DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
731                                 path_in,
732                                 *pp_path_out));
733
734         return NT_STATUS_OK;
735 }
736
737 /**********************************************************************
738  Return a self referral.
739 **********************************************************************/
740
741 static NTSTATUS self_ref(TALLOC_CTX *ctx,
742                         const char *dfs_path,
743                         struct junction_map *jucn,
744                         int *consumedcntp,
745                         bool *self_referralp)
746 {
747         struct referral *ref;
748
749         *self_referralp = True;
750
751         jucn->referral_count = 1;
752         if((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
753                 return NT_STATUS_NO_MEMORY;
754         }
755
756         ref->alternate_path = talloc_strdup(ctx, dfs_path);
757         if (!ref->alternate_path) {
758                 return NT_STATUS_NO_MEMORY;
759         }
760         ref->proximity = 0;
761         ref->ttl = REFERRAL_TTL;
762         jucn->referral_list = ref;
763         *consumedcntp = strlen(dfs_path);
764         return NT_STATUS_OK;
765 }
766
767 /**********************************************************************
768  Gets valid referrals for a dfs path and fills up the
769  junction_map structure.
770 **********************************************************************/
771
772 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
773                         const char *dfs_path,
774                         struct junction_map *jucn,
775                         int *consumedcntp,
776                         bool *self_referralp)
777 {
778         struct connection_struct *conn;
779         char *targetpath = NULL;
780         int snum;
781         NTSTATUS status = NT_STATUS_NOT_FOUND;
782         bool dummy;
783         struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
784         char *oldpath;
785
786         if (!pdp) {
787                 return NT_STATUS_NO_MEMORY;
788         }
789
790         *self_referralp = False;
791
792         status = parse_dfs_path(NULL, dfs_path, False, pdp, &dummy);
793         if (!NT_STATUS_IS_OK(status)) {
794                 return status;
795         }
796
797         jucn->service_name = talloc_strdup(ctx, pdp->servicename);
798         jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
799         if (!jucn->service_name || !jucn->volume_name) {
800                 TALLOC_FREE(pdp);
801                 return NT_STATUS_NO_MEMORY;
802         }
803
804         /* Verify the share is a dfs root */
805         snum = lp_servicenumber(jucn->service_name);
806         if(snum < 0) {
807                 fstring service_name;
808                 fstrcpy(service_name, jucn->service_name);
809                 if ((snum = find_service(service_name)) < 0) {
810                         return NT_STATUS_NOT_FOUND;
811                 }
812                 TALLOC_FREE(jucn->service_name);
813                 jucn->service_name = talloc_strdup(ctx, service_name);
814                 if (!jucn->service_name) {
815                         TALLOC_FREE(pdp);
816                         return NT_STATUS_NO_MEMORY;
817                 }
818         }
819
820         if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(snum) == '\0')) {
821                 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
822                         "a dfs root.\n",
823                         pdp->servicename, dfs_path));
824                 TALLOC_FREE(pdp);
825                 return NT_STATUS_NOT_FOUND;
826         }
827
828         /*
829          * Self referrals are tested with a anonymous IPC connection and
830          * a GET_DFS_REFERRAL call to \\server\share. (which means
831          * dp.reqpath[0] points to an empty string). create_conn_struct cd's
832          * into the directory and will fail if it cannot (as the anonymous
833          * user). Cope with this.
834          */
835
836         if (pdp->reqpath[0] == '\0') {
837                 char *tmp;
838                 struct referral *ref;
839
840                 if (*lp_msdfs_proxy(snum) == '\0') {
841                         TALLOC_FREE(pdp);
842                         return self_ref(ctx,
843                                         dfs_path,
844                                         jucn,
845                                         consumedcntp,
846                                         self_referralp);
847                 }
848
849                 /*
850                  * It's an msdfs proxy share. Redirect to
851                  * the configured target share.
852                  */
853
854                 jucn->referral_count = 1;
855                 if ((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
856                         TALLOC_FREE(pdp);
857                         return NT_STATUS_NO_MEMORY;
858                 }
859
860                 if (!(tmp = talloc_strdup(ctx, lp_msdfs_proxy(snum)))) {
861                         TALLOC_FREE(pdp);
862                         return NT_STATUS_NO_MEMORY;
863                 }
864
865                 trim_string(tmp, "\\", 0);
866
867                 ref->alternate_path = talloc_asprintf(ctx, "\\%s", tmp);
868                 TALLOC_FREE(tmp);
869
870                 if (!ref->alternate_path) {
871                         TALLOC_FREE(pdp);
872                         return NT_STATUS_NO_MEMORY;
873                 }
874
875                 if (pdp->reqpath[0] != '\0') {
876                         ref->alternate_path = talloc_asprintf_append(
877                                         ref->alternate_path,
878                                         "%s",
879                                         pdp->reqpath);
880                         if (!ref->alternate_path) {
881                                 TALLOC_FREE(pdp);
882                                 return NT_STATUS_NO_MEMORY;
883                         }
884                 }
885                 ref->proximity = 0;
886                 ref->ttl = REFERRAL_TTL;
887                 jucn->referral_list = ref;
888                 *consumedcntp = strlen(dfs_path);
889                 TALLOC_FREE(pdp);
890                 return NT_STATUS_OK;
891         }
892
893         status = create_conn_struct(ctx, &conn, snum, lp_pathname(snum),
894                                     NULL, &oldpath);
895         if (!NT_STATUS_IS_OK(status)) {
896                 TALLOC_FREE(pdp);
897                 return status;
898         }
899
900         /* If this is a DFS path dfs_lookup should return
901          * NT_STATUS_PATH_NOT_COVERED. */
902
903         status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
904                         False, consumedcntp, &targetpath);
905
906         if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
907                 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
908                         dfs_path));
909                 vfs_ChDir(conn, oldpath);
910                 conn_free_internal(conn);
911                 TALLOC_FREE(pdp);
912                 return status;
913         }
914
915         /* We know this is a valid dfs link. Parse the targetpath. */
916         if (!parse_msdfs_symlink(ctx, targetpath,
917                                 &jucn->referral_list,
918                                 &jucn->referral_count)) {
919                 DEBUG(3,("get_referred_path: failed to parse symlink "
920                         "target %s\n", targetpath ));
921                 vfs_ChDir(conn, oldpath);
922                 conn_free_internal(conn);
923                 TALLOC_FREE(pdp);
924                 return NT_STATUS_NOT_FOUND;
925         }
926
927         vfs_ChDir(conn, oldpath);
928         conn_free_internal(conn);
929         TALLOC_FREE(pdp);
930         return NT_STATUS_OK;
931 }
932
933 static int setup_ver2_dfs_referral(const char *pathname,
934                                 char **ppdata,
935                                 struct junction_map *junction,
936                                 bool self_referral)
937 {
938         char* pdata = *ppdata;
939
940         smb_ucs2_t *uni_requestedpath = NULL;
941         int uni_reqpathoffset1,uni_reqpathoffset2;
942         int uni_curroffset;
943         int requestedpathlen=0;
944         int offset;
945         int reply_size = 0;
946         int i=0;
947
948         DEBUG(10,("Setting up version2 referral\nRequested path:\n"));
949
950         requestedpathlen = rpcstr_push_talloc(talloc_tos(),
951                                         &uni_requestedpath, pathname);
952         if (uni_requestedpath == NULL || requestedpathlen == 0) {
953                 return -1;
954         }
955
956         if (DEBUGLVL(10)) {
957                 dump_data(0, (unsigned char *)uni_requestedpath,
958                         requestedpathlen);
959         }
960
961         DEBUG(10,("ref count = %u\n",junction->referral_count));
962
963         uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
964                         VERSION2_REFERRAL_SIZE * junction->referral_count;
965
966         uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen;
967
968         uni_curroffset = uni_reqpathoffset2 + requestedpathlen;
969
970         reply_size = REFERRAL_HEADER_SIZE +
971                         VERSION2_REFERRAL_SIZE*junction->referral_count +
972                         2 * requestedpathlen;
973         DEBUG(10,("reply_size: %u\n",reply_size));
974
975         /* add up the unicode lengths of all the referral paths */
976         for(i=0;i<junction->referral_count;i++) {
977                 DEBUG(10,("referral %u : %s\n",
978                         i,
979                         junction->referral_list[i].alternate_path));
980                 reply_size +=
981                         (strlen(junction->referral_list[i].alternate_path)+1)*2;
982         }
983
984         DEBUG(10,("reply_size = %u\n",reply_size));
985         /* add the unexplained 0x16 bytes */
986         reply_size += 0x16;
987
988         pdata = (char *)SMB_REALLOC(pdata,reply_size);
989         if(pdata == NULL) {
990                 DEBUG(0,("Realloc failed!\n"));
991                 return -1;
992         }
993         *ppdata = pdata;
994
995         /* copy in the dfs requested paths.. required for offset calculations */
996         memcpy(pdata+uni_reqpathoffset1,uni_requestedpath,requestedpathlen);
997         memcpy(pdata+uni_reqpathoffset2,uni_requestedpath,requestedpathlen);
998
999         /* create the header */
1000         SSVAL(pdata,0,requestedpathlen - 2); /* UCS2 of path consumed minus
1001                                                 2 byte null */
1002         /* number of referral in this pkt */
1003         SSVAL(pdata,2,junction->referral_count);
1004         if(self_referral) {
1005                 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
1006         } else {
1007                 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
1008         }
1009
1010         offset = 8;
1011         /* add the referral elements */
1012         for(i=0;i<junction->referral_count;i++) {
1013                 struct referral* ref = &junction->referral_list[i];
1014                 int unilen;
1015
1016                 SSVAL(pdata,offset,2); /* version 2 */
1017                 SSVAL(pdata,offset+2,VERSION2_REFERRAL_SIZE);
1018                 if(self_referral) {
1019                         SSVAL(pdata,offset+4,1);
1020                 } else {
1021                         SSVAL(pdata,offset+4,0);
1022                 }
1023
1024                 /* ref_flags :use path_consumed bytes? */
1025                 SSVAL(pdata,offset+6,0);
1026                 SIVAL(pdata,offset+8,ref->proximity);
1027                 SIVAL(pdata,offset+12,ref->ttl);
1028
1029                 SSVAL(pdata,offset+16,uni_reqpathoffset1-offset);
1030                 SSVAL(pdata,offset+18,uni_reqpathoffset2-offset);
1031                 /* copy referred path into current offset */
1032                 unilen = rpcstr_push(pdata+uni_curroffset,
1033                                         ref->alternate_path,
1034                                         reply_size - uni_curroffset,
1035                                         STR_UNICODE);
1036
1037                 SSVAL(pdata,offset+20,uni_curroffset-offset);
1038
1039                 uni_curroffset += unilen;
1040                 offset += VERSION2_REFERRAL_SIZE;
1041         }
1042         /* add in the unexplained 22 (0x16) bytes at the end */
1043         memset(pdata+uni_curroffset,'\0',0x16);
1044         return reply_size;
1045 }
1046
1047 static int setup_ver3_dfs_referral(const char *pathname,
1048                                 char **ppdata,
1049                                 struct junction_map *junction,
1050                                 bool self_referral)
1051 {
1052         char *pdata = *ppdata;
1053
1054         smb_ucs2_t *uni_reqpath = NULL;
1055         int uni_reqpathoffset1, uni_reqpathoffset2;
1056         int uni_curroffset;
1057         int reply_size = 0;
1058
1059         int reqpathlen = 0;
1060         int offset,i=0;
1061
1062         DEBUG(10,("setting up version3 referral\n"));
1063
1064         reqpathlen = rpcstr_push_talloc(talloc_tos(), &uni_reqpath, pathname);
1065         if (uni_reqpath == NULL || reqpathlen == 0) {
1066                 return -1;
1067         }
1068
1069         if (DEBUGLVL(10)) {
1070                 dump_data(0, (unsigned char *)uni_reqpath,
1071                         reqpathlen);
1072         }
1073
1074         uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
1075                         VERSION3_REFERRAL_SIZE * junction->referral_count;
1076         uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen;
1077         reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen;
1078
1079         for(i=0;i<junction->referral_count;i++) {
1080                 DEBUG(10,("referral %u : %s\n",
1081                         i,
1082                         junction->referral_list[i].alternate_path));
1083                 reply_size +=
1084                         (strlen(junction->referral_list[i].alternate_path)+1)*2;
1085         }
1086
1087         pdata = (char *)SMB_REALLOC(pdata,reply_size);
1088         if(pdata == NULL) {
1089                 DEBUG(0,("version3 referral setup:"
1090                         "malloc failed for Realloc!\n"));
1091                 return -1;
1092         }
1093         *ppdata = pdata;
1094
1095         /* create the header */
1096         SSVAL(pdata,0,reqpathlen - 2); /* UCS2 of path consumed minus
1097                                           2 byte null */
1098         SSVAL(pdata,2,junction->referral_count); /* number of referral */
1099         if(self_referral) {
1100                 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
1101         } else {
1102                 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
1103         }
1104
1105         /* copy in the reqpaths */
1106         memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen);
1107         memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen);
1108
1109         offset = 8;
1110         for(i=0;i<junction->referral_count;i++) {
1111                 struct referral* ref = &(junction->referral_list[i]);
1112                 int unilen;
1113
1114                 SSVAL(pdata,offset,3); /* version 3 */
1115                 SSVAL(pdata,offset+2,VERSION3_REFERRAL_SIZE);
1116                 if(self_referral) {
1117                         SSVAL(pdata,offset+4,1);
1118                 } else {
1119                         SSVAL(pdata,offset+4,0);
1120                 }
1121
1122                 /* ref_flags :use path_consumed bytes? */
1123                 SSVAL(pdata,offset+6,0);
1124                 SIVAL(pdata,offset+8,ref->ttl);
1125
1126                 SSVAL(pdata,offset+12,uni_reqpathoffset1-offset);
1127                 SSVAL(pdata,offset+14,uni_reqpathoffset2-offset);
1128                 /* copy referred path into current offset */
1129                 unilen = rpcstr_push(pdata+uni_curroffset,ref->alternate_path,
1130                                         reply_size - uni_curroffset,
1131                                         STR_UNICODE | STR_TERMINATE);
1132                 SSVAL(pdata,offset+16,uni_curroffset-offset);
1133                 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
1134                 memset(pdata+offset+18,'\0',16);
1135
1136                 uni_curroffset += unilen;
1137                 offset += VERSION3_REFERRAL_SIZE;
1138         }
1139         return reply_size;
1140 }
1141
1142 /******************************************************************
1143  Set up the DFS referral for the dfs pathname. This call returns
1144  the amount of the path covered by this server, and where the
1145  client should be redirected to. This is the meat of the
1146  TRANS2_GET_DFS_REFERRAL call.
1147 ******************************************************************/
1148
1149 int setup_dfs_referral(connection_struct *orig_conn,
1150                         const char *dfs_path,
1151                         int max_referral_level,
1152                         char **ppdata, NTSTATUS *pstatus)
1153 {
1154         struct junction_map *junction = NULL;
1155         int consumedcnt = 0;
1156         bool self_referral = False;
1157         int reply_size = 0;
1158         char *pathnamep = NULL;
1159         char *local_dfs_path = NULL;
1160         TALLOC_CTX *ctx;
1161
1162         if (!(ctx=talloc_init("setup_dfs_referral"))) {
1163                 *pstatus = NT_STATUS_NO_MEMORY;
1164                 return -1;
1165         }
1166
1167         /* get the junction entry */
1168         if (!dfs_path) {
1169                 talloc_destroy(ctx);
1170                 *pstatus = NT_STATUS_NOT_FOUND;
1171                 return -1;
1172         }
1173
1174         /*
1175          * Trim pathname sent by client so it begins with only one backslash.
1176          * Two backslashes confuse some dfs clients
1177          */
1178
1179         local_dfs_path = talloc_strdup(ctx,dfs_path);
1180         if (!local_dfs_path) {
1181                 *pstatus = NT_STATUS_NO_MEMORY;
1182                 talloc_destroy(ctx);
1183                 return -1;
1184         }
1185         pathnamep = local_dfs_path;
1186         while (IS_DIRECTORY_SEP(pathnamep[0]) &&
1187                         IS_DIRECTORY_SEP(pathnamep[1])) {
1188                 pathnamep++;
1189         }
1190
1191         junction = TALLOC_ZERO_P(ctx, struct junction_map);
1192         if (!junction) {
1193                 *pstatus = NT_STATUS_NO_MEMORY;
1194                 talloc_destroy(ctx);
1195                 return -1;
1196         }
1197
1198         /* The following call can change cwd. */
1199         *pstatus = get_referred_path(ctx, pathnamep, junction,
1200                         &consumedcnt, &self_referral);
1201         if (!NT_STATUS_IS_OK(*pstatus)) {
1202                 vfs_ChDir(orig_conn,orig_conn->connectpath);
1203                 talloc_destroy(ctx);
1204                 return -1;
1205         }
1206         vfs_ChDir(orig_conn,orig_conn->connectpath);
1207
1208         if (!self_referral) {
1209                 pathnamep[consumedcnt] = '\0';
1210
1211                 if( DEBUGLVL( 3 ) ) {
1212                         int i=0;
1213                         dbgtext("setup_dfs_referral: Path %s to "
1214                                 "alternate path(s):",
1215                                 pathnamep);
1216                         for(i=0;i<junction->referral_count;i++)
1217                                 dbgtext(" %s",
1218                                 junction->referral_list[i].alternate_path);
1219                         dbgtext(".\n");
1220                 }
1221         }
1222
1223         /* create the referral depeding on version */
1224         DEBUG(10,("max_referral_level :%d\n",max_referral_level));
1225
1226         if (max_referral_level < 2) {
1227                 max_referral_level = 2;
1228         }
1229         if (max_referral_level > 3) {
1230                 max_referral_level = 3;
1231         }
1232
1233         switch(max_referral_level) {
1234         case 2:
1235                 reply_size = setup_ver2_dfs_referral(pathnamep,
1236                                         ppdata, junction,
1237                                         self_referral);
1238                 break;
1239         case 3:
1240                 reply_size = setup_ver3_dfs_referral(pathnamep, ppdata,
1241                                         junction, self_referral);
1242                 break;
1243         default:
1244                 DEBUG(0,("setup_dfs_referral: Invalid dfs referral "
1245                         "version: %d\n",
1246                         max_referral_level));
1247                 talloc_destroy(ctx);
1248                 *pstatus = NT_STATUS_INVALID_LEVEL;
1249                 return -1;
1250         }
1251
1252         if (DEBUGLVL(10)) {
1253                 DEBUGADD(0,("DFS Referral pdata:\n"));
1254                 dump_data(0,(uint8 *)*ppdata,reply_size);
1255         }
1256
1257         talloc_destroy(ctx);
1258         *pstatus = NT_STATUS_OK;
1259         return reply_size;
1260 }
1261
1262 /**********************************************************************
1263  The following functions are called by the NETDFS RPC pipe functions
1264  **********************************************************************/
1265
1266 /*********************************************************************
1267  Creates a junction structure from a DFS pathname
1268 **********************************************************************/
1269
1270 bool create_junction(TALLOC_CTX *ctx,
1271                 const char *dfs_path,
1272                 struct junction_map *jucn)
1273 {
1274         int snum;
1275         bool dummy;
1276         struct dfs_path *pdp = TALLOC_P(ctx,struct dfs_path);
1277         NTSTATUS status;
1278
1279         if (!pdp) {
1280                 return False;
1281         }
1282         status = parse_dfs_path(NULL, dfs_path, False, pdp, &dummy);
1283         if (!NT_STATUS_IS_OK(status)) {
1284                 return False;
1285         }
1286
1287         /* check if path is dfs : validate first token */
1288         if (!is_myname_or_ipaddr(pdp->hostname)) {
1289                 DEBUG(4,("create_junction: Invalid hostname %s "
1290                         "in dfs path %s\n",
1291                         pdp->hostname, dfs_path));
1292                 TALLOC_FREE(pdp);
1293                 return False;
1294         }
1295
1296         /* Check for a non-DFS share */
1297         snum = lp_servicenumber(pdp->servicename);
1298
1299         if(snum < 0 || !lp_msdfs_root(snum)) {
1300                 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1301                         pdp->servicename));
1302                 TALLOC_FREE(pdp);
1303                 return False;
1304         }
1305
1306         jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1307         jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1308         jucn->comment = talloc_strdup(ctx, lp_comment(snum));
1309
1310         TALLOC_FREE(pdp);
1311         if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1312                 return False;
1313         }
1314         return True;
1315 }
1316
1317 /**********************************************************************
1318  Forms a valid Unix pathname from the junction
1319  **********************************************************************/
1320
1321 static bool junction_to_local_path(const struct junction_map *jucn,
1322                                    char **pp_path_out,
1323                                    connection_struct **conn_out,
1324                                    char **oldpath)
1325 {
1326         int snum;
1327         NTSTATUS status;
1328
1329         snum = lp_servicenumber(jucn->service_name);
1330         if(snum < 0) {
1331                 return False;
1332         }
1333         status = create_conn_struct(talloc_tos(), conn_out, snum,
1334                                     lp_pathname(snum), NULL, oldpath);
1335         if (!NT_STATUS_IS_OK(status)) {
1336                 return False;
1337         }
1338
1339         *pp_path_out = talloc_asprintf(*conn_out,
1340                         "%s/%s",
1341                         lp_pathname(snum),
1342                         jucn->volume_name);
1343         if (!*pp_path_out) {
1344                 vfs_ChDir(*conn_out, *oldpath);
1345                 conn_free_internal(*conn_out);
1346                 return False;
1347         }
1348         return True;
1349 }
1350
1351 bool create_msdfs_link(const struct junction_map *jucn)
1352 {
1353         char *path = NULL;
1354         char *cwd;
1355         char *msdfs_link = NULL;
1356         connection_struct *conn;
1357         int i=0;
1358         bool insert_comma = False;
1359         bool ret = False;
1360
1361         if(!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1362                 return False;
1363         }
1364
1365         /* Form the msdfs_link contents */
1366         msdfs_link = talloc_strdup(conn, "msdfs:");
1367         if (!msdfs_link) {
1368                 goto out;
1369         }
1370         for(i=0; i<jucn->referral_count; i++) {
1371                 char *refpath = jucn->referral_list[i].alternate_path;
1372
1373                 /* Alternate paths always use Windows separators. */
1374                 trim_char(refpath, '\\', '\\');
1375                 if(*refpath == '\0') {
1376                         if (i == 0) {
1377                                 insert_comma = False;
1378                         }
1379                         continue;
1380                 }
1381                 if (i > 0 && insert_comma) {
1382                         msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1383                                         ",%s",
1384                                         refpath);
1385                 } else {
1386                         msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1387                                         "%s",
1388                                         refpath);
1389                 }
1390
1391                 if (!msdfs_link) {
1392                         goto out;
1393                 }
1394                 if (!insert_comma) {
1395                         insert_comma = True;
1396                 }
1397         }
1398
1399         DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1400                 path, msdfs_link));
1401
1402         if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1403                 if (errno == EEXIST) {
1404                         if(SMB_VFS_UNLINK(conn,path)!=0) {
1405                                 goto out;
1406                         }
1407                 }
1408                 if (SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1409                         DEBUG(1,("create_msdfs_link: symlink failed "
1410                                  "%s -> %s\nError: %s\n",
1411                                  path, msdfs_link, strerror(errno)));
1412                         goto out;
1413                 }
1414         }
1415
1416         ret = True;
1417
1418 out:
1419         vfs_ChDir(conn, cwd);
1420         conn_free_internal(conn);
1421         return ret;
1422 }
1423
1424 bool remove_msdfs_link(const struct junction_map *jucn)
1425 {
1426         char *path = NULL;
1427         char *cwd;
1428         connection_struct *conn;
1429         bool ret = False;
1430
1431         if (!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1432                 return false;
1433         }
1434
1435         if( SMB_VFS_UNLINK(conn, path) == 0 ) {
1436                 ret = True;
1437         }
1438
1439         vfs_ChDir(conn, cwd);
1440         conn_free_internal(conn);
1441         return ret;
1442 }
1443
1444 /*********************************************************************
1445  Return the number of DFS links at the root of this share.
1446 *********************************************************************/
1447
1448 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1449 {
1450         size_t cnt = 0;
1451         SMB_STRUCT_DIR *dirp = NULL;
1452         char *dname = NULL;
1453         const char *connect_path = lp_pathname(snum);
1454         const char *msdfs_proxy = lp_msdfs_proxy(snum);
1455         connection_struct *conn;
1456         NTSTATUS status;
1457         char *cwd;
1458
1459         if(*connect_path == '\0') {
1460                 return 0;
1461         }
1462
1463         /*
1464          * Fake up a connection struct for the VFS layer.
1465          */
1466
1467         status = create_conn_struct(talloc_tos(), &conn, snum, connect_path,
1468                                     NULL, &cwd);
1469         if (!NT_STATUS_IS_OK(status)) {
1470                 DEBUG(3, ("create_conn_struct failed: %s\n",
1471                           nt_errstr(status)));
1472                 return 0;
1473         }
1474
1475         /* Count a link for the msdfs root - convention */
1476         cnt = 1;
1477
1478         /* No more links if this is an msdfs proxy. */
1479         if (*msdfs_proxy != '\0') {
1480                 goto out;
1481         }
1482
1483         /* Now enumerate all dfs links */
1484         dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1485         if(!dirp) {
1486                 goto out;
1487         }
1488
1489         while ((dname = vfs_readdirname(conn, dirp)) != NULL) {
1490                 if (is_msdfs_link(conn,
1491                                 dname,
1492                                 NULL)) {
1493                         cnt++;
1494                 }
1495         }
1496
1497         SMB_VFS_CLOSEDIR(conn,dirp);
1498
1499 out:
1500         vfs_ChDir(conn, cwd);
1501         conn_free_internal(conn);
1502         return cnt;
1503 }
1504
1505 /*********************************************************************
1506 *********************************************************************/
1507
1508 static int form_junctions(TALLOC_CTX *ctx,
1509                                 int snum,
1510                                 struct junction_map *jucn,
1511                                 size_t jn_remain)
1512 {
1513         size_t cnt = 0;
1514         SMB_STRUCT_DIR *dirp = NULL;
1515         char *dname = NULL;
1516         const char *connect_path = lp_pathname(snum);
1517         char *service_name = lp_servicename(snum);
1518         const char *msdfs_proxy = lp_msdfs_proxy(snum);
1519         connection_struct *conn;
1520         struct referral *ref = NULL;
1521         char *cwd;
1522         NTSTATUS status;
1523
1524         if (jn_remain == 0) {
1525                 return 0;
1526         }
1527
1528         if(*connect_path == '\0') {
1529                 return 0;
1530         }
1531
1532         /*
1533          * Fake up a connection struct for the VFS layer.
1534          */
1535
1536         status = create_conn_struct(ctx, &conn, snum, connect_path, NULL,
1537                                     &cwd);
1538         if (!NT_STATUS_IS_OK(status)) {
1539                 DEBUG(3, ("create_conn_struct failed: %s\n",
1540                           nt_errstr(status)));
1541                 return 0;
1542         }
1543
1544         /* form a junction for the msdfs root - convention
1545            DO NOT REMOVE THIS: NT clients will not work with us
1546            if this is not present
1547         */
1548         jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1549         jucn[cnt].volume_name = talloc_strdup(ctx, "");
1550         if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1551                 goto out;
1552         }
1553         jucn[cnt].comment = "";
1554         jucn[cnt].referral_count = 1;
1555
1556         ref = jucn[cnt].referral_list = TALLOC_ZERO_P(ctx, struct referral);
1557         if (jucn[cnt].referral_list == NULL) {
1558                 goto out;
1559         }
1560
1561         ref->proximity = 0;
1562         ref->ttl = REFERRAL_TTL;
1563         if (*msdfs_proxy != '\0') {
1564                 ref->alternate_path = talloc_strdup(ctx,
1565                                                 msdfs_proxy);
1566         } else {
1567                 ref->alternate_path = talloc_asprintf(ctx,
1568                         "\\\\%s\\%s",
1569                         get_local_machine_name(),
1570                         service_name);
1571         }
1572
1573         if (!ref->alternate_path) {
1574                 goto out;
1575         }
1576         cnt++;
1577
1578         /* Don't enumerate if we're an msdfs proxy. */
1579         if (*msdfs_proxy != '\0') {
1580                 goto out;
1581         }
1582
1583         /* Now enumerate all dfs links */
1584         dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1585         if(!dirp) {
1586                 goto out;
1587         }
1588
1589         while ((dname = vfs_readdirname(conn, dirp)) != NULL) {
1590                 char *link_target = NULL;
1591                 if (cnt >= jn_remain) {
1592                         DEBUG(2, ("form_junctions: ran out of MSDFS "
1593                                 "junction slots"));
1594                         goto out;
1595                 }
1596                 if (is_msdfs_link_internal(ctx,
1597                                         conn,
1598                                         dname, &link_target,
1599                                         NULL)) {
1600                         if (parse_msdfs_symlink(ctx,
1601                                         link_target,
1602                                         &jucn[cnt].referral_list,
1603                                         &jucn[cnt].referral_count)) {
1604
1605                                 jucn[cnt].service_name = talloc_strdup(ctx,
1606                                                                 service_name);
1607                                 jucn[cnt].volume_name = talloc_strdup(ctx,
1608                                                                 dname);
1609                                 if (!jucn[cnt].service_name ||
1610                                                 !jucn[cnt].volume_name) {
1611                                         goto out;
1612                                 }
1613                                 jucn[cnt].comment = "";
1614                                 cnt++;
1615                         }
1616                         TALLOC_FREE(link_target);
1617                 }
1618         }
1619
1620 out:
1621
1622         if (dirp) {
1623                 SMB_VFS_CLOSEDIR(conn,dirp);
1624         }
1625
1626         vfs_ChDir(conn, cwd);
1627         conn_free_internal(conn);
1628         return cnt;
1629 }
1630
1631 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1632 {
1633         struct junction_map *jn = NULL;
1634         int i=0;
1635         size_t jn_count = 0;
1636         int sharecount = 0;
1637
1638         *p_num_jn = 0;
1639         if(!lp_host_msdfs()) {
1640                 return NULL;
1641         }
1642
1643         /* Ensure all the usershares are loaded. */
1644         become_root();
1645         load_registry_shares();
1646         sharecount = load_usershare_shares();
1647         unbecome_root();
1648
1649         for(i=0;i < sharecount;i++) {
1650                 if(lp_msdfs_root(i)) {
1651                         jn_count += count_dfs_links(ctx, i);
1652                 }
1653         }
1654         if (jn_count == 0) {
1655                 return NULL;
1656         }
1657         jn = TALLOC_ARRAY(ctx,  struct junction_map, jn_count);
1658         if (!jn) {
1659                 return NULL;
1660         }
1661         for(i=0; i < sharecount; i++) {
1662                 if (*p_num_jn >= jn_count) {
1663                         break;
1664                 }
1665                 if(lp_msdfs_root(i)) {
1666                         *p_num_jn += form_junctions(ctx, i,
1667                                         &jn[*p_num_jn],
1668                                         jn_count - *p_num_jn);
1669                 }
1670         }
1671         return jn;
1672 }
1673
1674 /******************************************************************************
1675  Core function to resolve a dfs pathname.
1676 ******************************************************************************/
1677
1678 NTSTATUS resolve_dfspath(TALLOC_CTX *ctx,
1679                         connection_struct *conn,
1680                         bool dfs_pathnames,
1681                         const char *name_in,
1682                         char **pp_name_out)
1683 {
1684         NTSTATUS status = NT_STATUS_OK;
1685         bool dummy;
1686         if (dfs_pathnames) {
1687                 status = dfs_redirect(ctx,
1688                                         conn,
1689                                         name_in,
1690                                         False,
1691                                         pp_name_out,
1692                                         &dummy);
1693         } else {
1694                 /*
1695                  * Cheat and just return a copy of the in ptr.
1696                  * Once srvstr_get_path() uses talloc it'll
1697                  * be a talloced ptr anyway.
1698                  */
1699                 *pp_name_out = CONST_DISCARD(char *,name_in);
1700         }
1701         return status;
1702 }
1703
1704 /******************************************************************************
1705  Core function to resolve a dfs pathname possibly containing a wildcard.
1706  This function is identical to the above except for the bool param to
1707  dfs_redirect but I need this to be separate so it's really clear when
1708  we're allowing wildcards and when we're not. JRA.
1709 ******************************************************************************/
1710
1711 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1712                                 connection_struct *conn,
1713                                 bool dfs_pathnames,
1714                                 const char *name_in,
1715                                 char **pp_name_out,
1716                                 bool *ppath_contains_wcard)
1717 {
1718         NTSTATUS status = NT_STATUS_OK;
1719         if (dfs_pathnames) {
1720                 status = dfs_redirect(ctx,
1721                                         conn,
1722                                         name_in,
1723                                         True,
1724                                         pp_name_out,
1725                                         ppath_contains_wcard);
1726         } else {
1727                 /*
1728                  * Cheat and just return a copy of the in ptr.
1729                  * Once srvstr_get_path() uses talloc it'll
1730                  * be a talloced ptr anyway.
1731                  */
1732                 *pp_name_out = CONST_DISCARD(char *,name_in);
1733         }
1734         return status;
1735 }