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