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