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