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