smbd: Fix a typo in a few places
[samba.git] / source3 / modules / vfs_expand_msdfs.c
index e2a4a18bf0b3e0dcf3d631864440ffa46b32405a..503ee84e8a4e5483c537c1fd91a185268e483b5f 100644 (file)
  */
 
 #include "includes.h"
+#include "system/filesys.h"
+#include "smbd/smbd.h"
+#include "../librpc/gen_ndr/ndr_netlogon.h"
+#include "smbd/globals.h"
+#include "auth.h"
+#include "../lib/tsocket/tsocket.h"
+#include "msdfs.h"
+#include "source3/lib/substitute.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_VFS
 
-extern userdom_struct current_user_info;
-
 /**********************************************************
   Under mapfile we expect a table of the following format:
 
@@ -37,24 +43,25 @@ extern userdom_struct current_user_info;
   This is to redirect a DFS client to a host close to it.
 ***********************************************************/
 
-static bool read_target_host(const char *mapfile, pstring targethost)
+static char *read_target_host(TALLOC_CTX *ctx, const char *mapfile,
+                             const char *clientaddr)
 {
-       XFILE *f;
-       pstring buf;
+       FILE *f;
+       char buf[1024];
        char *space = buf;
-       bool found = False;
-       
-       f = x_fopen(mapfile, O_RDONLY, 0);
+       bool found = false;
+
+       f = fopen(mapfile, "r");
 
        if (f == NULL) {
                DEBUG(0,("can't open IP map %s. Error %s\n",
                         mapfile, strerror(errno) ));
-               return False;
+               return NULL;
        }
 
        DEBUG(10, ("Scanning mapfile [%s]\n", mapfile));
 
-       while (x_fgets(buf, sizeof(buf), f) != NULL) {
+       while (fgets(buf, sizeof(buf), f) != NULL) {
 
                if ((strlen(buf) > 0) && (buf[strlen(buf)-1] == '\n'))
                        buf[strlen(buf)-1] = '\0';
@@ -70,24 +77,24 @@ static bool read_target_host(const char *mapfile, pstring targethost)
 
                *space = '\0';
 
-               if (strncmp(client_addr(), buf, strlen(buf)) == 0) {
-                       found = True;
+               if (strncmp(clientaddr, buf, strlen(buf)) == 0) {
+                       found = true;
                        break;
                }
        }
 
-       x_fclose(f);
+       fclose(f);
 
-       if (!found)
-               return False;
+       if (!found) {
+               return NULL;
+       }
 
        space += 1;
 
        while (isspace(*space))
                space += 1;
 
-       pstrcpy(targethost, space);
-       return True;
+       return talloc_strdup(ctx, space);
 }
 
 /**********************************************************
@@ -103,94 +110,161 @@ static bool read_target_host(const char *mapfile, pstring targethost)
 
 ***********************************************************/
 
-static bool expand_msdfs_target(connection_struct* conn, pstring target)
+static char *expand_msdfs_target(TALLOC_CTX *ctx,
+                               connection_struct *conn,
+                               char *target)
 {
-       pstring mapfilename;
+       const struct loadparm_substitution *lp_sub =
+               loadparm_s3_global_substitution();
+       char *mapfilename = NULL;
        char *filename_start = strchr_m(target, '@');
-       char *filename_end;
-       int filename_len;
-       pstring targethost;
-       pstring new_target;
+       char *filename_end = NULL;
+       int filename_len = 0;
+       char *targethost = NULL;
+       char *new_target = NULL;
+       char *raddr;
 
        if (filename_start == NULL) {
                DEBUG(10, ("No filename start in %s\n", target));
-               return False;
+               return NULL;
        }
 
        filename_end = strchr_m(filename_start+1, '@');
 
        if (filename_end == NULL) {
                DEBUG(10, ("No filename end in %s\n", target));
-               return False;
+               return NULL;
        }
 
        filename_len = PTR_DIFF(filename_end, filename_start+1);
-       pstrcpy(mapfilename, filename_start+1);
+       mapfilename = talloc_strdup(ctx, filename_start+1);
+       if (!mapfilename) {
+               return NULL;
+       }
        mapfilename[filename_len] = '\0';
 
+       /*
+        * dfs links returned have had '/' characters replaced with '\'.
+        * Return them to '/' so we can have absolute path mapfilenames.
+        */
+       string_replace(mapfilename, '\\', '/');
+
        DEBUG(10, ("Expanding from table [%s]\n", mapfilename));
 
-       if (!read_target_host(mapfilename, targethost)) {
+       raddr = tsocket_address_inet_addr_string(conn->sconn->remote_address,
+                                                ctx);
+       if (raddr == NULL) {
+               return NULL;
+       }
+
+       targethost = read_target_host(ctx, mapfilename, raddr);
+       if (targethost == NULL) {
                DEBUG(1, ("Could not expand target host from file %s\n",
                          mapfilename));
-               return False;
+               return NULL;
        }
 
-       standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
-                             conn->connectpath, conn->gid,
-                             get_current_username(),
-                             current_user_info.domain,
-                             mapfilename, sizeof(mapfilename));
+       targethost = talloc_sub_full(ctx,
+                               lp_servicename(talloc_tos(), lp_sub, SNUM(conn)),
+                               conn->session_info->unix_info->unix_name,
+                               conn->connectpath,
+                               conn->session_info->unix_token->gid,
+                               conn->session_info->unix_info->sanitized_username,
+                               conn->session_info->info->domain_name,
+                               targethost);
 
        DEBUG(10, ("Expanded targethost to %s\n", targethost));
 
+       /* Replace the part between '@...@' */
        *filename_start = '\0';
-       pstrcpy(new_target, target);
-       pstrcat(new_target, targethost);
-       pstrcat(new_target, filename_end+1);
+       new_target = talloc_asprintf(ctx,
+                               "%s%s%s",
+                               target,
+                               targethost,
+                               filename_end+1);
+       if (!new_target) {
+               return NULL;
+       }
 
        DEBUG(10, ("New DFS target: %s\n", new_target));
-       pstrcpy(target, new_target);
-       return True;
+       return new_target;
 }
 
-static int expand_msdfs_readlink(struct vfs_handle_struct *handle,
-                                const char *path, char *buf, size_t bufsiz)
+static NTSTATUS expand_read_dfs_pathat(struct vfs_handle_struct *handle,
+                               TALLOC_CTX *mem_ctx,
+                               struct files_struct *dirfsp,
+                               struct smb_filename *smb_fname,
+                               struct referral **ppreflist,
+                               size_t *preferral_count)
 {
-       pstring target;
-       int result;
-
-       result = SMB_VFS_NEXT_READLINK(handle, path, target,
-                                      sizeof(target));
-
-       if (result < 0)
-               return result;
+       NTSTATUS status;
+       size_t i;
+       struct referral *reflist = NULL;
+       size_t count = 0;
+       TALLOC_CTX *frame = talloc_stackframe();
+
+       /*
+        * Always call the NEXT function first, then
+        * modify the return if needed.
+        */
+       status = SMB_VFS_NEXT_READ_DFS_PATHAT(handle,
+                               mem_ctx,
+                               dirfsp,
+                               smb_fname,
+                               ppreflist,
+                               preferral_count);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(frame);
+               return status;
+       }
 
-       target[result] = '\0';
+       /*
+        * This function can be called to check if a pathname
+        * is an MSDFS link, but not return the values of it.
+        * In this case ppreflist and preferral_count are NULL,
+        * so don't bother trying to look at any returns.
+        */
+       if (ppreflist == NULL || preferral_count == NULL) {
+               TALLOC_FREE(frame);
+               return status;
+       }
 
-       if ((strncmp(target, "msdfs:", strlen("msdfs:")) == 0) &&
-           (strchr_m(target, '@') != NULL)) {
-               if (!expand_msdfs_target(handle->conn, target)) {
-                       errno = ENOENT;
-                       return -1;
+       /*
+        * We are always returning the values returned
+        * returned by the NEXT call, but we might mess
+        * with the reflist[i].alternate_path values,
+        * so use local pointers to minimise indirections.
+        */
+       count = *preferral_count;
+       reflist = *ppreflist;
+
+       for (i = 0; i < count; i++) {
+               if (strchr_m(reflist[i].alternate_path, '@') != NULL) {
+                       char *new_altpath = expand_msdfs_target(frame,
+                                               handle->conn,
+                                               reflist[i].alternate_path);
+                       if (new_altpath == NULL) {
+                               TALLOC_FREE(*ppreflist);
+                               *preferral_count = 0;
+                               TALLOC_FREE(frame);
+                               return NT_STATUS_NO_MEMORY;
+                       }
+                       reflist[i].alternate_path = talloc_move(reflist,
+                                                       &new_altpath);
                }
        }
-
-       safe_strcpy(buf, target, bufsiz-1);
-       return strlen(buf);
+       TALLOC_FREE(frame);
+       return status;
 }
 
-/* VFS operations structure */
-
-static vfs_op_tuple expand_msdfs_ops[] = {     
-       {SMB_VFS_OP(expand_msdfs_readlink), SMB_VFS_OP_READLINK,
-        SMB_VFS_LAYER_TRANSPARENT},
-       {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+static struct vfs_fn_pointers vfs_expand_msdfs_fns = {
+       .read_dfs_pathat_fn = expand_read_dfs_pathat,
 };
 
-NTSTATUS vfs_expand_msdfs_init(void);
-NTSTATUS vfs_expand_msdfs_init(void)
+static_decl_vfs;
+NTSTATUS vfs_expand_msdfs_init(TALLOC_CTX *ctx)
 {
        return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "expand_msdfs",
-                               expand_msdfs_ops);
+                               &vfs_expand_msdfs_fns);
 }