smbd: add create_conn_struct_tos[_cwd]() helper functions
[kai/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         struct connection_struct *conn;
1086         char *targetpath = NULL;
1087         int snum;
1088         NTSTATUS status = NT_STATUS_NOT_FOUND;
1089         bool dummy;
1090         struct dfs_path *pdp = talloc(ctx, struct dfs_path);
1091         struct smb_filename *oldcwd_fname = NULL;
1092
1093         if (!pdp) {
1094                 return NT_STATUS_NO_MEMORY;
1095         }
1096
1097         *self_referralp = False;
1098
1099         status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1100                                 pdp, &dummy);
1101         if (!NT_STATUS_IS_OK(status)) {
1102                 return status;
1103         }
1104
1105         jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1106         jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1107         if (!jucn->service_name || !jucn->volume_name) {
1108                 TALLOC_FREE(pdp);
1109                 return NT_STATUS_NO_MEMORY;
1110         }
1111
1112         /* Verify the share is a dfs root */
1113         snum = lp_servicenumber(jucn->service_name);
1114         if(snum < 0) {
1115                 char *service_name = NULL;
1116                 if ((snum = find_service(ctx, jucn->service_name, &service_name)) < 0) {
1117                         return NT_STATUS_NOT_FOUND;
1118                 }
1119                 if (!service_name) {
1120                         return NT_STATUS_NO_MEMORY;
1121                 }
1122                 TALLOC_FREE(jucn->service_name);
1123                 jucn->service_name = talloc_strdup(ctx, service_name);
1124                 if (!jucn->service_name) {
1125                         TALLOC_FREE(pdp);
1126                         return NT_STATUS_NO_MEMORY;
1127                 }
1128         }
1129
1130         if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(talloc_tos(), snum) == '\0')) {
1131                 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
1132                         "a dfs root.\n",
1133                         pdp->servicename, dfs_path));
1134                 TALLOC_FREE(pdp);
1135                 return NT_STATUS_NOT_FOUND;
1136         }
1137
1138         /*
1139          * Self referrals are tested with a anonymous IPC connection and
1140          * a GET_DFS_REFERRAL call to \\server\share. (which means
1141          * dp.reqpath[0] points to an empty string). create_conn_struct cd's
1142          * into the directory and will fail if it cannot (as the anonymous
1143          * user). Cope with this.
1144          */
1145
1146         if (pdp->reqpath[0] == '\0') {
1147                 char *tmp;
1148                 struct referral *ref;
1149                 int refcount;
1150
1151                 if (*lp_msdfs_proxy(talloc_tos(), snum) == '\0') {
1152                         TALLOC_FREE(pdp);
1153                         return self_ref(ctx,
1154                                         dfs_path,
1155                                         jucn,
1156                                         consumedcntp,
1157                                         self_referralp);
1158                 }
1159
1160                 /*
1161                  * It's an msdfs proxy share. Redirect to
1162                  * the configured target share.
1163                  */
1164
1165                 tmp = talloc_asprintf(talloc_tos(), "msdfs:%s",
1166                                       lp_msdfs_proxy(talloc_tos(), snum));
1167                 if (tmp == NULL) {
1168                         TALLOC_FREE(pdp);
1169                         return NT_STATUS_NO_MEMORY;
1170                 }
1171
1172                 if (!parse_msdfs_symlink(ctx, snum, tmp, &ref, &refcount)) {
1173                         TALLOC_FREE(tmp);
1174                         TALLOC_FREE(pdp);
1175                         return NT_STATUS_INVALID_PARAMETER;
1176                 }
1177                 TALLOC_FREE(tmp);
1178                 jucn->referral_count = refcount;
1179                 jucn->referral_list = ref;
1180                 *consumedcntp = strlen(dfs_path);
1181                 TALLOC_FREE(pdp);
1182                 return NT_STATUS_OK;
1183         }
1184
1185         status = create_conn_struct_cwd(ctx,
1186                                         server_event_context(),
1187                                         server_messaging_context(),
1188                                         &conn,
1189                                         snum,
1190                                         lp_path(talloc_tos(), snum),
1191                                         NULL,
1192                                         &oldcwd_fname);
1193         if (!NT_STATUS_IS_OK(status)) {
1194                 TALLOC_FREE(pdp);
1195                 return status;
1196         }
1197
1198         /*
1199          * TODO
1200          *
1201          * The remote and local address should be passed down to
1202          * create_conn_struct_cwd.
1203          */
1204         if (conn->sconn->remote_address == NULL) {
1205                 conn->sconn->remote_address =
1206                         tsocket_address_copy(remote_address, conn->sconn);
1207                 if (conn->sconn->remote_address == NULL) {
1208                         TALLOC_FREE(pdp);
1209                         return NT_STATUS_NO_MEMORY;
1210                 }
1211         }
1212         if (conn->sconn->local_address == NULL) {
1213                 conn->sconn->local_address =
1214                         tsocket_address_copy(local_address, conn->sconn);
1215                 if (conn->sconn->local_address == NULL) {
1216                         TALLOC_FREE(pdp);
1217                         return NT_STATUS_NO_MEMORY;
1218                 }
1219         }
1220
1221         /* If this is a DFS path dfs_lookup should return
1222          * NT_STATUS_PATH_NOT_COVERED. */
1223
1224         status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
1225                                  0, consumedcntp, &targetpath);
1226
1227         if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
1228                 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
1229                         dfs_path));
1230                 if (NT_STATUS_IS_OK(status)) {
1231                         /*
1232                          * We are in an error path here (we
1233                          * know it's not a DFS path), but
1234                          * dfs_path_lookup() can return
1235                          * NT_STATUS_OK. Ensure we always
1236                          * return a valid error code.
1237                          *
1238                          * #9588 - ACLs are not inherited to directories
1239                          *         for DFS shares.
1240                          */
1241                         status = NT_STATUS_NOT_FOUND;
1242                 }
1243                 goto err_exit;
1244         }
1245
1246         /* We know this is a valid dfs link. Parse the targetpath. */
1247         if (!parse_msdfs_symlink(ctx, snum, targetpath,
1248                                 &jucn->referral_list,
1249                                 &jucn->referral_count)) {
1250                 DEBUG(3,("get_referred_path: failed to parse symlink "
1251                         "target %s\n", targetpath ));
1252                 status = NT_STATUS_NOT_FOUND;
1253                 goto err_exit;
1254         }
1255
1256         status = NT_STATUS_OK;
1257  err_exit:
1258         vfs_ChDir(conn, oldcwd_fname);
1259         TALLOC_FREE(oldcwd_fname);
1260         SMB_VFS_DISCONNECT(conn);
1261         conn_free(conn);
1262         TALLOC_FREE(pdp);
1263         return status;
1264 }
1265
1266 /******************************************************************
1267  Set up the DFS referral for the dfs pathname. This call returns
1268  the amount of the path covered by this server, and where the
1269  client should be redirected to. This is the meat of the
1270  TRANS2_GET_DFS_REFERRAL call.
1271 ******************************************************************/
1272
1273 int setup_dfs_referral(connection_struct *orig_conn,
1274                         const char *dfs_path,
1275                         int max_referral_level,
1276                         char **ppdata, NTSTATUS *pstatus)
1277 {
1278         char *pdata = *ppdata;
1279         int reply_size = 0;
1280         struct dfs_GetDFSReferral *r;
1281         DATA_BLOB blob = data_blob_null;
1282         NTSTATUS status;
1283         enum ndr_err_code ndr_err;
1284
1285         r = talloc_zero(talloc_tos(), struct dfs_GetDFSReferral);
1286         if (r == NULL) {
1287                 *pstatus = NT_STATUS_NO_MEMORY;
1288                 return -1;
1289         }
1290
1291         r->in.req.max_referral_level = max_referral_level;
1292         r->in.req.servername = talloc_strdup(r, dfs_path);
1293         if (r->in.req.servername == NULL) {
1294                 talloc_free(r);
1295                 *pstatus = NT_STATUS_NO_MEMORY;
1296                 return -1;
1297         }
1298
1299         status = SMB_VFS_GET_DFS_REFERRALS(orig_conn, r);
1300         if (!NT_STATUS_IS_OK(status)) {
1301                 talloc_free(r);
1302                 *pstatus = status;
1303                 return -1;
1304         }
1305
1306         ndr_err = ndr_push_struct_blob(&blob, r,
1307                                 r->out.resp,
1308                                 (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
1309         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1310                 TALLOC_FREE(r);
1311                 *pstatus = NT_STATUS_INVALID_PARAMETER;
1312                 return -1;
1313         }
1314
1315         pdata = (char *)SMB_REALLOC(pdata, blob.length);
1316         if(pdata == NULL) {
1317                 TALLOC_FREE(r);
1318                 DEBUG(0,("referral setup:"
1319                          "malloc failed for Realloc!\n"));
1320                 return -1;
1321         }
1322         *ppdata = pdata;
1323         reply_size = blob.length;
1324         memcpy(pdata, blob.data, blob.length);
1325         TALLOC_FREE(r);
1326
1327         *pstatus = NT_STATUS_OK;
1328         return reply_size;
1329 }
1330
1331 /**********************************************************************
1332  The following functions are called by the NETDFS RPC pipe functions
1333  **********************************************************************/
1334
1335 /*********************************************************************
1336  Creates a junction structure from a DFS pathname
1337 **********************************************************************/
1338
1339 bool create_junction(TALLOC_CTX *ctx,
1340                 const char *dfs_path,
1341                 bool allow_broken_path,
1342                 struct junction_map *jucn)
1343 {
1344         int snum;
1345         bool dummy;
1346         struct dfs_path *pdp = talloc(ctx,struct dfs_path);
1347         NTSTATUS status;
1348
1349         if (!pdp) {
1350                 return False;
1351         }
1352         status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
1353                                 pdp, &dummy);
1354         if (!NT_STATUS_IS_OK(status)) {
1355                 return False;
1356         }
1357
1358         /* check if path is dfs : validate first token */
1359         if (!is_myname_or_ipaddr(pdp->hostname)) {
1360                 DEBUG(4,("create_junction: Invalid hostname %s "
1361                         "in dfs path %s\n",
1362                         pdp->hostname, dfs_path));
1363                 TALLOC_FREE(pdp);
1364                 return False;
1365         }
1366
1367         /* Check for a non-DFS share */
1368         snum = lp_servicenumber(pdp->servicename);
1369
1370         if(snum < 0 || !lp_msdfs_root(snum)) {
1371                 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1372                         pdp->servicename));
1373                 TALLOC_FREE(pdp);
1374                 return False;
1375         }
1376
1377         jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1378         jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1379         jucn->comment = lp_comment(ctx, snum);
1380
1381         TALLOC_FREE(pdp);
1382         if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1383                 return False;
1384         }
1385         return True;
1386 }
1387
1388 /**********************************************************************
1389  Forms a valid Unix pathname from the junction
1390  **********************************************************************/
1391
1392 static bool junction_to_local_path(const struct junction_map *jucn,
1393                                    char **pp_path_out,
1394                                    connection_struct **conn_out,
1395                                    struct smb_filename **oldpath_fname)
1396 {
1397         int snum;
1398         NTSTATUS status;
1399
1400         snum = lp_servicenumber(jucn->service_name);
1401         if(snum < 0) {
1402                 return False;
1403         }
1404         status = create_conn_struct_cwd(talloc_tos(),
1405                                         server_event_context(),
1406                                         server_messaging_context(),
1407                                         conn_out,
1408                                         snum,
1409                                         lp_path(talloc_tos(), snum),
1410                                         NULL,
1411                                         oldpath_fname);
1412         if (!NT_STATUS_IS_OK(status)) {
1413                 return False;
1414         }
1415
1416         *pp_path_out = talloc_asprintf(*conn_out,
1417                         "%s/%s",
1418                         lp_path(talloc_tos(), snum),
1419                         jucn->volume_name);
1420         if (!*pp_path_out) {
1421                 vfs_ChDir(*conn_out, *oldpath_fname);
1422                 SMB_VFS_DISCONNECT(*conn_out);
1423                 conn_free(*conn_out);
1424                 return False;
1425         }
1426         return True;
1427 }
1428
1429 bool create_msdfs_link(const struct junction_map *jucn)
1430 {
1431         char *path = NULL;
1432         struct smb_filename *cwd_fname = NULL;
1433         char *msdfs_link = NULL;
1434         connection_struct *conn;
1435         int i=0;
1436         bool insert_comma = False;
1437         bool ret = False;
1438         struct smb_filename *smb_fname = NULL;
1439
1440         if(!junction_to_local_path(jucn, &path, &conn, &cwd_fname)) {
1441                 return False;
1442         }
1443
1444         /* Form the msdfs_link contents */
1445         msdfs_link = talloc_strdup(conn, "msdfs:");
1446         if (!msdfs_link) {
1447                 goto out;
1448         }
1449         for(i=0; i<jucn->referral_count; i++) {
1450                 char *refpath = jucn->referral_list[i].alternate_path;
1451
1452                 /* Alternate paths always use Windows separators. */
1453                 trim_char(refpath, '\\', '\\');
1454                 if(*refpath == '\0') {
1455                         if (i == 0) {
1456                                 insert_comma = False;
1457                         }
1458                         continue;
1459                 }
1460                 if (i > 0 && insert_comma) {
1461                         msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1462                                         ",%s",
1463                                         refpath);
1464                 } else {
1465                         msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1466                                         "%s",
1467                                         refpath);
1468                 }
1469
1470                 if (!msdfs_link) {
1471                         goto out;
1472                 }
1473                 if (!insert_comma) {
1474                         insert_comma = True;
1475                 }
1476         }
1477
1478         DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1479                 path, msdfs_link));
1480
1481         smb_fname = synthetic_smb_fname(talloc_tos(),
1482                                 path,
1483                                 NULL,
1484                                 NULL,
1485                                 0);
1486         if (smb_fname == NULL) {
1487                 errno = ENOMEM;
1488                 goto out;
1489         }
1490
1491         if(SMB_VFS_SYMLINK(conn, msdfs_link, smb_fname) < 0) {
1492                 if (errno == EEXIST) {
1493                         if(SMB_VFS_UNLINK(conn, smb_fname)!=0) {
1494                                 TALLOC_FREE(smb_fname);
1495                                 goto out;
1496                         }
1497                 }
1498                 if (SMB_VFS_SYMLINK(conn, msdfs_link, smb_fname) < 0) {
1499                         DEBUG(1,("create_msdfs_link: symlink failed "
1500                                  "%s -> %s\nError: %s\n",
1501                                  path, msdfs_link, strerror(errno)));
1502                         goto out;
1503                 }
1504         }
1505
1506         ret = True;
1507
1508 out:
1509         TALLOC_FREE(smb_fname);
1510         vfs_ChDir(conn, cwd_fname);
1511         TALLOC_FREE(cwd_fname);
1512         SMB_VFS_DISCONNECT(conn);
1513         conn_free(conn);
1514         return ret;
1515 }
1516
1517 bool remove_msdfs_link(const struct junction_map *jucn)
1518 {
1519         char *path = NULL;
1520         struct smb_filename *cwd_fname = NULL;
1521         connection_struct *conn;
1522         bool ret = False;
1523         struct smb_filename *smb_fname;
1524
1525         if (!junction_to_local_path(jucn, &path, &conn, &cwd_fname)) {
1526                 return false;
1527         }
1528
1529         smb_fname = synthetic_smb_fname(talloc_tos(),
1530                                         path,
1531                                         NULL,
1532                                         NULL,
1533                                         0);
1534         if (smb_fname == NULL) {
1535                 errno = ENOMEM;
1536                 return false;
1537         }
1538
1539         if( SMB_VFS_UNLINK(conn, smb_fname) == 0 ) {
1540                 ret = True;
1541         }
1542
1543         TALLOC_FREE(smb_fname);
1544         vfs_ChDir(conn, cwd_fname);
1545         TALLOC_FREE(cwd_fname);
1546         SMB_VFS_DISCONNECT(conn);
1547         conn_free(conn);
1548         return ret;
1549 }
1550
1551 /*********************************************************************
1552  Return the number of DFS links at the root of this share.
1553 *********************************************************************/
1554
1555 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1556 {
1557         size_t cnt = 0;
1558         DIR *dirp = NULL;
1559         const char *dname = NULL;
1560         char *talloced = NULL;
1561         const char *connect_path = lp_path(talloc_tos(), snum);
1562         const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum);
1563         connection_struct *conn;
1564         NTSTATUS status;
1565         struct smb_filename *cwd_fname = NULL;
1566         struct smb_filename *smb_fname = NULL;
1567
1568         if(*connect_path == '\0') {
1569                 return 0;
1570         }
1571
1572         /*
1573          * Fake up a connection struct for the VFS layer.
1574          */
1575
1576         status = create_conn_struct_cwd(talloc_tos(),
1577                                         server_event_context(),
1578                                         server_messaging_context(),
1579                                         &conn,
1580                                         snum,
1581                                         connect_path,
1582                                         NULL,
1583                                         &cwd_fname);
1584         if (!NT_STATUS_IS_OK(status)) {
1585                 DEBUG(3, ("create_conn_struct failed: %s\n",
1586                           nt_errstr(status)));
1587                 return 0;
1588         }
1589
1590         /* Count a link for the msdfs root - convention */
1591         cnt = 1;
1592
1593         /* No more links if this is an msdfs proxy. */
1594         if (*msdfs_proxy != '\0') {
1595                 goto out;
1596         }
1597
1598         smb_fname = synthetic_smb_fname(talloc_tos(),
1599                                         ".",
1600                                         NULL,
1601                                         NULL,
1602                                         0);
1603         if (smb_fname == NULL) {
1604                 goto out;
1605         }
1606
1607         /* Now enumerate all dfs links */
1608         dirp = SMB_VFS_OPENDIR(conn, smb_fname, NULL, 0);
1609         if(!dirp) {
1610                 goto out;
1611         }
1612
1613         while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1614                != NULL) {
1615                 struct smb_filename *smb_dname =
1616                         synthetic_smb_fname(talloc_tos(),
1617                                         dname,
1618                                         NULL,
1619                                         NULL,
1620                                         0);
1621                 if (smb_dname == NULL) {
1622                         goto out;
1623                 }
1624                 if (is_msdfs_link(conn, smb_dname)) {
1625                         cnt++;
1626                 }
1627                 TALLOC_FREE(talloced);
1628                 TALLOC_FREE(smb_dname);
1629         }
1630
1631         SMB_VFS_CLOSEDIR(conn,dirp);
1632
1633 out:
1634         TALLOC_FREE(smb_fname);
1635         vfs_ChDir(conn, cwd_fname);
1636         TALLOC_FREE(cwd_fname);
1637         SMB_VFS_DISCONNECT(conn);
1638         conn_free(conn);
1639         return cnt;
1640 }
1641
1642 /*********************************************************************
1643 *********************************************************************/
1644
1645 static int form_junctions(TALLOC_CTX *ctx,
1646                                 int snum,
1647                                 struct junction_map *jucn,
1648                                 size_t jn_remain)
1649 {
1650         size_t cnt = 0;
1651         DIR *dirp = NULL;
1652         const char *dname = NULL;
1653         char *talloced = NULL;
1654         const char *connect_path = lp_path(talloc_tos(), snum);
1655         char *service_name = lp_servicename(talloc_tos(), snum);
1656         const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum);
1657         connection_struct *conn;
1658         struct referral *ref = NULL;
1659         struct smb_filename *cwd_fname = NULL;
1660         struct smb_filename *smb_fname = NULL;
1661         NTSTATUS status;
1662
1663         if (jn_remain == 0) {
1664                 return 0;
1665         }
1666
1667         if(*connect_path == '\0') {
1668                 return 0;
1669         }
1670
1671         /*
1672          * Fake up a connection struct for the VFS layer.
1673          */
1674
1675         status = create_conn_struct_cwd(ctx,
1676                                         server_event_context(),
1677                                         server_messaging_context(),
1678                                         &conn,
1679                                         snum,
1680                                         connect_path,
1681                                         NULL,
1682                                         &cwd_fname);
1683         if (!NT_STATUS_IS_OK(status)) {
1684                 DEBUG(3, ("create_conn_struct failed: %s\n",
1685                           nt_errstr(status)));
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(talloc_tos(),
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         TALLOC_FREE(smb_fname);
1796         vfs_ChDir(conn, cwd_fname);
1797         TALLOC_FREE(cwd_fname);
1798         conn_free(conn);
1799         return cnt;
1800 }
1801
1802 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1803 {
1804         struct junction_map *jn = NULL;
1805         int i=0;
1806         size_t jn_count = 0;
1807         int sharecount = 0;
1808
1809         *p_num_jn = 0;
1810         if(!lp_host_msdfs()) {
1811                 return NULL;
1812         }
1813
1814         /* Ensure all the usershares are loaded. */
1815         become_root();
1816         load_registry_shares();
1817         sharecount = load_usershare_shares(NULL, connections_snum_used);
1818         unbecome_root();
1819
1820         for(i=0;i < sharecount;i++) {
1821                 if(lp_msdfs_root(i)) {
1822                         jn_count += count_dfs_links(ctx, i);
1823                 }
1824         }
1825         if (jn_count == 0) {
1826                 return NULL;
1827         }
1828         jn = talloc_array(ctx,  struct junction_map, jn_count);
1829         if (!jn) {
1830                 return NULL;
1831         }
1832         for(i=0; i < sharecount; i++) {
1833                 if (*p_num_jn >= jn_count) {
1834                         break;
1835                 }
1836                 if(lp_msdfs_root(i)) {
1837                         *p_num_jn += form_junctions(ctx, i,
1838                                         &jn[*p_num_jn],
1839                                         jn_count - *p_num_jn);
1840                 }
1841         }
1842         return jn;
1843 }
1844
1845 /******************************************************************************
1846  Core function to resolve a dfs pathname possibly containing a wildcard.  If
1847  ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1848  detected during dfs resolution.
1849 ******************************************************************************/
1850
1851 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1852                                 connection_struct *conn,
1853                                 const char *name_in,
1854                                 uint32_t ucf_flags,
1855                                 bool allow_broken_path,
1856                                 char **pp_name_out,
1857                                 bool *ppath_contains_wcard)
1858 {
1859         bool path_contains_wcard = false;
1860         NTSTATUS status = NT_STATUS_OK;
1861
1862         status = dfs_redirect(ctx,
1863                                 conn,
1864                                 name_in,
1865                                 ucf_flags,
1866                                 allow_broken_path,
1867                                 pp_name_out,
1868                                 &path_contains_wcard);
1869
1870         if (NT_STATUS_IS_OK(status) &&
1871                                 ppath_contains_wcard != NULL &&
1872                                 path_contains_wcard) {
1873                 *ppath_contains_wcard = path_contains_wcard;
1874         }
1875         return status;
1876 }