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