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