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