LCOV - code coverage report
Current view: top level - source3/smbd - msdfs.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 358 794 45.1 %
Date: 2021-09-23 10:06:22 Functions: 14 26 53.8 %

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

Generated by: LCOV version 1.13