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