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