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