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