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