auth: Generate a human readable Authentication log message.
[amitay/samba.git] / source3 / modules / vfs_xattr_tdb.c
index 5c105b5194d161eadba60b3baf1a731762a88957..b32fbc1e9eb1047dea4baef324ecc1bcf3e2ca3c 100644 (file)
@@ -2,6 +2,7 @@
  * Store posix-level xattrs in a tdb
  *
  * Copyright (C) Volker Lendecke, 2007
+ * Copyright (C) Andrew Bartlett, 2012
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_VFS
 
+static bool xattr_tdb_init(int snum, TALLOC_CTX *mem_ctx, struct db_context **p_db);
+
+static int xattr_tdb_get_file_id(struct vfs_handle_struct *handle,
+                               const char *path, struct file_id *id)
+{
+       int ret;
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct smb_filename *smb_fname;
+
+       smb_fname = synthetic_smb_fname(frame, path, NULL, NULL, 0);
+       if (smb_fname == NULL) {
+               TALLOC_FREE(frame);
+               errno = ENOMEM;
+               return -1;
+       }
+
+       ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
+
+       if (ret == -1) {
+               TALLOC_FREE(frame); 
+               return -1;
+       }
+
+       *id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &smb_fname->st);
+       TALLOC_FREE(frame);
+       return 0;
+}
+
 static ssize_t xattr_tdb_getxattr(struct vfs_handle_struct *handle,
                                  const char *path, const char *name,
                                  void *value, size_t size)
 {
-       SMB_STRUCT_STAT sbuf;
        struct file_id id;
        struct db_context *db;
        ssize_t xattr_size;
+       int ret;
        DATA_BLOB blob;
        TALLOC_CTX *frame = talloc_stackframe();
-       if (!frame) {
-               errno = ENOMEM;
-               return -1;
-       }
 
-       SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+       SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
+                               if (!xattr_tdb_init(-1, frame, &db))
+                               {
+                                       TALLOC_FREE(frame); return -1;
+                               });
 
-       if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
+       ret = xattr_tdb_get_file_id(handle, path, &id);
+       if (ret == -1) {
                TALLOC_FREE(frame);
                return -1;
        }
 
-       id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
-
        xattr_size = xattr_tdb_getattr(db, frame, &id, name, &blob);
        if (xattr_size < 0) {
+               errno = ENOATTR;
                TALLOC_FREE(frame);
                return -1;
        }
@@ -61,7 +90,8 @@ static ssize_t xattr_tdb_getxattr(struct vfs_handle_struct *handle,
                errno = ERANGE;
                return -1;
        }
-       memcpy(value, blob.data, size);
+       memcpy(value, blob.data, xattr_size);
+       TALLOC_FREE(frame);
        return xattr_size;
 }
 
@@ -75,22 +105,23 @@ static ssize_t xattr_tdb_fgetxattr(struct vfs_handle_struct *handle,
        ssize_t xattr_size;
        DATA_BLOB blob;
        TALLOC_CTX *frame = talloc_stackframe();
-       if (!frame) {
-               errno = ENOMEM;
-               return -1;
-       }
 
-       SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+       SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
+                               if (!xattr_tdb_init(-1, frame, &db))
+                               {
+                                       TALLOC_FREE(frame); return -1;
+                               });
 
-       if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
+       if (SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf) == -1) {
                TALLOC_FREE(frame);
                return -1;
        }
 
-       id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
+       id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &sbuf);
 
        xattr_size = xattr_tdb_getattr(db, frame, &id, name, &blob);
        if (xattr_size < 0) {
+               errno = ENOATTR;
                TALLOC_FREE(frame);
                return -1;
        }
@@ -99,7 +130,7 @@ static ssize_t xattr_tdb_fgetxattr(struct vfs_handle_struct *handle,
                errno = ERANGE;
                return -1;
        }
-       memcpy(value, blob.data, size);
+       memcpy(value, blob.data, xattr_size);
        TALLOC_FREE(frame);
        return xattr_size;
 }
@@ -108,19 +139,26 @@ static int xattr_tdb_setxattr(struct vfs_handle_struct *handle,
                              const char *path, const char *name,
                              const void *value, size_t size, int flags)
 {
-       SMB_STRUCT_STAT sbuf;
        struct file_id id;
        struct db_context *db;
+       int ret;
+       TALLOC_CTX *frame = talloc_stackframe();
 
-       SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+       SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
+                               if (!xattr_tdb_init(-1, frame, &db))
+                               {
+                                       TALLOC_FREE(frame); return -1;
+                               });
 
-       if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
+       ret = xattr_tdb_get_file_id(handle, path, &id);
+       if (ret == -1) {
+               TALLOC_FREE(frame);
                return -1;
        }
 
-       id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
-
-       return xattr_tdb_setattr(db, &id, name, value, size, flags);
+       ret = xattr_tdb_setattr(db, &id, name, value, size, flags);
+       TALLOC_FREE(frame);
+       return ret;
 }
 
 static int xattr_tdb_fsetxattr(struct vfs_handle_struct *handle,
@@ -131,34 +169,52 @@ static int xattr_tdb_fsetxattr(struct vfs_handle_struct *handle,
        SMB_STRUCT_STAT sbuf;
        struct file_id id;
        struct db_context *db;
+       int ret;
+       TALLOC_CTX *frame = talloc_stackframe();
 
-       SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+       SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
+                               if (!xattr_tdb_init(-1, frame, &db))
+                               {
+                                       TALLOC_FREE(frame); return -1;
+                               });
 
-       if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
+       if (SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf) == -1) {
+               TALLOC_FREE(frame);
                return -1;
        }
 
-       id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
+       id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &sbuf);
+
+       ret = xattr_tdb_setattr(db, &id, name, value, size, flags);
+       TALLOC_FREE(frame);
+       return ret;
 
-       return xattr_tdb_setattr(db, &id, name, value, size, flags);
 }
 
 static ssize_t xattr_tdb_listxattr(struct vfs_handle_struct *handle,
                                   const char *path, char *list, size_t size)
 {
-       SMB_STRUCT_STAT sbuf;
        struct file_id id;
        struct db_context *db;
+       int ret;
+       TALLOC_CTX *frame = talloc_stackframe();
 
-       SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+       SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
+                               if (!xattr_tdb_init(-1, frame, &db))
+                               {
+                                       TALLOC_FREE(frame); return -1;
+                               });
 
-       if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
+       ret = xattr_tdb_get_file_id(handle, path, &id);
+       if (ret == -1) {
+               TALLOC_FREE(frame);
                return -1;
        }
 
-       id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
+       ret = xattr_tdb_listattr(db, &id, list, size);
+       TALLOC_FREE(frame);
+       return ret;
 
-       return xattr_tdb_listattr(db, &id, list, size);
 }
 
 static ssize_t xattr_tdb_flistxattr(struct vfs_handle_struct *handle,
@@ -168,34 +224,51 @@ static ssize_t xattr_tdb_flistxattr(struct vfs_handle_struct *handle,
        SMB_STRUCT_STAT sbuf;
        struct file_id id;
        struct db_context *db;
+       int ret;
+       TALLOC_CTX *frame = talloc_stackframe();
 
-       SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+       SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
+                               if (!xattr_tdb_init(-1, frame, &db))
+                               {
+                                       TALLOC_FREE(frame); return -1;
+                               });
 
-       if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
+       if (SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf) == -1) {
+               TALLOC_FREE(frame);
                return -1;
        }
 
-       id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
+       id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &sbuf);
 
-       return xattr_tdb_listattr(db, &id, list, size);
+       ret = xattr_tdb_listattr(db, &id, list, size);
+       TALLOC_FREE(frame);
+       return ret;
 }
 
 static int xattr_tdb_removexattr(struct vfs_handle_struct *handle,
                                 const char *path, const char *name)
 {
-       SMB_STRUCT_STAT sbuf;
        struct file_id id;
        struct db_context *db;
+       int ret;
+       TALLOC_CTX *frame = talloc_stackframe();
 
-       SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+       SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
+                               if (!xattr_tdb_init(-1, frame, &db))
+                               {
+                                       TALLOC_FREE(frame); return -1;
+                               });
 
-       if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
-               return -1;
+       ret = xattr_tdb_get_file_id(handle, path, &id);
+       if (ret == -1) {
+               TALLOC_FREE(frame);
+               return ret;
        }
 
-       id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
-
-       return xattr_tdb_removeattr(db, &id, name);
+       
+       ret = xattr_tdb_removeattr(db, &id, name);
+       TALLOC_FREE(frame);
+       return ret;
 }
 
 static int xattr_tdb_fremovexattr(struct vfs_handle_struct *handle,
@@ -204,23 +277,32 @@ static int xattr_tdb_fremovexattr(struct vfs_handle_struct *handle,
        SMB_STRUCT_STAT sbuf;
        struct file_id id;
        struct db_context *db;
+       int ret;
+       TALLOC_CTX *frame = talloc_stackframe();
 
-       SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+       SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
+                               if (!xattr_tdb_init(-1, frame, &db))
+                               {
+                                       TALLOC_FREE(frame); return -1;
+                               });
 
-       if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
+       if (SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf) == -1) {
+               TALLOC_FREE(frame);
                return -1;
        }
 
-       id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
+       id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &sbuf);
 
-       return xattr_tdb_removeattr(db, &id, name);
+       ret = xattr_tdb_removeattr(db, &id, name);
+       TALLOC_FREE(frame);
+       return ret;
 }
 
 /*
  * Open the tdb file upon VFS_CONNECT
  */
 
-static bool xattr_tdb_init(int snum, struct db_context **p_db)
+static bool xattr_tdb_init(int snum, TALLOC_CTX *mem_ctx, struct db_context **p_db)
 {
        struct db_context *db;
        const char *dbname;
@@ -238,7 +320,7 @@ static bool xattr_tdb_init(int snum, struct db_context **p_db)
 
        become_root();
        db = db_open(NULL, dbname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600,
-                    DBWRAP_LOCK_ORDER_2);
+                    DBWRAP_LOCK_ORDER_2, DBWRAP_FLAG_NONE);
        unbecome_root();
 
        if (db == NULL) {
@@ -256,6 +338,105 @@ static bool xattr_tdb_init(int snum, struct db_context **p_db)
        return true;
 }
 
+static int xattr_tdb_open(vfs_handle_struct *handle,
+                       struct smb_filename *smb_fname,
+                       files_struct *fsp,
+                       int flags,
+                       mode_t mode)
+{
+       struct db_context *db = NULL;
+       TALLOC_CTX *frame = NULL;
+       int ret;
+
+       fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle,
+                               smb_fname, fsp,
+                               flags,
+                               mode);
+
+       if (fsp->fh->fd < 0) {
+               return fsp->fh->fd;
+       }
+
+       if ((flags & (O_CREAT|O_EXCL)) != (O_CREAT|O_EXCL)) {
+               return fsp->fh->fd;
+       }
+
+       /*
+        * We know we used O_CREAT|O_EXCL and it worked.
+        * We must have created the file.
+        */
+
+       ret = SMB_VFS_FSTAT(fsp, &smb_fname->st);
+       if (ret == -1) {
+               /* Can't happen... */
+               DBG_WARNING("SMB_VFS_FSTAT failed on file %s (%s)\n",
+                       smb_fname_str_dbg(smb_fname),
+                       strerror(errno));
+               return -1;
+       }
+       fsp->file_id = SMB_VFS_FILE_ID_CREATE(fsp->conn, &smb_fname->st);
+
+       frame = talloc_stackframe();
+       SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
+                               if (!xattr_tdb_init(-1, frame, &db))
+                               {
+                                       TALLOC_FREE(frame); return -1;
+                               });
+
+       xattr_tdb_remove_all_attrs(db, &fsp->file_id);
+       TALLOC_FREE(frame);
+       return fsp->fh->fd;
+}
+
+static int xattr_tdb_mkdir(vfs_handle_struct *handle,
+               const struct smb_filename *smb_fname,
+               mode_t mode)
+{
+       struct db_context *db = NULL;
+       TALLOC_CTX *frame = NULL;
+       struct file_id fileid;
+       int ret;
+       struct smb_filename *smb_fname_tmp = NULL;
+
+       ret = SMB_VFS_NEXT_MKDIR(handle, smb_fname, mode);
+       if (ret < 0) {
+               return ret;
+       }
+
+       frame = talloc_stackframe();
+       smb_fname_tmp = cp_smb_filename(frame, smb_fname);
+       if (smb_fname_tmp == NULL) {
+               TALLOC_FREE(frame);
+               errno = ENOMEM;
+               return -1;
+       }
+
+       /* Always use LSTAT here - we just creaded the directory. */
+       ret = SMB_VFS_LSTAT(handle->conn, smb_fname_tmp);
+       if (ret == -1) {
+               /* Rename race. Let upper level take care of it. */
+               TALLOC_FREE(frame);
+               return -1;
+       }
+       if (!S_ISDIR(smb_fname_tmp->st.st_ex_mode)) {
+               /* Rename race. Let upper level take care of it. */
+               TALLOC_FREE(frame);
+               return -1;
+       }
+
+       fileid = SMB_VFS_FILE_ID_CREATE(handle->conn, &smb_fname_tmp->st);
+
+       SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
+                               if (!xattr_tdb_init(-1, frame, &db))
+                               {
+                                       TALLOC_FREE(frame); return -1;
+                               });
+
+       xattr_tdb_remove_all_attrs(db, &fileid);
+       TALLOC_FREE(frame);
+       return 0;
+}
+
 /*
  * On unlink we need to delete the tdb record
  */
@@ -265,22 +446,27 @@ static int xattr_tdb_unlink(vfs_handle_struct *handle,
        struct smb_filename *smb_fname_tmp = NULL;
        struct file_id id;
        struct db_context *db;
-       NTSTATUS status;
        int ret = -1;
        bool remove_record = false;
+       TALLOC_CTX *frame = talloc_stackframe();
 
-       SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+       SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
+                               if (!xattr_tdb_init(-1, frame, &db))
+                               {
+                                       TALLOC_FREE(frame); return -1;
+                               });
 
-       status = copy_smb_filename(talloc_tos(), smb_fname, &smb_fname_tmp);
-       if (!NT_STATUS_IS_OK(status)) {
-               errno = map_errno_from_nt_status(status);
+       smb_fname_tmp = cp_smb_filename(frame, smb_fname);
+       if (smb_fname_tmp == NULL) {
+               TALLOC_FREE(frame);
+               errno = ENOMEM;
                return -1;
        }
 
-       if (lp_posix_pathnames()) {
-               ret = SMB_VFS_LSTAT(handle->conn, smb_fname_tmp);
+       if (smb_fname_tmp->flags & SMB_FILENAME_POSIX_PATH) {
+               ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_tmp);
        } else {
-               ret = SMB_VFS_STAT(handle->conn, smb_fname_tmp);
+               ret = SMB_VFS_NEXT_STAT(handle, smb_fname_tmp);
        }
        if (ret == -1) {
                goto out;
@@ -301,41 +487,52 @@ static int xattr_tdb_unlink(vfs_handle_struct *handle,
                goto out;
        }
 
-       id = SMB_VFS_FILE_ID_CREATE(handle->conn, &smb_fname_tmp->st);
+       id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &smb_fname_tmp->st);
 
        xattr_tdb_remove_all_attrs(db, &id);
 
  out:
-       TALLOC_FREE(smb_fname_tmp);
+       TALLOC_FREE(frame);
        return ret;
 }
 
 /*
  * On rmdir we need to delete the tdb record
  */
-static int xattr_tdb_rmdir(vfs_handle_struct *handle, const char *path)
+static int xattr_tdb_rmdir(vfs_handle_struct *handle,
+                       const struct smb_filename *smb_fname)
 {
        SMB_STRUCT_STAT sbuf;
        struct file_id id;
        struct db_context *db;
        int ret;
+       TALLOC_CTX *frame = talloc_stackframe();
 
-       SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+       SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
+                               if (!xattr_tdb_init(-1, frame, &db))
+                               {
+                                       TALLOC_FREE(frame); return -1;
+                               });
 
-       if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
+       if (vfs_stat_smb_basename(handle->conn,
+                               smb_fname,
+                               &sbuf) == -1) {
+               TALLOC_FREE(frame);
                return -1;
        }
 
-       ret = SMB_VFS_NEXT_RMDIR(handle, path);
+       ret = SMB_VFS_NEXT_RMDIR(handle, smb_fname);
 
        if (ret == -1) {
+               TALLOC_FREE(frame);
                return -1;
        }
 
-       id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
+       id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &sbuf);
 
        xattr_tdb_remove_all_attrs(db, &id);
 
+       TALLOC_FREE(frame);
        return 0;
 }
 
@@ -369,7 +566,7 @@ static int xattr_tdb_connect(vfs_handle_struct *handle, const char *service,
                return 0;
        }
 
-       if (!xattr_tdb_init(snum, &db)) {
+       if (!xattr_tdb_init(snum, NULL, &db)) {
                DEBUG(5, ("Could not init xattr tdb\n"));
                lp_do_parameter(snum, "ea support", "False");
                return 0;
@@ -392,6 +589,8 @@ static struct vfs_fn_pointers vfs_xattr_tdb_fns = {
        .flistxattr_fn = xattr_tdb_flistxattr,
        .removexattr_fn = xattr_tdb_removexattr,
        .fremovexattr_fn = xattr_tdb_fremovexattr,
+       .open_fn = xattr_tdb_open,
+       .mkdir_fn = xattr_tdb_mkdir,
        .unlink_fn = xattr_tdb_unlink,
        .rmdir_fn = xattr_tdb_rmdir,
        .connect_fn = xattr_tdb_connect,