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

Generated by: LCOV version 1.13