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