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