s3: Remove the smbd_server_conn ref from dfs_redirect
[garming/samba-autobuild/.git] / source3 / smbd / msdfs.c
1 /*
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    MSDFS services for Samba
5    Copyright (C) Shirish Kalele 2000
6    Copyright (C) Jeremy Allison 2007
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
21 */
22
23 #define DBGC_CLASS DBGC_MSDFS
24 #include "includes.h"
25 #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 can
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          * If we needed to remember what we'd resolved in
585          * dp->reqpath (as the original code did) we'd
586          * copy (localhost, dp->reqpath) on any code
587          * path below that returns True - but I don't
588          * think this is needed. JRA.
589          */
590
591         status = unix_convert(ctx, conn, pdp->reqpath, &smb_fname,
592                               search_flag ? UCF_ALWAYS_ALLOW_WCARD_LCOMP : 0);
593
594         if (!NT_STATUS_IS_OK(status)) {
595                 if (!NT_STATUS_EQUAL(status,
596                                      NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
597                         return status;
598                 }
599
600                 /* Create an smb_fname to use below. */
601                 status = create_synthetic_smb_fname(ctx, pdp->reqpath, NULL,
602                                                     NULL, &smb_fname);
603                 if (!NT_STATUS_IS_OK(status)) {
604                         return status;
605                 }
606         }
607
608         /* Optimization - check if we can redirect the whole path. */
609
610         if (is_msdfs_link_internal(ctx, conn, smb_fname->base_name,
611                                    pp_targetpath, NULL)) {
612                 if (search_flag) {
613                         DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
614                                  "for dfs link %s.\n", dfspath));
615                         status = NT_STATUS_OK;
616                         goto out;
617                 }
618
619                 DEBUG(6,("dfs_path_lookup: %s resolves to a "
620                         "valid dfs link %s.\n", dfspath,
621                         pp_targetpath ? *pp_targetpath : ""));
622
623                 if (consumedcntp) {
624                         *consumedcntp = strlen(dfspath);
625                 }
626                 status = NT_STATUS_PATH_NOT_COVERED;
627                 goto out;
628         }
629
630         /* Prepare to test only for '/' components in the given path,
631          * so if a Windows path replace all '\\' characters with '/'.
632          * For a POSIX DFS path we know all separators are already '/'. */
633
634         canon_dfspath = talloc_strdup(ctx, dfspath);
635         if (!canon_dfspath) {
636                 status = NT_STATUS_NO_MEMORY;
637                 goto out;
638         }
639         if (!pdp->posix_path) {
640                 string_replace(canon_dfspath, '\\', '/');
641         }
642
643         /*
644          * localpath comes out of unix_convert, so it has
645          * no trailing backslash. Make sure that canon_dfspath hasn't either.
646          * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
647          */
648
649         trim_char(canon_dfspath,0,'/');
650
651         /*
652          * Redirect if any component in the path is a link.
653          * We do this by walking backwards through the
654          * local path, chopping off the last component
655          * in both the local path and the canonicalized
656          * DFS path. If we hit a DFS link then we're done.
657          */
658
659         p = strrchr_m(smb_fname->base_name, '/');
660         if (consumedcntp) {
661                 q = strrchr_m(canon_dfspath, '/');
662         }
663
664         while (p) {
665                 *p = '\0';
666                 if (q) {
667                         *q = '\0';
668                 }
669
670                 if (is_msdfs_link_internal(ctx, conn,
671                                            smb_fname->base_name, pp_targetpath,
672                                            NULL)) {
673                         DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
674                                   "parent %s is dfs link\n", dfspath,
675                                   smb_fname_str_dbg(smb_fname)));
676
677                         if (consumedcntp) {
678                                 *consumedcntp = strlen(canon_dfspath);
679                                 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
680                                         "(%d)\n",
681                                         canon_dfspath,
682                                         *consumedcntp));
683                         }
684
685                         status = NT_STATUS_PATH_NOT_COVERED;
686                         goto out;
687                 }
688
689                 /* Step back on the filesystem. */
690                 p = strrchr_m(smb_fname->base_name, '/');
691
692                 if (consumedcntp) {
693                         /* And in the canonicalized dfs path. */
694                         q = strrchr_m(canon_dfspath, '/');
695                 }
696         }
697
698         status = NT_STATUS_OK;
699  out:
700         TALLOC_FREE(smb_fname);
701         return status;
702 }
703
704 /*****************************************************************
705  Decides if a dfs pathname should be redirected or not.
706  If not, the pathname is converted to a tcon-relative local unix path
707
708  search_wcard_flag: this flag performs 2 functions both related
709  to searches.  See resolve_dfs_path() and parse_dfs_path_XX()
710  for details.
711
712  This function can return NT_STATUS_OK, meaning use the returned path as-is
713  (mapped into a local path).
714  or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
715  any other NT_STATUS error which is a genuine error to be
716  returned to the client.
717 *****************************************************************/
718
719 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
720                         connection_struct *conn,
721                         const char *path_in,
722                         bool search_wcard_flag,
723                         bool allow_broken_path,
724                         char **pp_path_out,
725                         bool *ppath_contains_wcard)
726 {
727         NTSTATUS status;
728         struct dfs_path *pdp = talloc(ctx, struct dfs_path);
729
730         if (!pdp) {
731                 return NT_STATUS_NO_MEMORY;
732         }
733
734         status = parse_dfs_path(conn, path_in, search_wcard_flag,
735                                 allow_broken_path, pdp,
736                         ppath_contains_wcard);
737         if (!NT_STATUS_IS_OK(status)) {
738                 TALLOC_FREE(pdp);
739                 return status;
740         }
741
742         if (pdp->reqpath[0] == '\0') {
743                 TALLOC_FREE(pdp);
744                 *pp_path_out = talloc_strdup(ctx, "");
745                 if (!*pp_path_out) {
746                         return NT_STATUS_NO_MEMORY;
747                 }
748                 DEBUG(5,("dfs_redirect: self-referral.\n"));
749                 return NT_STATUS_OK;
750         }
751
752         /* If dfs pathname for a non-dfs share, convert to tcon-relative
753            path and return OK */
754
755         if (!lp_msdfs_root(SNUM(conn))) {
756                 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
757                 TALLOC_FREE(pdp);
758                 if (!*pp_path_out) {
759                         return NT_STATUS_NO_MEMORY;
760                 }
761                 return NT_STATUS_OK;
762         }
763
764         /* If it looked like a local path (zero hostname/servicename)
765          * just treat as a tcon-relative path. */
766
767         if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
768                 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
769                 TALLOC_FREE(pdp);
770                 if (!*pp_path_out) {
771                         return NT_STATUS_NO_MEMORY;
772                 }
773                 return NT_STATUS_OK;
774         }
775
776         if (!( strequal(pdp->servicename, lp_servicename(SNUM(conn)))
777                         || (strequal(pdp->servicename, HOMES_NAME)
778                         && strequal(lp_servicename(SNUM(conn)),
779                                 conn->session_info->unix_info->sanitized_username) )) ) {
780
781                 /* The given sharename doesn't match this connection. */
782                 TALLOC_FREE(pdp);
783
784                 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
785         }
786
787         status = dfs_path_lookup(ctx, conn, path_in, pdp,
788                         search_wcard_flag, NULL, NULL);
789         if (!NT_STATUS_IS_OK(status)) {
790                 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
791                         DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
792                 } else {
793                         DEBUG(10,("dfs_redirect: dfs_path_lookup "
794                                 "failed for %s with %s\n",
795                                 path_in, nt_errstr(status) ));
796                 }
797                 return status;
798         }
799
800         DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
801
802         /* Form non-dfs tcon-relative path */
803         *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
804         TALLOC_FREE(pdp);
805         if (!*pp_path_out) {
806                 return NT_STATUS_NO_MEMORY;
807         }
808
809         DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
810                                 path_in,
811                                 *pp_path_out));
812
813         return NT_STATUS_OK;
814 }
815
816 /**********************************************************************
817  Return a self referral.
818 **********************************************************************/
819
820 static NTSTATUS self_ref(TALLOC_CTX *ctx,
821                         const char *dfs_path,
822                         struct junction_map *jucn,
823                         int *consumedcntp,
824                         bool *self_referralp)
825 {
826         struct referral *ref;
827
828         *self_referralp = True;
829
830         jucn->referral_count = 1;
831         if((ref = talloc_zero(ctx, struct referral)) == NULL) {
832                 return NT_STATUS_NO_MEMORY;
833         }
834
835         ref->alternate_path = talloc_strdup(ctx, dfs_path);
836         if (!ref->alternate_path) {
837                 return NT_STATUS_NO_MEMORY;
838         }
839         ref->proximity = 0;
840         ref->ttl = REFERRAL_TTL;
841         jucn->referral_list = ref;
842         *consumedcntp = strlen(dfs_path);
843         return NT_STATUS_OK;
844 }
845
846 /**********************************************************************
847  Gets valid referrals for a dfs path and fills up the
848  junction_map structure.
849 **********************************************************************/
850
851 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
852                         const char *dfs_path,
853                         struct junction_map *jucn,
854                         int *consumedcntp,
855                         bool *self_referralp)
856 {
857         struct connection_struct *conn;
858         char *targetpath = NULL;
859         int snum;
860         NTSTATUS status = NT_STATUS_NOT_FOUND;
861         bool dummy;
862         struct dfs_path *pdp = talloc(ctx, struct dfs_path);
863         char *oldpath;
864
865         if (!pdp) {
866                 return NT_STATUS_NO_MEMORY;
867         }
868
869         *self_referralp = False;
870
871         status = parse_dfs_path(NULL, dfs_path, False,
872                                 !smbd_server_conn->using_smb2, pdp, &dummy);
873         if (!NT_STATUS_IS_OK(status)) {
874                 return status;
875         }
876
877         jucn->service_name = talloc_strdup(ctx, pdp->servicename);
878         jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
879         if (!jucn->service_name || !jucn->volume_name) {
880                 TALLOC_FREE(pdp);
881                 return NT_STATUS_NO_MEMORY;
882         }
883
884         /* Verify the share is a dfs root */
885         snum = lp_servicenumber(jucn->service_name);
886         if(snum < 0) {
887                 char *service_name = NULL;
888                 if ((snum = find_service(ctx, jucn->service_name, &service_name)) < 0) {
889                         return NT_STATUS_NOT_FOUND;
890                 }
891                 if (!service_name) {
892                         return NT_STATUS_NO_MEMORY;
893                 }
894                 TALLOC_FREE(jucn->service_name);
895                 jucn->service_name = talloc_strdup(ctx, service_name);
896                 if (!jucn->service_name) {
897                         TALLOC_FREE(pdp);
898                         return NT_STATUS_NO_MEMORY;
899                 }
900         }
901
902         if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(snum) == '\0')) {
903                 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
904                         "a dfs root.\n",
905                         pdp->servicename, dfs_path));
906                 TALLOC_FREE(pdp);
907                 return NT_STATUS_NOT_FOUND;
908         }
909
910         /*
911          * Self referrals are tested with a anonymous IPC connection and
912          * a GET_DFS_REFERRAL call to \\server\share. (which means
913          * dp.reqpath[0] points to an empty string). create_conn_struct cd's
914          * into the directory and will fail if it cannot (as the anonymous
915          * user). Cope with this.
916          */
917
918         if (pdp->reqpath[0] == '\0') {
919                 char *tmp;
920                 struct referral *ref;
921
922                 if (*lp_msdfs_proxy(snum) == '\0') {
923                         TALLOC_FREE(pdp);
924                         return self_ref(ctx,
925                                         dfs_path,
926                                         jucn,
927                                         consumedcntp,
928                                         self_referralp);
929                 }
930
931                 /*
932                  * It's an msdfs proxy share. Redirect to
933                  * the configured target share.
934                  */
935
936                 jucn->referral_count = 1;
937                 if ((ref = talloc_zero(ctx, struct referral)) == NULL) {
938                         TALLOC_FREE(pdp);
939                         return NT_STATUS_NO_MEMORY;
940                 }
941
942                 if (!(tmp = talloc_strdup(ctx, lp_msdfs_proxy(snum)))) {
943                         TALLOC_FREE(pdp);
944                         return NT_STATUS_NO_MEMORY;
945                 }
946
947                 trim_string(tmp, "\\", 0);
948
949                 ref->alternate_path = talloc_asprintf(ctx, "\\%s", tmp);
950                 TALLOC_FREE(tmp);
951
952                 if (!ref->alternate_path) {
953                         TALLOC_FREE(pdp);
954                         return NT_STATUS_NO_MEMORY;
955                 }
956
957                 if (pdp->reqpath[0] != '\0') {
958                         ref->alternate_path = talloc_asprintf_append(
959                                         ref->alternate_path,
960                                         "%s",
961                                         pdp->reqpath);
962                         if (!ref->alternate_path) {
963                                 TALLOC_FREE(pdp);
964                                 return NT_STATUS_NO_MEMORY;
965                         }
966                 }
967                 ref->proximity = 0;
968                 ref->ttl = REFERRAL_TTL;
969                 jucn->referral_list = ref;
970                 *consumedcntp = strlen(dfs_path);
971                 TALLOC_FREE(pdp);
972                 return NT_STATUS_OK;
973         }
974
975         status = create_conn_struct(ctx, smbd_server_conn, &conn, snum,
976                                     lp_pathname(snum), NULL, &oldpath);
977         if (!NT_STATUS_IS_OK(status)) {
978                 TALLOC_FREE(pdp);
979                 return status;
980         }
981
982         /* If this is a DFS path dfs_lookup should return
983          * NT_STATUS_PATH_NOT_COVERED. */
984
985         status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
986                         False, consumedcntp, &targetpath);
987
988         if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
989                 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
990                         dfs_path));
991                 goto err_exit;
992         }
993
994         /* We know this is a valid dfs link. Parse the targetpath. */
995         if (!parse_msdfs_symlink(ctx, targetpath,
996                                 &jucn->referral_list,
997                                 &jucn->referral_count)) {
998                 DEBUG(3,("get_referred_path: failed to parse symlink "
999                         "target %s\n", targetpath ));
1000                 status = NT_STATUS_NOT_FOUND;
1001                 goto err_exit;
1002         }
1003
1004         status = NT_STATUS_OK;
1005  err_exit:
1006         vfs_ChDir(conn, oldpath);
1007         SMB_VFS_DISCONNECT(conn);
1008         conn_free(conn);
1009         TALLOC_FREE(pdp);
1010         return status;
1011 }
1012
1013 static int setup_ver2_dfs_referral(const char *pathname,
1014                                 char **ppdata,
1015                                 struct junction_map *junction,
1016                                 bool self_referral)
1017 {
1018         char* pdata = *ppdata;
1019
1020         smb_ucs2_t *uni_requestedpath = NULL;
1021         int uni_reqpathoffset1,uni_reqpathoffset2;
1022         int uni_curroffset;
1023         int requestedpathlen=0;
1024         int offset;
1025         int reply_size = 0;
1026         int i=0;
1027
1028         DEBUG(10,("Setting up version2 referral\nRequested path:\n"));
1029
1030         requestedpathlen = rpcstr_push_talloc(talloc_tos(),
1031                                         &uni_requestedpath, pathname);
1032         if (uni_requestedpath == NULL || requestedpathlen == 0) {
1033                 return -1;
1034         }
1035
1036         if (DEBUGLVL(10)) {
1037                 dump_data(0, (unsigned char *)uni_requestedpath,
1038                         requestedpathlen);
1039         }
1040
1041         DEBUG(10,("ref count = %u\n",junction->referral_count));
1042
1043         uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
1044                         VERSION2_REFERRAL_SIZE * junction->referral_count;
1045
1046         uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen;
1047
1048         uni_curroffset = uni_reqpathoffset2 + requestedpathlen;
1049
1050         reply_size = REFERRAL_HEADER_SIZE +
1051                         VERSION2_REFERRAL_SIZE*junction->referral_count +
1052                         2 * requestedpathlen;
1053         DEBUG(10,("reply_size: %u\n",reply_size));
1054
1055         /* add up the unicode lengths of all the referral paths */
1056         for(i=0;i<junction->referral_count;i++) {
1057                 DEBUG(10,("referral %u : %s\n",
1058                         i,
1059                         junction->referral_list[i].alternate_path));
1060                 reply_size +=
1061                         (strlen(junction->referral_list[i].alternate_path)+1)*2;
1062         }
1063
1064         DEBUG(10,("reply_size = %u\n",reply_size));
1065         /* add the unexplained 0x16 bytes */
1066         reply_size += 0x16;
1067
1068         pdata = (char *)SMB_REALLOC(pdata,reply_size);
1069         if(pdata == NULL) {
1070                 DEBUG(0,("Realloc failed!\n"));
1071                 return -1;
1072         }
1073         *ppdata = pdata;
1074
1075         /* copy in the dfs requested paths.. required for offset calculations */
1076         memcpy(pdata+uni_reqpathoffset1,uni_requestedpath,requestedpathlen);
1077         memcpy(pdata+uni_reqpathoffset2,uni_requestedpath,requestedpathlen);
1078
1079         /* create the header */
1080         SSVAL(pdata,0,requestedpathlen - 2); /* UCS2 of path consumed minus
1081                                                 2 byte null */
1082         /* number of referral in this pkt */
1083         SSVAL(pdata,2,junction->referral_count);
1084         if(self_referral) {
1085                 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
1086         } else {
1087                 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
1088         }
1089
1090         offset = 8;
1091         /* add the referral elements */
1092         for(i=0;i<junction->referral_count;i++) {
1093                 struct referral* ref = &junction->referral_list[i];
1094                 int unilen;
1095
1096                 SSVAL(pdata,offset,2); /* version 2 */
1097                 SSVAL(pdata,offset+2,VERSION2_REFERRAL_SIZE);
1098                 if(self_referral) {
1099                         SSVAL(pdata,offset+4,1);
1100                 } else {
1101                         SSVAL(pdata,offset+4,0);
1102                 }
1103
1104                 /* ref_flags :use path_consumed bytes? */
1105                 SSVAL(pdata,offset+6,0);
1106                 SIVAL(pdata,offset+8,ref->proximity);
1107                 SIVAL(pdata,offset+12,ref->ttl);
1108
1109                 SSVAL(pdata,offset+16,uni_reqpathoffset1-offset);
1110                 SSVAL(pdata,offset+18,uni_reqpathoffset2-offset);
1111                 /* copy referred path into current offset */
1112                 unilen = rpcstr_push(pdata+uni_curroffset,
1113                                         ref->alternate_path,
1114                                         reply_size - uni_curroffset,
1115                                         STR_UNICODE);
1116
1117                 SSVAL(pdata,offset+20,uni_curroffset-offset);
1118
1119                 uni_curroffset += unilen;
1120                 offset += VERSION2_REFERRAL_SIZE;
1121         }
1122         /* add in the unexplained 22 (0x16) bytes at the end */
1123         memset(pdata+uni_curroffset,'\0',0x16);
1124         return reply_size;
1125 }
1126
1127 static int setup_ver3_dfs_referral(const char *pathname,
1128                                 char **ppdata,
1129                                 struct junction_map *junction,
1130                                 bool self_referral)
1131 {
1132         char *pdata = *ppdata;
1133
1134         smb_ucs2_t *uni_reqpath = NULL;
1135         int uni_reqpathoffset1, uni_reqpathoffset2;
1136         int uni_curroffset;
1137         int reply_size = 0;
1138
1139         int reqpathlen = 0;
1140         int offset,i=0;
1141
1142         DEBUG(10,("setting up version3 referral\n"));
1143
1144         reqpathlen = rpcstr_push_talloc(talloc_tos(), &uni_reqpath, pathname);
1145         if (uni_reqpath == NULL || reqpathlen == 0) {
1146                 return -1;
1147         }
1148
1149         if (DEBUGLVL(10)) {
1150                 dump_data(0, (unsigned char *)uni_reqpath,
1151                         reqpathlen);
1152         }
1153
1154         uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
1155                         VERSION3_REFERRAL_SIZE * junction->referral_count;
1156         uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen;
1157         reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen;
1158
1159         for(i=0;i<junction->referral_count;i++) {
1160                 DEBUG(10,("referral %u : %s\n",
1161                         i,
1162                         junction->referral_list[i].alternate_path));
1163                 reply_size +=
1164                         (strlen(junction->referral_list[i].alternate_path)+1)*2;
1165         }
1166
1167         pdata = (char *)SMB_REALLOC(pdata,reply_size);
1168         if(pdata == NULL) {
1169                 DEBUG(0,("version3 referral setup:"
1170                         "malloc failed for Realloc!\n"));
1171                 return -1;
1172         }
1173         *ppdata = pdata;
1174
1175         /* create the header */
1176         SSVAL(pdata,0,reqpathlen - 2); /* UCS2 of path consumed minus
1177                                           2 byte null */
1178         SSVAL(pdata,2,junction->referral_count); /* number of referral */
1179         if(self_referral) {
1180                 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
1181         } else {
1182                 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
1183         }
1184
1185         /* copy in the reqpaths */
1186         memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen);
1187         memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen);
1188
1189         offset = 8;
1190         for(i=0;i<junction->referral_count;i++) {
1191                 struct referral* ref = &(junction->referral_list[i]);
1192                 int unilen;
1193
1194                 SSVAL(pdata,offset,3); /* version 3 */
1195                 SSVAL(pdata,offset+2,VERSION3_REFERRAL_SIZE);
1196                 if(self_referral) {
1197                         SSVAL(pdata,offset+4,1);
1198                 } else {
1199                         SSVAL(pdata,offset+4,0);
1200                 }
1201
1202                 /* ref_flags :use path_consumed bytes? */
1203                 SSVAL(pdata,offset+6,0);
1204                 SIVAL(pdata,offset+8,ref->ttl);
1205
1206                 SSVAL(pdata,offset+12,uni_reqpathoffset1-offset);
1207                 SSVAL(pdata,offset+14,uni_reqpathoffset2-offset);
1208                 /* copy referred path into current offset */
1209                 unilen = rpcstr_push(pdata+uni_curroffset,ref->alternate_path,
1210                                         reply_size - uni_curroffset,
1211                                         STR_UNICODE | STR_TERMINATE);
1212                 SSVAL(pdata,offset+16,uni_curroffset-offset);
1213                 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
1214                 memset(pdata+offset+18,'\0',16);
1215
1216                 uni_curroffset += unilen;
1217                 offset += VERSION3_REFERRAL_SIZE;
1218         }
1219         return reply_size;
1220 }
1221
1222 /******************************************************************
1223  Set up the DFS referral for the dfs pathname. This call returns
1224  the amount of the path covered by this server, and where the
1225  client should be redirected to. This is the meat of the
1226  TRANS2_GET_DFS_REFERRAL call.
1227 ******************************************************************/
1228
1229 int setup_dfs_referral(connection_struct *orig_conn,
1230                         const char *dfs_path,
1231                         int max_referral_level,
1232                         char **ppdata, NTSTATUS *pstatus)
1233 {
1234         struct junction_map *junction = NULL;
1235         int consumedcnt = 0;
1236         bool self_referral = False;
1237         int reply_size = 0;
1238         char *pathnamep = NULL;
1239         char *local_dfs_path = NULL;
1240         TALLOC_CTX *ctx;
1241
1242         if (!(ctx=talloc_init("setup_dfs_referral"))) {
1243                 *pstatus = NT_STATUS_NO_MEMORY;
1244                 return -1;
1245         }
1246
1247         /* get the junction entry */
1248         if (!dfs_path) {
1249                 talloc_destroy(ctx);
1250                 *pstatus = NT_STATUS_NOT_FOUND;
1251                 return -1;
1252         }
1253
1254         /*
1255          * Trim pathname sent by client so it begins with only one backslash.
1256          * Two backslashes confuse some dfs clients
1257          */
1258
1259         local_dfs_path = talloc_strdup(ctx,dfs_path);
1260         if (!local_dfs_path) {
1261                 *pstatus = NT_STATUS_NO_MEMORY;
1262                 talloc_destroy(ctx);
1263                 return -1;
1264         }
1265         pathnamep = local_dfs_path;
1266         while (IS_DIRECTORY_SEP(pathnamep[0]) &&
1267                         IS_DIRECTORY_SEP(pathnamep[1])) {
1268                 pathnamep++;
1269         }
1270
1271         junction = talloc_zero(ctx, struct junction_map);
1272         if (!junction) {
1273                 *pstatus = NT_STATUS_NO_MEMORY;
1274                 talloc_destroy(ctx);
1275                 return -1;
1276         }
1277
1278         /* The following call can change cwd. */
1279         *pstatus = get_referred_path(ctx, pathnamep, junction,
1280                         &consumedcnt, &self_referral);
1281         if (!NT_STATUS_IS_OK(*pstatus)) {
1282                 vfs_ChDir(orig_conn,orig_conn->connectpath);
1283                 talloc_destroy(ctx);
1284                 return -1;
1285         }
1286         vfs_ChDir(orig_conn,orig_conn->connectpath);
1287
1288         if (!self_referral) {
1289                 pathnamep[consumedcnt] = '\0';
1290
1291                 if( DEBUGLVL( 3 ) ) {
1292                         int i=0;
1293                         dbgtext("setup_dfs_referral: Path %s to "
1294                                 "alternate path(s):",
1295                                 pathnamep);
1296                         for(i=0;i<junction->referral_count;i++)
1297                                 dbgtext(" %s",
1298                                 junction->referral_list[i].alternate_path);
1299                         dbgtext(".\n");
1300                 }
1301         }
1302
1303         /* create the referral depeding on version */
1304         DEBUG(10,("max_referral_level :%d\n",max_referral_level));
1305
1306         if (max_referral_level < 2) {
1307                 max_referral_level = 2;
1308         }
1309         if (max_referral_level > 3) {
1310                 max_referral_level = 3;
1311         }
1312
1313         switch(max_referral_level) {
1314         case 2:
1315                 reply_size = setup_ver2_dfs_referral(pathnamep,
1316                                         ppdata, junction,
1317                                         self_referral);
1318                 break;
1319         case 3:
1320                 reply_size = setup_ver3_dfs_referral(pathnamep, ppdata,
1321                                         junction, self_referral);
1322                 break;
1323         default:
1324                 DEBUG(0,("setup_dfs_referral: Invalid dfs referral "
1325                         "version: %d\n",
1326                         max_referral_level));
1327                 talloc_destroy(ctx);
1328                 *pstatus = NT_STATUS_INVALID_LEVEL;
1329                 return -1;
1330         }
1331
1332         if (DEBUGLVL(10)) {
1333                 DEBUGADD(0,("DFS Referral pdata:\n"));
1334                 dump_data(0,(uint8 *)*ppdata,reply_size);
1335         }
1336
1337         talloc_destroy(ctx);
1338         *pstatus = NT_STATUS_OK;
1339         return reply_size;
1340 }
1341
1342 /**********************************************************************
1343  The following functions are called by the NETDFS RPC pipe functions
1344  **********************************************************************/
1345
1346 /*********************************************************************
1347  Creates a junction structure from a DFS pathname
1348 **********************************************************************/
1349
1350 bool create_junction(TALLOC_CTX *ctx,
1351                 const char *dfs_path,
1352                 struct junction_map *jucn)
1353 {
1354         int snum;
1355         bool dummy;
1356         struct dfs_path *pdp = talloc(ctx,struct dfs_path);
1357         NTSTATUS status;
1358
1359         if (!pdp) {
1360                 return False;
1361         }
1362         status = parse_dfs_path(NULL, dfs_path, False,
1363                                 !smbd_server_conn->using_smb2, pdp, &dummy);
1364         if (!NT_STATUS_IS_OK(status)) {
1365                 return False;
1366         }
1367
1368         /* check if path is dfs : validate first token */
1369         if (!is_myname_or_ipaddr(pdp->hostname)) {
1370                 DEBUG(4,("create_junction: Invalid hostname %s "
1371                         "in dfs path %s\n",
1372                         pdp->hostname, dfs_path));
1373                 TALLOC_FREE(pdp);
1374                 return False;
1375         }
1376
1377         /* Check for a non-DFS share */
1378         snum = lp_servicenumber(pdp->servicename);
1379
1380         if(snum < 0 || !lp_msdfs_root(snum)) {
1381                 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1382                         pdp->servicename));
1383                 TALLOC_FREE(pdp);
1384                 return False;
1385         }
1386
1387         jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1388         jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1389         jucn->comment = talloc_strdup(ctx, lp_comment(snum));
1390
1391         TALLOC_FREE(pdp);
1392         if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1393                 return False;
1394         }
1395         return True;
1396 }
1397
1398 /**********************************************************************
1399  Forms a valid Unix pathname from the junction
1400  **********************************************************************/
1401
1402 static bool junction_to_local_path(const struct junction_map *jucn,
1403                                    char **pp_path_out,
1404                                    connection_struct **conn_out,
1405                                    char **oldpath)
1406 {
1407         int snum;
1408         NTSTATUS status;
1409
1410         snum = lp_servicenumber(jucn->service_name);
1411         if(snum < 0) {
1412                 return False;
1413         }
1414         status = create_conn_struct(talloc_tos(), smbd_server_conn, conn_out,
1415                                     snum, lp_pathname(snum), NULL, oldpath);
1416         if (!NT_STATUS_IS_OK(status)) {
1417                 return False;
1418         }
1419
1420         *pp_path_out = talloc_asprintf(*conn_out,
1421                         "%s/%s",
1422                         lp_pathname(snum),
1423                         jucn->volume_name);
1424         if (!*pp_path_out) {
1425                 vfs_ChDir(*conn_out, *oldpath);
1426                 SMB_VFS_DISCONNECT(*conn_out);
1427                 conn_free(*conn_out);
1428                 return False;
1429         }
1430         return True;
1431 }
1432
1433 bool create_msdfs_link(const struct junction_map *jucn)
1434 {
1435         char *path = NULL;
1436         char *cwd;
1437         char *msdfs_link = NULL;
1438         connection_struct *conn;
1439         int i=0;
1440         bool insert_comma = False;
1441         bool ret = False;
1442
1443         if(!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1444                 return False;
1445         }
1446
1447         /* Form the msdfs_link contents */
1448         msdfs_link = talloc_strdup(conn, "msdfs:");
1449         if (!msdfs_link) {
1450                 goto out;
1451         }
1452         for(i=0; i<jucn->referral_count; i++) {
1453                 char *refpath = jucn->referral_list[i].alternate_path;
1454
1455                 /* Alternate paths always use Windows separators. */
1456                 trim_char(refpath, '\\', '\\');
1457                 if(*refpath == '\0') {
1458                         if (i == 0) {
1459                                 insert_comma = False;
1460                         }
1461                         continue;
1462                 }
1463                 if (i > 0 && insert_comma) {
1464                         msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1465                                         ",%s",
1466                                         refpath);
1467                 } else {
1468                         msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1469                                         "%s",
1470                                         refpath);
1471                 }
1472
1473                 if (!msdfs_link) {
1474                         goto out;
1475                 }
1476                 if (!insert_comma) {
1477                         insert_comma = True;
1478                 }
1479         }
1480
1481         DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1482                 path, msdfs_link));
1483
1484         if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1485                 if (errno == EEXIST) {
1486                         struct smb_filename *smb_fname = NULL;
1487                         NTSTATUS status;
1488
1489                         status = create_synthetic_smb_fname(talloc_tos(), path,
1490                                                             NULL, NULL,
1491                                                             &smb_fname);
1492                         if (!NT_STATUS_IS_OK(status)) {
1493                                 errno = map_errno_from_nt_status(status);
1494                                 goto out;
1495                         }
1496
1497                         if(SMB_VFS_UNLINK(conn, smb_fname)!=0) {
1498                                 TALLOC_FREE(smb_fname);
1499                                 goto out;
1500                         }
1501                         TALLOC_FREE(smb_fname);
1502                 }
1503                 if (SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1504                         DEBUG(1,("create_msdfs_link: symlink failed "
1505                                  "%s -> %s\nError: %s\n",
1506                                  path, msdfs_link, strerror(errno)));
1507                         goto out;
1508                 }
1509         }
1510
1511         ret = True;
1512
1513 out:
1514         vfs_ChDir(conn, cwd);
1515         SMB_VFS_DISCONNECT(conn);
1516         conn_free(conn);
1517         return ret;
1518 }
1519
1520 bool remove_msdfs_link(const struct junction_map *jucn)
1521 {
1522         char *path = NULL;
1523         char *cwd;
1524         connection_struct *conn;
1525         bool ret = False;
1526         struct smb_filename *smb_fname = NULL;
1527         NTSTATUS status;
1528
1529         if (!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1530                 return false;
1531         }
1532
1533         status = create_synthetic_smb_fname(talloc_tos(), path,
1534                                             NULL, NULL,
1535                                             &smb_fname);
1536         if (!NT_STATUS_IS_OK(status)) {
1537                 errno = map_errno_from_nt_status(status);
1538                 return false;
1539         }
1540
1541         if( SMB_VFS_UNLINK(conn, smb_fname) == 0 ) {
1542                 ret = True;
1543         }
1544
1545         TALLOC_FREE(smb_fname);
1546         vfs_ChDir(conn, cwd);
1547         SMB_VFS_DISCONNECT(conn);
1548         conn_free(conn);
1549         return ret;
1550 }
1551
1552 /*********************************************************************
1553  Return the number of DFS links at the root of this share.
1554 *********************************************************************/
1555
1556 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1557 {
1558         size_t cnt = 0;
1559         SMB_STRUCT_DIR *dirp = NULL;
1560         const char *dname = NULL;
1561         char *talloced = NULL;
1562         const char *connect_path = lp_pathname(snum);
1563         const char *msdfs_proxy = lp_msdfs_proxy(snum);
1564         connection_struct *conn;
1565         NTSTATUS status;
1566         char *cwd;
1567
1568         if(*connect_path == '\0') {
1569                 return 0;
1570         }
1571
1572         /*
1573          * Fake up a connection struct for the VFS layer.
1574          */
1575
1576         status = create_conn_struct(talloc_tos(), smbd_server_conn, &conn,
1577                                     snum, connect_path, NULL, &cwd);
1578         if (!NT_STATUS_IS_OK(status)) {
1579                 DEBUG(3, ("create_conn_struct failed: %s\n",
1580                           nt_errstr(status)));
1581                 return 0;
1582         }
1583
1584         /* Count a link for the msdfs root - convention */
1585         cnt = 1;
1586
1587         /* No more links if this is an msdfs proxy. */
1588         if (*msdfs_proxy != '\0') {
1589                 goto out;
1590         }
1591
1592         /* Now enumerate all dfs links */
1593         dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1594         if(!dirp) {
1595                 goto out;
1596         }
1597
1598         while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1599                != NULL) {
1600                 if (is_msdfs_link(conn,
1601                                 dname,
1602                                 NULL)) {
1603                         cnt++;
1604                 }
1605                 TALLOC_FREE(talloced);
1606         }
1607
1608         SMB_VFS_CLOSEDIR(conn,dirp);
1609
1610 out:
1611         vfs_ChDir(conn, cwd);
1612         SMB_VFS_DISCONNECT(conn);
1613         conn_free(conn);
1614         return cnt;
1615 }
1616
1617 /*********************************************************************
1618 *********************************************************************/
1619
1620 static int form_junctions(TALLOC_CTX *ctx,
1621                                 int snum,
1622                                 struct junction_map *jucn,
1623                                 size_t jn_remain)
1624 {
1625         size_t cnt = 0;
1626         SMB_STRUCT_DIR *dirp = NULL;
1627         const char *dname = NULL;
1628         char *talloced = NULL;
1629         const char *connect_path = lp_pathname(snum);
1630         char *service_name = lp_servicename(snum);
1631         const char *msdfs_proxy = lp_msdfs_proxy(snum);
1632         connection_struct *conn;
1633         struct referral *ref = NULL;
1634         char *cwd;
1635         NTSTATUS status;
1636
1637         if (jn_remain == 0) {
1638                 return 0;
1639         }
1640
1641         if(*connect_path == '\0') {
1642                 return 0;
1643         }
1644
1645         /*
1646          * Fake up a connection struct for the VFS layer.
1647          */
1648
1649         status = create_conn_struct(ctx, smbd_server_conn, &conn, snum, connect_path, NULL,
1650                                     &cwd);
1651         if (!NT_STATUS_IS_OK(status)) {
1652                 DEBUG(3, ("create_conn_struct failed: %s\n",
1653                           nt_errstr(status)));
1654                 return 0;
1655         }
1656
1657         /* form a junction for the msdfs root - convention
1658            DO NOT REMOVE THIS: NT clients will not work with us
1659            if this is not present
1660         */
1661         jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1662         jucn[cnt].volume_name = talloc_strdup(ctx, "");
1663         if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1664                 goto out;
1665         }
1666         jucn[cnt].comment = "";
1667         jucn[cnt].referral_count = 1;
1668
1669         ref = jucn[cnt].referral_list = talloc_zero(ctx, struct referral);
1670         if (jucn[cnt].referral_list == NULL) {
1671                 goto out;
1672         }
1673
1674         ref->proximity = 0;
1675         ref->ttl = REFERRAL_TTL;
1676         if (*msdfs_proxy != '\0') {
1677                 ref->alternate_path = talloc_strdup(ctx,
1678                                                 msdfs_proxy);
1679         } else {
1680                 ref->alternate_path = talloc_asprintf(ctx,
1681                         "\\\\%s\\%s",
1682                         get_local_machine_name(),
1683                         service_name);
1684         }
1685
1686         if (!ref->alternate_path) {
1687                 goto out;
1688         }
1689         cnt++;
1690
1691         /* Don't enumerate if we're an msdfs proxy. */
1692         if (*msdfs_proxy != '\0') {
1693                 goto out;
1694         }
1695
1696         /* Now enumerate all dfs links */
1697         dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1698         if(!dirp) {
1699                 goto out;
1700         }
1701
1702         while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1703                != NULL) {
1704                 char *link_target = NULL;
1705                 if (cnt >= jn_remain) {
1706                         DEBUG(2, ("form_junctions: ran out of MSDFS "
1707                                 "junction slots"));
1708                         TALLOC_FREE(talloced);
1709                         goto out;
1710                 }
1711                 if (is_msdfs_link_internal(ctx,
1712                                         conn,
1713                                         dname, &link_target,
1714                                         NULL)) {
1715                         if (parse_msdfs_symlink(ctx,
1716                                         link_target,
1717                                         &jucn[cnt].referral_list,
1718                                         &jucn[cnt].referral_count)) {
1719
1720                                 jucn[cnt].service_name = talloc_strdup(ctx,
1721                                                                 service_name);
1722                                 jucn[cnt].volume_name = talloc_strdup(ctx,
1723                                                                 dname);
1724                                 if (!jucn[cnt].service_name ||
1725                                                 !jucn[cnt].volume_name) {
1726                                         TALLOC_FREE(talloced);
1727                                         goto out;
1728                                 }
1729                                 jucn[cnt].comment = "";
1730                                 cnt++;
1731                         }
1732                         TALLOC_FREE(link_target);
1733                 }
1734                 TALLOC_FREE(talloced);
1735         }
1736
1737 out:
1738
1739         if (dirp) {
1740                 SMB_VFS_CLOSEDIR(conn,dirp);
1741         }
1742
1743         vfs_ChDir(conn, cwd);
1744         conn_free(conn);
1745         return cnt;
1746 }
1747
1748 struct junction_map *enum_msdfs_links(struct smbd_server_connection *sconn,
1749                                       TALLOC_CTX *ctx, size_t *p_num_jn)
1750 {
1751         struct junction_map *jn = NULL;
1752         int i=0;
1753         size_t jn_count = 0;
1754         int sharecount = 0;
1755
1756         *p_num_jn = 0;
1757         if(!lp_host_msdfs()) {
1758                 return NULL;
1759         }
1760
1761         /* Ensure all the usershares are loaded. */
1762         become_root();
1763         load_registry_shares();
1764         sharecount = load_usershare_shares(sconn);
1765         unbecome_root();
1766
1767         for(i=0;i < sharecount;i++) {
1768                 if(lp_msdfs_root(i)) {
1769                         jn_count += count_dfs_links(ctx, i);
1770                 }
1771         }
1772         if (jn_count == 0) {
1773                 return NULL;
1774         }
1775         jn = talloc_array(ctx,  struct junction_map, jn_count);
1776         if (!jn) {
1777                 return NULL;
1778         }
1779         for(i=0; i < sharecount; i++) {
1780                 if (*p_num_jn >= jn_count) {
1781                         break;
1782                 }
1783                 if(lp_msdfs_root(i)) {
1784                         *p_num_jn += form_junctions(ctx, i,
1785                                         &jn[*p_num_jn],
1786                                         jn_count - *p_num_jn);
1787                 }
1788         }
1789         return jn;
1790 }
1791
1792 /******************************************************************************
1793  Core function to resolve a dfs pathname possibly containing a wildcard.  If
1794  ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1795  detected during dfs resolution.
1796 ******************************************************************************/
1797
1798 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1799                                 connection_struct *conn,
1800                                 bool dfs_pathnames,
1801                                 const char *name_in,
1802                                 bool allow_wcards,
1803                                 char **pp_name_out,
1804                                 bool *ppath_contains_wcard)
1805 {
1806         bool path_contains_wcard;
1807         NTSTATUS status = NT_STATUS_OK;
1808
1809         if (dfs_pathnames) {
1810                 status = dfs_redirect(ctx,
1811                                         conn,
1812                                         name_in,
1813                                         allow_wcards,
1814                                         !smbd_server_conn->using_smb2,
1815                                         pp_name_out,
1816                                         &path_contains_wcard);
1817
1818                 if (NT_STATUS_IS_OK(status) && ppath_contains_wcard != NULL) {
1819                         *ppath_contains_wcard = path_contains_wcard;
1820                 }
1821         } else {
1822                 /*
1823                  * Cheat and just return a copy of the in ptr.
1824                  * Once srvstr_get_path() uses talloc it'll
1825                  * be a talloced ptr anyway.
1826                  */
1827                 *pp_name_out = discard_const_p(char, name_in);
1828         }
1829         return status;
1830 }