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