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