diff options
Diffstat (limited to 'source3/modules')
-rw-r--r-- | source3/modules/gpfs.c | 29 | ||||
-rw-r--r-- | source3/modules/onefs.h | 68 | ||||
-rw-r--r-- | source3/modules/onefs_acl.c | 119 | ||||
-rw-r--r-- | source3/modules/onefs_open.c | 2153 | ||||
-rw-r--r-- | source3/modules/onefs_system.c | 214 | ||||
-rw-r--r-- | source3/modules/vfs_default.c | 40 | ||||
-rw-r--r-- | source3/modules/vfs_full_audit.c | 64 | ||||
-rw-r--r-- | source3/modules/vfs_gpfs.c | 166 | ||||
-rw-r--r-- | source3/modules/vfs_onefs.c | 27 | ||||
-rw-r--r-- | source3/modules/vfs_prealloc.c | 2 |
10 files changed, 2772 insertions, 110 deletions
diff --git a/source3/modules/gpfs.c b/source3/modules/gpfs.c index 4e76b97ccf..16599005b9 100644 --- a/source3/modules/gpfs.c +++ b/source3/modules/gpfs.c @@ -31,6 +31,8 @@ static int (*gpfs_set_share_fn)(int fd, unsigned int allow, unsigned int deny); static int (*gpfs_set_lease_fn)(int fd, unsigned int leaseType); static int (*gpfs_getacl_fn)(char *pathname, int flags, void *acl); static int (*gpfs_putacl_fn)(char *pathname, int flags, void *acl); +static int (*gpfs_get_realfilename_path_fn)(char *pathname, char *filenamep, + int *buflen); bool set_gpfs_sharemode(files_struct *fsp, uint32 access_mask, @@ -43,7 +45,7 @@ bool set_gpfs_sharemode(files_struct *fsp, uint32 access_mask, if (!gpfs_share_modes) { return True; } - + if (gpfs_set_share_fn == NULL) { return False; } @@ -104,7 +106,7 @@ int set_gpfs_lease(int fd, int leasetype) if (leasetype == F_WRLCK) { gpfs_type = GPFS_LEASE_WRITE; } - + /* we unconditionally set CAP_LEASE, rather than looking for -1/EACCES as there is a bug in some versions of libgpfs_gpl.so which results in a leaked fd on /dev/ss0 @@ -134,6 +136,17 @@ int smbd_gpfs_putacl(char *pathname, int flags, void *acl) return gpfs_putacl_fn(pathname, flags, acl); } +int smbd_gpfs_get_realfilename_path(char *pathname, char *filenamep, + int *buflen) +{ + if (gpfs_get_realfilename_path_fn == NULL) { + errno = ENOSYS; + return -1; + } + + return gpfs_get_realfilename_path_fn(pathname, filenamep, buflen); +} + static bool init_gpfs_function_lib(void *plibhandle_pointer, const char *libname, void *pfn_pointer, const char *fn_name) @@ -142,6 +155,9 @@ static bool init_gpfs_function_lib(void *plibhandle_pointer, void **libhandle_pointer = (void **)plibhandle_pointer; void **fn_pointer = (void **)pfn_pointer; + DEBUG(10, ("trying to load name %s from %s\n", + fn_name, libname)); + if (*libhandle_pointer == NULL) { *libhandle_pointer = dlopen(libname, RTLD_LAZY); did_open_here = true; @@ -187,6 +203,8 @@ void init_gpfs(void) init_gpfs_function(&gpfs_set_lease_fn, "gpfs_set_lease"); init_gpfs_function(&gpfs_getacl_fn, "gpfs_getacl"); init_gpfs_function(&gpfs_putacl_fn, "gpfs_putacl"); + init_gpfs_function(&gpfs_get_realfilename_path_fn, + "gpfs_get_realfilename_path"); gpfs_share_modes = lp_parm_bool(-1, "gpfs", "sharemodes", True); gpfs_leases = lp_parm_bool(-1, "gpfs", "leases", True); @@ -226,6 +244,13 @@ int smbd_gpfs_putacl(char *pathname, int flags, void *acl) return -1; } +int smbd_gpfs_get_realfilename_path(char *pathname, char *fileamep, + int *buflen) +{ + errno = ENOSYS; + return -1; +} + void init_gpfs(void) { return; diff --git a/source3/modules/onefs.h b/source3/modules/onefs.h index 965f39509a..8d0f45abdb 100644 --- a/source3/modules/onefs.h +++ b/source3/modules/onefs.h @@ -21,6 +21,10 @@ #ifndef _ONEFS_H #define _ONEFS_H +#include "includes.h" + +#include <sys/isi_acl.h> + /* OneFS Module smb.conf parameters and defaults */ /** @@ -34,13 +38,6 @@ enum onefs_acl_wire_format ACL_FORMAT_ALWAYS /**< Always canonicalize */ }; -const struct enum_list enum_onefs_acl_wire_format[] = { - {ACL_FORMAT_RAW, "No Format"}, - {ACL_FORMAT_WINDOWS_SD, "Format Windows SD"}, - {ACL_FORMAT_ALWAYS, "Always Format SD"}, - {-1, NULL} -}; - #define PARM_ONEFS_TYPE "onefs" #define PARM_ACL_WIRE_FORMAT "acl wire format" #define PARM_ACL_WIRE_FORMAT_DEFAULT ACL_FORMAT_WINDOWS_SD @@ -49,4 +46,61 @@ const struct enum_list enum_onefs_acl_wire_format[] = { #define PARM_CREATOR_OWNER_GETS_FULL_CONTROL "creator owner gets full control" #define PARM_CREATOR_OWNER_GETS_FULL_CONTROL_DEFAULT true +/* + * vfs interface handlers + */ +NTSTATUS onefs_create_file(vfs_handle_struct *handle, + struct smb_request *req, + uint16_t root_dir_fid, + const char *fname, + uint32_t create_file_flags, + uint32_t access_mask, + uint32_t share_access, + uint32_t create_disposition, + uint32_t create_options, + uint32_t file_attributes, + uint32_t oplock_request, + uint64_t allocation_size, + struct security_descriptor *sd, + struct ea_list *ea_list, + files_struct **result, + int *pinfo, + SMB_STRUCT_STAT *psbuf); + +NTSTATUS onefs_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp, + uint32 security_info, SEC_DESC **ppdesc); + +NTSTATUS onefs_get_nt_acl(vfs_handle_struct *handle, const char* name, + uint32 security_info, SEC_DESC **ppdesc); + +NTSTATUS onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, + uint32 security_info_sent, SEC_DESC *psd); + + +/* + * Utility functions + */ +NTSTATUS onefs_setup_sd(uint32 security_info_sent, SEC_DESC *psd, + struct ifs_security_descriptor *sd); + +/* + * System Interfaces + */ +int onefs_sys_create_file(connection_struct *conn, + int base_fd, + const char *path, + uint32_t access_mask, + uint32_t open_access_mask, + uint32_t share_access, + uint32_t create_options, + int flags, + mode_t mode, + int oplock_request, + uint64_t id, + struct security_descriptor *sd, + uint32_t ntfs_flags, + int *granted_oplock); + + + #endif /* _ONEFS_H */ diff --git a/source3/modules/onefs_acl.c b/source3/modules/onefs_acl.c index 3a692c95ab..5351118a87 100644 --- a/source3/modules/onefs_acl.c +++ b/source3/modules/onefs_acl.c @@ -19,20 +19,23 @@ * along with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "includes.h" +#include "onefs.h" -#include <sys/isi_acl.h> #include <isi_acl/isi_acl_util.h> -#include <sys/isi_oplock.h> #include <ifs/ifs_syscalls.h> -#include "onefs.h" +const struct enum_list enum_onefs_acl_wire_format[] = { + {ACL_FORMAT_RAW, "No Format"}, + {ACL_FORMAT_WINDOWS_SD, "Format Windows SD"}, + {ACL_FORMAT_ALWAYS, "Always Format SD"}, + {-1, NULL} +}; /** * Turn SID into UID/GID and setup a struct ifs_identity */ static bool -onefs_sid_to_identity(DOM_SID *sid, struct ifs_identity *id, bool is_group) +onefs_sid_to_identity(const DOM_SID *sid, struct ifs_identity *id, bool is_group) { enum ifs_identity_type type = IFS_ID_TYPE_LAST+1; uid_t uid = 0; @@ -514,15 +517,22 @@ onefs_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp, if (security_info & SACL_SECURITY_INFORMATION) desired_access |= IFS_RTS_SACL_ACCESS; - if ((fsp->fh->fd = ifs_createfile(-1, - fsp->fsp_name, - desired_access, - 0, 0, - OPLOCK_NONE, - 0, NULL, 0, - NULL, 0, NULL)) == -1) { - DEBUG(0, ("Error opening file %s. errno=%d\n", - fsp->fsp_name, errno)); + if ((fsp->fh->fd = onefs_sys_create_file(handle->conn, + -1, + fsp->fsp_name, + desired_access, + desired_access, + 0, + 0, + 0, + 0, + INTERNAL_OPEN_ONLY, + 0, + NULL, + 0, + NULL)) == -1) { + DEBUG(0, ("Error opening file %s. errno=%d (%s)\n", + fsp->fsp_name, errno, strerror(errno))); status = map_nt_error_from_unix(errno); goto out; } @@ -679,22 +689,18 @@ onefs_get_nt_acl(vfs_handle_struct *handle, const char* name, } /** - * Isilon-specific function for setting an NTFS ACL on an open file. + * Isilon-specific function for setting up an ifs_security_descriptor, given a + * samba SEC_DESC. * - * @return NT_STATUS_UNSUCCESSFUL for userspace errors, NTSTATUS based off - * errno on syscall errors + * @param[out] sd ifs_security_descriptor to fill in + * + * @return NTSTATUS_OK if successful */ -NTSTATUS -onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, - uint32 security_info_sent, SEC_DESC *psd) +NTSTATUS onefs_setup_sd(uint32 security_info_sent, SEC_DESC *psd, + struct ifs_security_descriptor *sd) { - struct ifs_security_descriptor sd = {}; struct ifs_security_acl dacl, sacl, *daclp, *saclp; struct ifs_identity owner, group, *ownerp, *groupp; - int fd; - bool fopened = false; - - DEBUG(5,("Setting SD on file %s.\n", fsp->fsp_name )); ownerp = NULL; groupp = NULL; @@ -759,10 +765,37 @@ onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, /* Setup ifs_security_descriptor */ DEBUG(5,("Setting up SD\n")); - if (aclu_initialize_sd(&sd, psd->type, ownerp, groupp, - (daclp ? &daclp : NULL), (saclp ? &saclp : NULL), false)) + if (aclu_initialize_sd(sd, psd->type, ownerp, groupp, + (daclp ? &daclp : NULL), (saclp ? &saclp : NULL), false)) return NT_STATUS_UNSUCCESSFUL; + return NT_STATUS_OK; +} + +/** + * Isilon-specific function for setting an NTFS ACL on an open file. + * + * @return NT_STATUS_UNSUCCESSFUL for userspace errors, NTSTATUS based off + * errno on syscall errors + */ +NTSTATUS +onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, + uint32 security_info_sent, SEC_DESC *psd) +{ + struct ifs_security_descriptor sd = {}; + int fd; + bool fopened = false; + NTSTATUS status; + + DEBUG(5,("Setting SD on file %s.\n", fsp->fsp_name )); + + status = onefs_setup_sd(security_info_sent, psd, &sd); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(3, ("SD initialization failure: %s", nt_errstr(status))); + return status; + } + fd = fsp->fh->fd; if (fd == -1) { enum ifs_ace_rights desired_access = 0; @@ -775,16 +808,24 @@ onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, if (security_info_sent & SACL_SECURITY_INFORMATION) desired_access |= IFS_RTS_SACL_ACCESS; - if ((fd = ifs_createfile(-1, - fsp->fsp_name, - desired_access, - 0, 0, - OPLOCK_NONE, - 0, NULL, 0, - NULL, 0, NULL)) == -1) { - DEBUG(0, ("Error opening file %s. errno=%d\n", - fsp->fsp_name, errno)); - return map_nt_error_from_unix(errno); + if ((fd = onefs_sys_create_file(handle->conn, + -1, + fsp->fsp_name, + desired_access, + desired_access, + 0, + 0, + 0, + 0, + INTERNAL_OPEN_ONLY, + 0, + NULL, + 0, + NULL)) == -1) { + DEBUG(0, ("Error opening file %s. errno=%d (%s)\n", + fsp->fsp_name, errno, strerror(errno))); + status = map_nt_error_from_unix(errno); + goto out; } fopened = true; } @@ -792,10 +833,12 @@ onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, errno = 0; if (ifs_set_security_descriptor(fd, security_info_sent, &sd)) { DEBUG(0, ("Error setting security descriptor = %d\n", errno)); + status = map_nt_error_from_unix(errno); goto out; } DEBUG(5, ("Security descriptor set correctly!\n")); + status = NT_STATUS_OK; /* FALLTHROUGH */ out: @@ -803,5 +846,5 @@ out: close(fd); aclu_free_sd(&sd, false); - return errno ? map_nt_error_from_unix(errno) : NT_STATUS_OK; + return status; } diff --git a/source3/modules/onefs_open.c b/source3/modules/onefs_open.c new file mode 100644 index 0000000000..d0310d0174 --- /dev/null +++ b/source3/modules/onefs_open.c @@ -0,0 +1,2153 @@ +/* + * Unix SMB/CIFS implementation. + * + * This file began with some code from source3/smbd/open.c and modified it to + * work with ifs_createfile. + * + * ifs_createfile is a CIFS-specific syscall for opening/files and + * directories. It adds support for: + * - Full in-kernel access checks using a windows access_mask + * - Cluster-coherent share mode locks + * - Cluster-coherent oplocks + * - Streams + * - Setting security descriptors at create time + * - Setting dos_attributes at create time + * + * Copyright (C) Andrew Tridgell 1992-1998 + * Copyright (C) Jeremy Allison 2001-2004 + * Copyright (C) Volker Lendecke 2005 + * Copyright (C) Tim Prouty, 2008 + * + * 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "onefs.h" + +extern const struct generic_mapping file_generic_mapping; +extern bool global_client_failed_oplock_break; + +struct deferred_open_record { + bool delayed_for_oplocks; + bool failed; /* added for onefs_oplocks */ + struct file_id id; +}; + +static NTSTATUS onefs_create_file_unixpath(connection_struct *conn, + struct smb_request *req, + const char *fname, + uint32_t access_mask, + uint32_t share_access, + uint32_t create_disposition, + uint32_t create_options, + uint32_t file_attributes, + uint32_t oplock_request, + uint64_t allocation_size, + struct security_descriptor *sd, + struct ea_list *ea_list, + + files_struct **result, + int *pinfo, + SMB_STRUCT_STAT *psbuf); + +/**************************************************************************** + Open a file. +****************************************************************************/ + +static NTSTATUS onefs_open_file(files_struct *fsp, + connection_struct *conn, + struct smb_request *req, + const char *parent_dir, + const char *name, + const char *path, + SMB_STRUCT_STAT *psbuf, + int flags, + mode_t unx_mode, + uint32 access_mask, + uint32 open_access_mask, + int oplock_request, + uint64 id, + uint32 share_access, + uint32 create_options, + uint32_t new_dos_attributes, + struct security_descriptor *sd, + int *granted_oplock) +{ + NTSTATUS status = NT_STATUS_OK; + int accmode = (flags & O_ACCMODE); + int local_flags = flags; + bool file_existed = VALID_STAT(*psbuf); + const char *wild; + + fsp->fh->fd = -1; + errno = EPERM; + + /* Check permissions */ + + /* + * This code was changed after seeing a client open request + * containing the open mode of (DENY_WRITE/read-only) with + * the 'create if not exist' bit set. The previous code + * would fail to open the file read only on a read-only share + * as it was checking the flags parameter directly against O_RDONLY, + * this was failing as the flags parameter was set to O_RDONLY|O_CREAT. + * JRA. + */ + + if (!CAN_WRITE(conn)) { + /* It's a read-only share - fail if we wanted to write. */ + if(accmode != O_RDONLY) { + DEBUG(3,("Permission denied opening %s\n", path)); + return NT_STATUS_ACCESS_DENIED; + } else if(flags & O_CREAT) { + /* We don't want to write - but we must make sure that + O_CREAT doesn't create the file if we have write + access into the directory. + */ + flags &= ~O_CREAT; + local_flags &= ~O_CREAT; + } + } + + /* + * This little piece of insanity is inspired by the + * fact that an NT client can open a file for O_RDONLY, + * but set the create disposition to FILE_EXISTS_TRUNCATE. + * If the client *can* write to the file, then it expects to + * truncate the file, even though it is opening for readonly. + * Quicken uses this stupid trick in backup file creation... + * Thanks *greatly* to "David W. Chapman Jr." <dwcjr@inethouston.net> + * for helping track this one down. It didn't bite us in 2.0.x + * as we always opened files read-write in that release. JRA. + */ + + if ((accmode == O_RDONLY) && ((flags & O_TRUNC) == O_TRUNC)) { + DEBUG(10,("onefs_open_file: truncate requested on read-only " + "open for file %s\n", path)); + local_flags = (flags & ~O_ACCMODE)|O_RDWR; + } + +#if defined(O_NONBLOCK) && defined(S_ISFIFO) + /* + * We would block on opening a FIFO with no one else on the + * other end. Do what we used to do and add O_NONBLOCK to the + * open flags. JRA. + */ + + if (file_existed && S_ISFIFO(psbuf->st_mode)) { + local_flags |= O_NONBLOCK; + } +#endif + + /* Don't create files with Microsoft wildcard characters. */ + if (fsp->base_fsp) { + /* + * wildcard characters are allowed in stream names + * only test the basefilename + */ + wild = fsp->base_fsp->fsp_name; + } else { + wild = path; + } + if ((local_flags & O_CREAT) && !file_existed && + ms_has_wild(wild)) { + /* + * XXX: may need to remvoe this return... + * + * We dont think this check needs to exist. All it does is + * block creating files with Microsoft wildcards, which is + * fine if the creation originated from NFS or locally and + * then was copied via Samba. + */ + DEBUG(1, ("onefs_open_file: creating file with wildcard: %s\n", + path)); + return NT_STATUS_OBJECT_NAME_INVALID; + } + + /* Actually do the open */ + +#ifdef O_NOFOLLOW + /* + * Never follow symlinks on a POSIX client. The + * client should be doing this. + */ + + if (fsp->posix_open || !lp_symlinks(SNUM(conn))) { + flags |= O_NOFOLLOW; + } +#endif + /* Don't request an oplock if oplocks are turned off for the + * share. */ + if (!lp_oplocks(SNUM(conn))) + oplock_request = 0; + + fsp->fh->fd = onefs_sys_create_file(conn, + -1, + path, + access_mask, + open_access_mask, + share_access, + create_options, + flags, + unx_mode, + oplock_request, + id, + sd, + new_dos_attributes, + granted_oplock); + + if (fsp->fh->fd == -1) { + if (errno == EMFILE) { + static time_t last_warned = 0L; + + if (time((time_t *) NULL) > last_warned) { + DEBUG(0, ("Too many open files, unable " + "to open more! smbd's max " + "open files = %d, also check " + "sysctl kern.maxfiles and " + "sysctl kern.maxfilesperproc\n", + lp_max_open_files())); + last_warned = time((time_t *) NULL); + } + } + + status = map_nt_error_from_unix(errno); + DEBUG(3,("Error opening file %s (%s) (local_flags=%d) " + "(flags=%d)\n", + path,nt_errstr(status),local_flags,flags)); + return status; + } + + if ((local_flags & O_CREAT) && !file_existed) { + + /* Inherit the ACL if required */ + if (lp_inherit_perms(SNUM(conn))) { + inherit_access_posix_acl(conn, parent_dir, path, + unx_mode); + } + + /* Change the owner if required. */ + if (lp_inherit_owner(SNUM(conn))) { + change_file_owner_to_parent(conn, parent_dir, + fsp); + } + + notify_fname(conn, NOTIFY_ACTION_ADDED, + FILE_NOTIFY_CHANGE_FILE_NAME, path); + } + + if (!file_existed) { + int ret; + + if (fsp->fh->fd == -1) { + ret = SMB_VFS_STAT(conn, path, psbuf); + } else { + ret = SMB_VFS_FSTAT(fsp, psbuf); + /* If we have an fd, this stat should succeed. */ + if (ret == -1) { + DEBUG(0,("Error doing fstat on open file %s " + "(%s)\n", path,strerror(errno) )); + } + } + + /* For a non-io open, this stat failing means file not found. JRA */ + if (ret == -1) { + status = map_nt_error_from_unix(errno); + fd_close(fsp); + return status; + } + } + + /* + * POSIX allows read-only opens of directories. We don't + * want to do this (we use a different code path for this) + * so catch a directory open and return an EISDIR. JRA. + */ + + if(S_ISDIR(psbuf->st_mode)) { + fd_close(fsp); + errno = EISDIR; + return NT_STATUS_FILE_IS_A_DIRECTORY; + } + + fsp->mode = psbuf->st_mode; + fsp->file_id = vfs_file_id_from_sbuf(conn, psbuf); + fsp->vuid = req ? req->vuid : UID_FIELD_INVALID; + fsp->file_pid = req ? req->smbpid : 0; + fsp->can_lock = True; + fsp->can_read = (access_mask & (FILE_READ_DATA)) ? True : False; + if (!CAN_WRITE(conn)) { + fsp->can_write = False; + } else { + fsp->can_write = (access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) ? + True : False; + } + fsp->print_file = False; + fsp->modified = False; + fsp->sent_oplock_break = NO_BREAK_SENT; + fsp->is_directory = False; + if (conn->aio_write_behind_list && + is_in_path(path, conn->aio_write_behind_list, conn->case_sensitive)) { + fsp->aio_write_behind = True; + } + + string_set(&fsp->fsp_name, path); + fsp->wcp = NULL; /* Write cache pointer. */ + + DEBUG(2,("%s opened file %s read=%s write=%s (numopen=%d)\n", + conn->server_info->unix_name, + fsp->fsp_name, + BOOLSTR(fsp->can_read), BOOLSTR(fsp->can_write), + conn->num_files_open)); + + errno = 0; + return NT_STATUS_OK; +} + +/**************************************************************************** + Handle the 1 second delay in returning a SHARING_VIOLATION error. +****************************************************************************/ + +static void defer_open(struct share_mode_lock *lck, + struct timeval request_time, + struct timeval timeout, + struct smb_request *req, + struct deferred_open_record *state) +{ + int i; + + /* Paranoia check */ + + for (i=0; i<lck->num_share_modes; i++) { + struct share_mode_entry *e = &lck->share_modes[i]; + + if (!is_deferred_open_entry(e)) { + continue; + } + + if (procid_is_me(&e->pid) && (e->op_mid == req->mid)) { + DEBUG(0, ("Trying to defer an already deferred " + "request: mid=%d, exiting\n", req->mid)); + exit_server("attempt to defer a deferred request"); + } + } + + /* End paranoia check */ + + DEBUG(10,("defer_open_sharing_error: time [%u.%06u] adding deferred " + "open entry for mid %u\n", + (unsigned int)request_time.tv_sec, + (unsigned int)request_time.tv_usec, + (unsigned int)req->mid)); + + if (!push_deferred_smb_message(req, request_time, timeout, + (char *)state, sizeof(*state))) { + exit_server("push_deferred_smb_message failed"); + } + add_deferred_open(lck, req->mid, request_time, state->id); + + /* + * Push the MID of this packet on the signing queue. + * We only do this once, the first time we push the packet + * onto the deferred open queue, as this has a side effect + * of incrementing the response sequence number. + */ + + srv_defer_sign_response(req->mid); +} + +static void schedule_defer_open(struct share_mode_lock *lck, + struct timeval request_time, + struct smb_request *req) +{ + struct deferred_open_record state; + + /* This is a relative time, added to the absolute + request_time value to get the absolute timeout time. + Note that if this is the second or greater time we enter + this codepath for this particular request mid then + request_time is left as the absolute time of the *first* + time this request mid was processed. This is what allows + the request to eventually time out. */ + + struct timeval timeout; + + /* Normally the smbd we asked should respond within + * OPLOCK_BREAK_TIMEOUT seconds regardless of whether + * the client did, give twice the timeout as a safety + * measure here in case the other smbd is stuck + * somewhere else. */ + + timeout = timeval_set(OPLOCK_BREAK_TIMEOUT*2, 0); + + /* Nothing actually uses state.delayed_for_oplocks + but it's handy to differentiate in debug messages + between a 30 second delay due to oplock break, and + a 1 second delay for share mode conflicts. */ + + state.delayed_for_oplocks = True; + state.failed = False; + state.id = lck->id; + + if (!request_timed_out(request_time, timeout)) { + defer_open(lck, request_time, timeout, req, &state); + } +} + +/**************************************************************************** + Open a file with a share mode. Passed in an already created files_struct. +****************************************************************************/ +NTSTATUS onefs_open_file_ntcreate(connection_struct *conn, + struct smb_request *req, + const char *fname, + uint32 access_mask, + uint32 share_access, + uint32 create_disposition, + uint32 create_options, + uint32 new_dos_attributes, + int oplock_request, + struct security_descriptor *sd, + files_struct *fsp, + int *pinfo, + SMB_STRUCT_STAT *psbuf) +{ + int flags=0; + int flags2=0; + bool file_existed = VALID_STAT(*psbuf); + bool def_acl = False; + bool posix_open = False; + bool new_file_created = False; + struct file_id id; + mode_t new_unx_mode = (mode_t)0; + mode_t unx_mode = (mode_t)0; + int info; + uint32 existing_dos_attributes = 0; + struct pending_message_list *pml = NULL; + struct timeval request_time = timeval_zero(); + struct share_mode_lock *lck = NULL; + uint32 open_access_mask = access_mask; + NTSTATUS status; + int ret_flock; + char *parent_dir; + const char *newname; + int granted_oplock; + uint64 oplock_waiter; + uint32 createfile_attributes = 0; + + ZERO_STRUCT(id); + + if (conn->printer) { + /* + * Printers are handled completely differently. + * Most of the passed parameters are ignored. + */ + + if (pinfo) { + *pinfo = FILE_WAS_CREATED; + } + + DEBUG(10, ("onefs_open_file_ntcreate: printer open fname=%s\n", + fname)); + + return print_fsp_open(req, conn, fname, req->vuid, fsp); + } + + if (!parent_dirname_talloc(talloc_tos(), fname, &parent_dir, + &newname)) { + return NT_STATUS_NO_MEMORY; + } + + if (new_dos_attributes & FILE_FLAG_POSIX_SEMANTICS) { + posix_open = True; + unx_mode = (mode_t)(new_dos_attributes & ~FILE_FLAG_POSIX_SEMANTICS); + new_dos_attributes = 0; + } else { + /* We add aARCH to this as this mode is only used if the file is + * created new. */ + unx_mode = unix_mode(conn, new_dos_attributes | aARCH, fname, + parent_dir); + } + + DEBUG(10,("onefs_open_file_ntcreate: fname=%s, dos_attrs=0x%x " + "access_mask=0x%x share_access=0x%x " + "create_disposition = 0x%x create_options=0x%x " + "unix mode=0%o oplock_request=0x%x\n", + fname, new_dos_attributes, access_mask, share_access, + create_disposition, create_options, unx_mode, + oplock_request)); + + if ((req == NULL) && ((oplock_request & INTERNAL_OPEN_ONLY) == 0)) { + DEBUG(0, ("No smb request but not an internal only open!\n")); + return NT_STATUS_INTERNAL_ERROR; + } + + /* + * Only non-internal opens can be deferred at all + */ + + if ((req != NULL) + && ((pml = get_open_deferred_message(req->mid)) != NULL)) { + struct deferred_open_record *state = + (struct deferred_open_record *)pml->private_data.data; + + /* Remember the absolute time of the original + request with this mid. We'll use it later to + see if this has timed out. */ + + request_time = pml->request_time; + + /* Remove the deferred open entry under lock. */ + lck = get_share_mode_lock(talloc_tos(), state->id, NULL, NULL, + NULL); + if (lck == NULL) { + DEBUG(0, ("could not get share mode lock\n")); + } else { + del_deferred_open_entry(lck, req->mid); + TALLOC_FREE(lck); + } + + /* Ensure we don't reprocess this message. */ + remove_deferred_open_smb_message(req->mid); + + /* + * When receiving a semlock_async_failure message, the + * deferred open will be marked as "failed". Returning + * INTERNAL_ERROR. + */ + if (state->failed) { + DEBUG(0, ("onefs_open_file_ntcreate: " + "semlock_async_failure detected!\n")); + return NT_STATUS_INTERNAL_ERROR; + } + } + + status = check_name(conn, fname); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (!posix_open) { + new_dos_attributes &= SAMBA_ATTRIBUTES_MASK; + if (file_existed) { + existing_dos_attributes = dos_mode(conn, fname, psbuf); + } + } + + /* Setup dos_attributes to be set by ifs_createfile */ + if (lp_store_dos_attributes(SNUM(conn))) { + createfile_attributes = (new_dos_attributes | aARCH) & + ~(FILE_ATTRIBUTE_NONINDEXED | FILE_ATTRIBUTE_COMPRESSED); + } + + /* Ignore oplock requests if oplocks are disabled. */ + if (!lp_oplocks(SNUM(conn)) || global_client_failed_oplock_break || + IS_VETO_OPLOCK_PATH(conn, fname)) { + /* Mask off everything except the private Samba bits. */ + oplock_request &= SAMBA_PRIVATE_OPLOCK_MASK; + } + + /* this is for OS/2 long file names - say we don't support them */ + if (!lp_posix_pathnames() && strstr(fname,".+,;=[].")) { + /* OS/2 Workplace shell fix may be main code stream in a later + * release. */ + DEBUG(5,("onefs_open_file_ntcreate: OS/2 long filenames are " + "not supported.\n")); + if (use_nt_status()) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + return NT_STATUS_DOS(ERRDOS, ERRcannotopen); + } + + switch( create_disposition ) { + /* + * Currently we're using FILE_SUPERSEDE as the same as + * FILE_OVERWRITE_IF but they really are + * different. FILE_SUPERSEDE deletes an existing file + * (requiring delete access) then recreates it. + */ + case FILE_SUPERSEDE: + /* If file exists replace/overwrite. If file doesn't + * exist create. */ + /** + * @todo: Clear all file attributes? + * http://www.osronline.com/article.cfm?article=302 + * create if not exist, trunc if exist + * + * If file exists replace/overwrite. If file doesn't + * exist create. + */ + flags2 |= (O_CREAT | O_TRUNC); + break; + + case FILE_OVERWRITE_IF: + /* If file exists replace/overwrite. If file doesn't + * exist create. */ + flags2 |= (O_CREAT | O_TRUNC); + break; + + case FILE_OPEN: + /* If file exists open. If file doesn't exist error. */ + if (!file_existed) { + DEBUG(5,("onefs_open_file_ntcreate: FILE_OPEN " + "requested for file %s and file " + "doesn't exist.\n", fname )); + errno = ENOENT; + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + break; + + case FILE_OVERWRITE: + /* If file exists overwrite. If file doesn't exist + * error. */ + if (!file_existed) { + DEBUG(5, ("onefs_open_file_ntcreate: " + "FILE_OVERWRITE requested for file " + "%s and file doesn't exist.\n", + fname)); + errno = ENOENT; + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + flags2 |= O_TRUNC; + break; + + case FILE_CREATE: + /* If file exists error. If file doesn't exist + * create. */ + if (file_existed) { + DEBUG(5, ("onefs_open_file_ntcreate: " + "FILE_CREATE requested for file %s " + "and file already exists.\n", + fname)); + if (S_ISDIR(psbuf->st_mode)) { + errno = EISDIR; + } else { + errno = EEXIST; + } + return map_nt_error_from_unix(errno); + } + flags2 |= (O_CREAT|O_EXCL); + break; + + case FILE_OPEN_IF: + /* If file exists open. If file doesn't exist + * create. */ + flags2 |= O_CREAT; + break; + + default: + return NT_STATUS_INVALID_PARAMETER; + } + + /* Match attributes on file exists and overwrite. */ + if (!posix_open && file_existed && + ((create_disposition == FILE_OVERWRITE) || + (create_disposition == FILE_OVERWRITE_IF))) { + if (!open_match_attributes(conn, fname, + existing_dos_attributes, + new_dos_attributes, psbuf->st_mode, + unx_mode, &new_unx_mode)) { + DEBUG(5, ("onefs_open_file_ntcreate: attributes " + "missmatch for file %s (%x %x) (0%o, 0%o)\n", + fname, existing_dos_attributes, + new_dos_attributes, + (unsigned int)psbuf->st_mode, + (unsigned int)unx_mode )); + errno = EACCES; + return NT_STATUS_ACCESS_DENIED; + } + } + + /* + * OneFS understands MAXIMUM_ALLOWED_ACCESS, so only hack the + * access_mask, but leave the MAA for the actual open in + * open_access_mask. + */ + open_access_mask = access_mask; + if (open_access_mask & MAXIMUM_ALLOWED_ACCESS) { + access_mask |= FILE_GENERIC_ALL; + } + + /* Convert GENERIC bits to specific bits. */ + se_map_generic(&access_mask, &file_generic_mapping); + se_map_generic(&open_access_mask, &file_generic_mapping); + + if ((flags2 & O_TRUNC) || (oplock_request & FORCE_OPLOCK_BREAK_TO_NONE)) { + /* This will cause oplock breaks. */ + open_access_mask |= FILE_WRITE_DATA; + } + + DEBUG(10, ("onefs_open_file_ntcreate: fname=%s, after mapping " + "open_access_mask=%#x, access_mask=0x%x\n", + fname, open_access_mask, access_mask)); + + /* + * Note that we ignore the append flag as append does not + * mean the same thing under DOS and Unix. + */ + + if ((access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) || + (oplock_request & FORCE_OPLOCK_BREAK_TO_NONE)) { + + /* + * DENY_DOS opens are always underlying read-write on the + * file handle, no matter what the requested access mask + * says. Stock samba just sets the flags, but since + * ifs_createfile uses the access_mask, it must be updated as + * well. This allows BASE-DENY* to pass. + */ + if (create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS) { + + DEBUG(10,("onefs_open_file_ntcreate: deny_dos: " + "Adding O_RDWR to flags " + "(0x%x) and some READ bits to " + "open_access_mask (0x%x)\n", + flags, open_access_mask)); + + flags = O_RDWR; + open_access_mask |= (FILE_READ_ATTRIBUTES | + FILE_READ_DATA | FILE_READ_EA | FILE_EXECUTE); + + } else if (access_mask & (FILE_READ_ATTRIBUTES | + FILE_READ_DATA | + FILE_READ_EA | + FILE_EXECUTE)) { + flags = O_RDWR; + } else { + flags = O_WRONLY; + } + } else { + flags = O_RDONLY; + } + + /* Currently we only look at FILE_WRITE_THROUGH for create options. */ +#if defined(O_SYNC) + if ((create_options & FILE_WRITE_THROUGH) && + lp_strict_sync(SNUM(conn))) { + flags2 |= O_SYNC; + } +#endif /* O_SYNC */ + + if (posix_open && (access_mask & FILE_APPEND_DATA)) { + flags2 |= O_APPEND; + } + + if (!posix_open && !CAN_WRITE(conn)) { + /* + * We should really return a permission denied error if either + * O_CREAT or O_TRUNC are set, but for compatibility with + * older versions of Samba we just AND them out. + */ + flags2 &= ~(O_CREAT|O_TRUNC); + + /** + * XXX: TODO + * Apparently this is necessary because we ship with + * lp_acl_check_permissions = no. It is set to no because our + * ifs_createfile does the access check correctly. This check + * was added in the last merge, and the question is why is it + * necessary? Check out Bug 25547 and Bug 14596. The key is + * to figure out what case this is covering, and do some + * testing to see if it's actually necessary. If it is, maybe + * it should go upstream in open.c. + */ + if (!lp_acl_check_permissions(SNUM(conn)) && + (access_mask & DELETE_ACCESS)) { + return map_nt_error_from_unix(EACCES); + } + } + + /* Ensure we can't write on a read-only share or file. */ + if (flags != O_RDONLY && file_existed && + (!CAN_WRITE(conn) || IS_DOS_READONLY(existing_dos_attributes))) { + DEBUG(5, ("onefs_open_file_ntcreate: write access requested " + "for file %s on read only %s\n", + fname, !CAN_WRITE(conn) ? "share" : "file" )); + errno = EACCES; + return NT_STATUS_ACCESS_DENIED; + } + + DEBUG(10, ("fsp = %p\n", fsp)); + + fsp->file_id = vfs_file_id_from_sbuf(conn, psbuf); + fsp->share_access = share_access; + fsp->fh->private_options = create_options; + fsp->access_mask = open_access_mask; /* We change this to the + * requested access_mask after + * the open is done. */ + fsp->posix_open = posix_open; + + /* Ensure no SAMBA_PRIVATE bits can be set. */ + fsp->oplock_type = (oplock_request & ~SAMBA_PRIVATE_OPLOCK_MASK); + + if (timeval_is_zero(&request_time)) { + request_time = fsp->open_time; + } + + if (file_existed) { + struct timespec old_write_time = get_mtimespec(psbuf); + id = vfs_file_id_from_sbuf(conn, psbuf); + + lck = get_share_mode_lock(talloc_tos(), id, + conn->connectpath, + fname, &old_write_time); + + if (lck == NULL) { + DEBUG(0, ("Could not get share mode lock\n")); + return NT_STATUS_SHARING_VIOLATION; + } + + if (lck->delete_on_close) { + /* DELETE_PENDING is not deferred for a second */ + TALLOC_FREE(lck); + return NT_STATUS_DELETE_PENDING; + } + } + + SMB_ASSERT(!file_existed || (lck != NULL)); + + /* + * Ensure we pay attention to default ACLs on directories. May be + * neccessary depending on ACL policies. + */ + if ((flags2 & O_CREAT) && lp_inherit_acls(SNUM(conn)) && + (def_acl = directory_has_default_acl(conn, parent_dir))) { + unx_mode = 0777; + } + + DEBUG(4,("calling onefs_open_file with flags=0x%X flags2=0x%X " + "mode=0%o, access_mask = 0x%x, open_access_mask = 0x%x\n", + (unsigned int)flags, (unsigned int)flags2, + (unsigned int)unx_mode, (unsigned int)access_mask, + (unsigned int)open_access_mask)); + + oplock_waiter = 1; //ifs_oplock_wait_record(mid); + + if (oplock_waiter == 0) { + return NT_STATUS_NO_MEMORY; + } + + /* Do the open. */ + status = onefs_open_file(fsp, + conn, + req, + parent_dir, + newname, + fname, + psbuf, + flags|flags2, + unx_mode, + access_mask, + open_access_mask, + fsp->oplock_type, + oplock_waiter, + share_access, + create_options, + createfile_attributes, + sd, + &granted_oplock); + + if (!NT_STATUS_IS_OK(status)) { + + /* OneFS Oplock Handling */ + if (errno == EINPROGRESS) { + + if (lck == NULL) { + + struct deferred_open_record state; + struct timespec old_write_time; + + old_write_time = get_mtimespec(psbuf); + + DEBUG(3, ("Someone created file %s with an " + "oplock after we looked: Retrying\n", + fname)); + /* + * We hit the race that when we did the stat + * on the file it did not exist, and someone + * has created it in between the stat and the + * open_file() call. Just retry immediately. + */ + id = vfs_file_id_from_sbuf(conn, psbuf); + if (!(lck = get_share_mode_lock(talloc_tos(), + id, conn->connectpath, fname, + &old_write_time))) { + /* + * Emergency exit + */ + DEBUG(0, ("onefs_open_file_ntcreate: " + "Could not get share mode " + "lock for %s\n", fname)); + status = NT_STATUS_SHARING_VIOLATION; + goto cleanup_destroy; + } + + state.delayed_for_oplocks = False; + state.id = id; + + if (req != NULL) { + defer_open(lck, request_time, + timeval_zero(), req, &state); + } + goto cleanup_destroy; + } + /* Waiting for an oplock */ + SMB_ASSERT(req); + schedule_defer_open(lck, request_time, req); + goto cleanup; + } + + /* Check for a sharing violation */ + if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { + uint32 can_access_mask; + bool can_access = True; + + /* Check if this can be done with the deny_dos and fcb + * calls. */ + + /* Try to find dup fsp if possible. */ + if (create_options & + (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS| + NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) { + + if (req == NULL) { + DEBUG(0, ("DOS open without an SMB " + "request!\n")); + status = NT_STATUS_INTERNAL_ERROR; + goto cleanup_destroy; + } + + /* Use the client requested access mask here, + * not the one we open with. */ + status = fcb_or_dos_open(req, + conn, + fsp, + fname, + id, + req->smbpid, + req->vuid, + access_mask, + share_access, + create_options); + + if (NT_STATUS_IS_OK(status)) { + TALLOC_FREE(lck); + if (pinfo) { + *pinfo = FILE_WAS_OPENED; + } + status = NT_STATUS_OK; + goto cleanup; + } + } + + /* + * This next line is a subtlety we need for + * MS-Access. If a file open will fail due to share + * permissions and also for security (access) reasons, + * we need to return the access failed error, not the + * share error. We can't open the file due to kernel + * oplock deadlock (it's possible we failed above on + * the open_mode_check()) so use a userspace check. + */ + + if (flags & O_RDWR) { + can_access_mask = FILE_READ_DATA|FILE_WRITE_DATA; + } else if (flags & O_WRONLY) { + can_access_mask = FILE_WRITE_DATA; + } else { + can_access_mask = FILE_READ_DATA; + } + + if (((can_access_mask & FILE_WRITE_DATA) && !CAN_WRITE(conn)) || + !can_access_file_data(conn,fname,psbuf,can_access_mask)) { + can_access = False; + } + + /* + * If we're returning a share violation, ensure we + * cope with the braindead 1 second delay. + */ + if (!(oplock_request & INTERNAL_OPEN_ONLY) && + lp_defer_sharing_violations()) { + struct timeval timeout; + struct deferred_open_record state; + int timeout_usecs; + + /* this is a hack to speed up torture tests + in 'make test' */ + timeout_usecs = lp_parm_int(SNUM(conn), + "smbd","sharedelay", + SHARING_VIOLATION_USEC_WAIT); + + /* This is a relative time, added to the + absolute request_time value to get the + absolute timeout time. Note that if this + is the second or greater time we enter this + codepath for this particular request mid + then request_time is left as the absolute + time of the *first* time this request mid + was processed. This is what allows the + request to eventually time out. */ + + timeout = timeval_set(0, timeout_usecs); + + /* Nothing actually uses + state.delayed_for_oplocks but it's handy to + differentiate in debug messages between a + 30 second delay due to oplock break, and a + 1 second delay for share mode conflicts. */ + + state.delayed_for_oplocks = False; + state.id = id; + state.failed = false; + + if ((req != NULL) + && !request_timed_out(request_time, + timeout)) { + defer_open(lck, request_time, timeout, + req, &state); + } + } + + if (can_access) { + /* + * We have detected a sharing violation here + * so return the correct error code + */ + status = NT_STATUS_SHARING_VIOLATION; + } else { + status = NT_STATUS_ACCESS_DENIED; + } + + goto cleanup_destroy; + } + + /* + * Normal error, for example EACCES + */ + cleanup_destroy: + //destroy_ifs_callback_record(oplock_waiter); + cleanup: + TALLOC_FREE(lck); + return status; + } + + fsp->oplock_type = granted_oplock; + + /* XXX uncomment for oplocks */ + //ifs_set_oplock_callback(oplock_waiter, fsp); + //fsp->oplock_callback_id = oplock_waiter; + + if (!file_existed) { + struct timespec old_write_time = get_mtimespec(psbuf); + /* + * Deal with the race condition where two smbd's detect the + * file doesn't exist and do the create at the same time. One + * of them will win and set a share mode, the other (ie. this + * one) should check if the requested share mode for this + * create is allowed. + */ + + /* + * Now the file exists and fsp is successfully opened, + * fsp->dev and fsp->inode are valid and should replace the + * dev=0,inode=0 from a non existent file. Spotted by + * Nadav Danieli <nadavd@exanet.com>. JRA. + */ + + id = fsp->file_id; + + lck = get_share_mode_lock(talloc_tos(), id, + conn->connectpath, + fname, &old_write_time); + + if (lck == NULL) { + DEBUG(0, ("onefs_open_file_ntcreate: Could not get " + "share mode lock for %s\n", fname)); + fd_close(fsp); + return NT_STATUS_SHARING_VIOLATION; + } + + if (lck->delete_on_close) { + status = NT_STATUS_DELETE_PENDING; + } + + if (!NT_STATUS_IS_OK(status)) { + struct deferred_open_record state; + + fd_close(fsp); + + state.delayed_for_oplocks = False; + state.id = id; + + /* Do it all over again immediately. In the second + * round we will find that the file existed and handle + * the DELETE_PENDING and FCB cases correctly. No need + * to duplicate the code here. Essentially this is a + * "goto top of this function", but don't tell + * anybody... */ + + if (req != NULL) { + defer_open(lck, request_time, timeval_zero(), + req, &state); + } + TALLOC_FREE(lck); + return status; + } + + /* + * We exit this block with the share entry *locked*..... + */ + + } + + SMB_ASSERT(lck != NULL); + + /* note that we ignore failure for the following. It is + basically a hack for NFS, and NFS will never set one of + these only read them. Nobody but Samba can ever set a deny + mode and we have already checked our more authoritative + locking database for permission to set this deny mode. If + the kernel refuses the operations then the kernel is wrong. + note that GPFS supports it as well - jmcd */ + + if (fsp->fh->fd != -1) { + ret_flock = SMB_VFS_KERNEL_FLOCK(fsp, share_access); + if(ret_flock == -1 ){ + + TALLOC_FREE(lck); + fd_close(fsp); + return NT_STATUS_SHARING_VIOLATION; + } + } + + /* + * At this point onwards, we can guarentee that the share entry + * is locked, whether we created the file or not, and that the + * deny mode is compatible with all current opens. + */ + + /* Record the options we were opened with. */ + fsp->share_access = share_access; + fsp->fh->private_options = create_options; + /* + * According to Samba4, SEC_FILE_READ_ATTRIBUTE is always granted, + */ + fsp->access_mask = access_mask | FILE_READ_ATTRIBUTES; + + if (file_existed) { + /* stat opens on existing files don't get oplocks. */ + if (is_stat_open(open_access_mask)) { + fsp->oplock_type = NO_OPLOCK; + } + + if (!(flags2 & O_TRUNC)) { + info = FILE_WAS_OPENED; + } else { + info = FILE_WAS_OVERWRITTEN; + } + } else { + info = FILE_WAS_CREATED; + } + + if (pinfo) { + *pinfo = info; + } + + /* + * Setup the oplock info in both the shared memory and + * file structs. + */ + + if ((fsp->oplock_type != NO_OPLOCK) && + (fsp->oplock_type != FAKE_LEVEL_II_OPLOCK)) { + if (!set_file_oplock(fsp, fsp->oplock_type)) { + /* Could not get the kernel oplock */ + fsp->oplock_type = NO_OPLOCK; + } + } + + if (info == FILE_WAS_OVERWRITTEN || info == FILE_WAS_CREATED || + info == FILE_WAS_SUPERSEDED) { + new_file_created = True; + } + + set_share_mode(lck, fsp, conn->server_info->utok.uid, 0, + fsp->oplock_type); + + /* Handle strange delete on close create semantics. */ + if (create_options & FILE_DELETE_ON_CLOSE) { + status = can_set_delete_on_close(fsp, True, new_dos_attributes); + + if (!NT_STATUS_IS_OK(status)) { + /* Remember to delete the mode we just added. */ + del_share_mode(lck, fsp); + TALLOC_FREE(lck); + fd_close(fsp); + return status; + } + /* Note that here we set the *inital* delete on close flag, + not the regular one. The magic gets handled in close. */ + fsp->initial_delete_on_close = True; + } + + /* + * Take care of inherited ACLs on created files - if default ACL not + * selected. + * May be necessary depending on acl policies. + */ + if (!posix_open && !file_existed && !def_acl && !(VALID_STAT(*psbuf) + && (psbuf->st_flags & SF_HASNTFSACL))) { + + int saved_errno = errno; /* We might get ENOSYS in the next + * call.. */ + + if (SMB_VFS_FCHMOD_ACL(fsp, unx_mode) == -1 && + errno == ENOSYS) { + errno = saved_errno; /* Ignore ENOSYS */ + } + + } else if (new_unx_mode) { + + int ret = -1; + + /* Attributes need changing. File already existed. */ + + { + int saved_errno = errno; /* We might get ENOSYS in the + * next call.. */ + ret = SMB_VFS_FCHMOD_ACL(fsp, new_unx_mode); + + if (ret == -1 && errno == ENOSYS) { + errno = saved_errno; /* Ignore ENOSYS */ + } else { + DEBUG(5, ("onefs_open_file_ntcreate: reset " + "attributes of file %s to 0%o\n", + fname, (unsigned int)new_unx_mode)); + ret = 0; /* Don't do the fchmod below. */ + } + } + + if ((ret == -1) && + (SMB_VFS_FCHMOD(fsp, new_unx_mode) == -1)) + DEBUG(5, ("onefs_open_file_ntcreate: failed to reset " + "attributes of file %s to 0%o\n", + fname, (unsigned int)new_unx_mode)); + } + + /* If this is a successful open, we must remove any deferred open + * records. */ + if (req != NULL) { + del_deferred_open_entry(lck, req->mid); + } + TALLOC_FREE(lck); + + return NT_STATUS_OK; +} + + +/**************************************************************************** + Open a directory from an NT SMB call. +****************************************************************************/ +static NTSTATUS onefs_open_directory(connection_struct *conn, + struct smb_request *req, + const char *fname, + uint32 access_mask, + uint32 share_access, + uint32 create_disposition, + uint32 create_options, + uint32 file_attributes, + struct security_descriptor *sd, + files_struct **result, + int *pinfo, + SMB_STRUCT_STAT *psbuf) +{ + files_struct *fsp = NULL; + struct share_mode_lock *lck = NULL; + NTSTATUS status; + struct timespec mtimespec; + int info = 0; + char *parent_dir; + const char *dirname; + bool posix_open = false; + uint32 create_flags = 0; + uint32 mode = lp_dir_mask(SNUM(conn)); + + DEBUG(5, ("onefs_open_directory: opening directory %s, " + "access_mask = 0x%x, " + "share_access = 0x%x create_options = 0x%x, " + "create_disposition = 0x%x, file_attributes = 0x%x\n", + fname, (unsigned int)access_mask, (unsigned int)share_access, + (unsigned int)create_options, (unsigned int)create_disposition, + (unsigned int)file_attributes)); + + if (!(file_attributes & FILE_FLAG_POSIX_SEMANTICS) && + (conn->fs_capabilities & FILE_NAMED_STREAMS) && + is_ntfs_stream_name(fname)) { + DEBUG(2, ("onefs_open_directory: %s is a stream name!\n", fname)); + return NT_STATUS_NOT_A_DIRECTORY; + } + + switch (create_disposition) { + case FILE_OPEN: + /* If directory exists open. If directory doesn't + * exist error. */ + create_flags = 0; + info = FILE_WAS_OPENED; + break; + case FILE_CREATE: + /* If directory exists error. If directory doesn't + * exist create. */ + create_flags = O_CREAT | O_EXCL; + info = FILE_WAS_CREATED; + break; + case FILE_OPEN_IF: + /* If directory exists open. If directory doesn't + * exist create. */ + + /* Note: in order to return whether the directory was + * opened or created, we first try to open and then try + * to create. */ + create_flags = 0; + info = FILE_WAS_OPENED; + break; + case FILE_SUPERSEDE: + case FILE_OVERWRITE: + case FILE_OVERWRITE_IF: + default: + DEBUG(5, ("onefs_open_directory: invalid " + "create_disposition 0x%x for directory %s\n", + (unsigned int)create_disposition, fname)); + return NT_STATUS_INVALID_PARAMETER; + } + + /* + * Check for write access to the share. Done in mkdir_internal() in + * mainline samba. + */ + if (!CAN_WRITE(conn) && (create_flags & O_CREAT)) { + return NT_STATUS_ACCESS_DENIED; + } + + /* Get parent dirname */ + if (!parent_dirname_talloc(talloc_tos(), fname, &parent_dir, + &dirname)) { + return NT_STATUS_NO_MEMORY; + } + + if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) { + posix_open = true; + mode = (mode_t)(file_attributes & ~FILE_FLAG_POSIX_SEMANTICS); + file_attributes = 0; + } else { + mode = unix_mode(conn, aDIR, fname, parent_dir); + } + + /* + * The NONINDEXED and COMPRESSED bits seem to always be cleared on + * directories, no matter if you specify that they should be set. + */ + file_attributes &= + ~(FILE_ATTRIBUTE_NONINDEXED | FILE_ATTRIBUTE_COMPRESSED); + + status = file_new(req, conn, &fsp); + if(!NT_STATUS_IS_OK(status)) { + return status; + } + + /* + * Actual open with retry magic to handle FILE_OPEN_IF which is + * unique because the kernel won't tell us if the file was opened or + * created. + */ + retry_open: + fsp->fh->fd = onefs_sys_create_file(conn, + -1, + fname, + access_mask, + access_mask, + share_access, + create_options, + create_flags | O_DIRECTORY, + mode, + 0, + 0, + sd, + file_attributes, + NULL); + + if (fsp->fh->fd == -1) { + DEBUG(3, ("Error opening %s. Errno=%d (%s).\n", fname, errno, + strerror(errno))); + SMB_ASSERT(errno != EINPROGRESS); + + if (create_disposition == FILE_OPEN_IF) { + if (errno == ENOENT) { + /* Try again, creating it this time. */ + create_flags = O_CREAT | O_EXCL; + info = FILE_WAS_CREATED; + goto retry_open; + } else if (errno == EEXIST) { + /* Uggh. Try again again. */ + create_flags = 0; + info = FILE_WAS_OPENED; + goto retry_open; + } + } + + /* Error cases below: */ + file_free(req, fsp); + + if ((errno == ENOENT) && (create_disposition == FILE_OPEN)) { + DEBUG(5,("onefs_open_directory: FILE_OPEN requested " + "for directory %s and it doesn't " + "exist.\n", fname )); + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } else if ((errno == EEXIST) && + (create_disposition == FILE_CREATE)) { + DEBUG(5,("onefs_open_directory: FILE_CREATE " + "requested for directory %s and it " + "already exists.\n", fname )); + return NT_STATUS_OBJECT_NAME_COLLISION; + } else if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { + /* Catch sharing violations. */ + return NT_STATUS_SHARING_VIOLATION; + } + + return map_nt_error_from_unix(errno); + } + + if (info == FILE_WAS_CREATED) { + + /* Pulled from mkdir_internal() */ + if (SMB_VFS_LSTAT(conn, fname, psbuf) == -1) { + DEBUG(2, ("Could not stat directory '%s' just " + "created: %s\n",fname, strerror(errno))); + return map_nt_error_from_unix(errno); + } + + if (!S_ISDIR(psbuf->st_mode)) { + DEBUG(0, ("Directory just '%s' created is not a " + "directory\n", fname)); + return NT_STATUS_ACCESS_DENIED; + } + + if (!posix_open) { + /* + * Check if high bits should have been set, then (if + * bits are missing): add them. Consider bits + * automagically set by UNIX, i.e. SGID bit from + * parent dir. + */ + if (mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) && + (mode & ~psbuf->st_mode)) { + SMB_VFS_CHMOD(conn, fname, (psbuf->st_mode | + (mode & ~psbuf->st_mode))); + } + } + + /* Change the owner if required. */ + if (lp_inherit_owner(SNUM(conn))) { + change_dir_owner_to_parent(conn, parent_dir, fname, + psbuf); + } + + notify_fname(conn, NOTIFY_ACTION_ADDED, + FILE_NOTIFY_CHANGE_DIR_NAME, fname); + } + + /* Stat the fd for Samba bookkeeping. */ + if(SMB_VFS_FSTAT(fsp, psbuf) != 0) { + fd_close(fsp); + file_free(req, fsp); + return map_nt_error_from_unix(errno); + } + + /* Setup the files_struct for it. */ + fsp->mode = psbuf->st_mode; + fsp->file_id = vfs_file_id_from_sbuf(conn, psbuf); + fsp->vuid = req ? req->vuid : UID_FIELD_INVALID; + fsp->file_pid = req ? req->smbpid : 0; + fsp->can_lock = False; + fsp->can_read = False; + fsp->can_write = False; + + fsp->share_access = share_access; + fsp->fh->private_options = create_options; + /* + * According to Samba4, SEC_FILE_READ_ATTRIBUTE is always granted, + */ + fsp->access_mask = access_mask | FILE_READ_ATTRIBUTES; + fsp->print_file = False; + fsp->modified = False; + fsp->oplock_type = NO_OPLOCK; + fsp->sent_oplock_break = NO_BREAK_SENT; + fsp->is_directory = True; + fsp->posix_open = posix_open; + + string_set(&fsp->fsp_name,fname); + + mtimespec = get_mtimespec(psbuf); + + /* + * Still set the samba share mode lock for correct delete-on-close + * semantics and to make smbstatus more useful. + */ + lck = get_share_mode_lock(talloc_tos(), fsp->file_id, + conn->connectpath, + fname, &mtimespec); + + if (lck == NULL) { + DEBUG(0, ("onefs_open_directory: Could not get share mode " + "lock for %s\n", fname)); + fd_close(fsp); + file_free(req, fsp); + return NT_STATUS_SHARING_VIOLATION; + } + + if (lck->delete_on_close) { + TALLOC_FREE(lck); + fd_close(fsp); + file_free(req, fsp); + return NT_STATUS_DELETE_PENDING; + } + + set_share_mode(lck, fsp, conn->server_info->utok.uid, 0, NO_OPLOCK); + + /* + * For directories the delete on close bit at open time seems + * always to be honored on close... See test 19 in Samba4 BASE-DELETE. + */ + if (create_options & FILE_DELETE_ON_CLOSE) { + status = can_set_delete_on_close(fsp, True, 0); + if (!NT_STATUS_IS_OK(status) && + !NT_STATUS_EQUAL(status, NT_STATUS_DIRECTORY_NOT_EMPTY)) { + TALLOC_FREE(lck); + fd_close(fsp); + file_free(req, fsp); + return status; + } + + if (NT_STATUS_IS_OK(status)) { + /* Note that here we set the *inital* delete on close flag, + not the regular one. The magic gets handled in close. */ + fsp->initial_delete_on_close = True; + } + } + + TALLOC_FREE(lck); + + if (pinfo) { + *pinfo = info; + } + + *result = fsp; + return NT_STATUS_OK; +} + +/* + * If a main file is opened for delete, all streams need to be checked for + * !FILE_SHARE_DELETE. Do this by opening with DELETE_ACCESS. + * If that works, delete them all by setting the delete on close and close. + */ + +static NTSTATUS open_streams_for_delete(connection_struct *conn, + const char *fname) +{ + struct stream_struct *stream_info; + files_struct **streams; + int i; + unsigned int num_streams; + TALLOC_CTX *frame = talloc_stackframe(); + NTSTATUS status; + + status = SMB_VFS_STREAMINFO(conn, NULL, fname, talloc_tos(), + &num_streams, &stream_info); + + if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED) + || NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { + DEBUG(10, ("no streams around\n")); + TALLOC_FREE(frame); + return NT_STATUS_OK; + } + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("SMB_VFS_STREAMINFO failed: %s\n", + nt_errstr(status))); + goto fail; + } + + DEBUG(10, ("open_streams_for_delete found %d streams\n", + num_streams)); + + if (num_streams == 0) { + TALLOC_FREE(frame); + return NT_STATUS_OK; + } + + streams = TALLOC_ARRAY(talloc_tos(), files_struct *, num_streams); + if (streams == NULL) { + DEBUG(0, ("talloc failed\n")); + status = NT_STATUS_NO_MEMORY; + goto fail; + } + + for (i=0; i<num_streams; i++) { + char *streamname; + + if (strequal(stream_info[i].name, "::$DATA")) { + streams[i] = NULL; + continue; + } + + streamname = talloc_asprintf(talloc_tos(), "%s%s", fname, + stream_info[i].name); + + if (streamname == NULL) { + DEBUG(0, ("talloc_aprintf failed\n")); + status = NT_STATUS_NO_MEMORY; + goto fail; + } + + status = onefs_create_file_unixpath + (conn, /* conn */ + NULL, /* req */ + streamname, /* fname */ + DELETE_ACCESS, /* access_mask */ + FILE_SHARE_READ | FILE_SHARE_WRITE + | FILE_SHARE_DELETE, /* share_access */ + FILE_OPEN, /* create_disposition*/ + NTCREATEX_OPTIONS_PRIVATE_STREAM_DELETE, /* create_options */ + FILE_ATTRIBUTE_NORMAL, /* file_attributes */ + 0, /* oplock_request */ + 0, /* allocation_size */ + NULL, /* sd */ + NULL, /* ea_list */ + &streams[i], /* result */ + NULL, /* pinfo */ + NULL); /* psbuf */ + + TALLOC_FREE(streamname); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("Could not open stream %s: %s\n", + streamname, nt_errstr(status))); + break; + } + } + + /* + * don't touch the variable "status" beyond this point :-) + */ + + for (i -= 1 ; i >= 0; i--) { + if (streams[i] == NULL) { + continue; + } + + DEBUG(10, ("Closing stream # %d, %s\n", i, + streams[i]->fsp_name)); + close_file(NULL, streams[i], NORMAL_CLOSE); + } + + fail: + TALLOC_FREE(frame); + return status; +} + +/* + * Wrapper around onefs_open_file_ntcreate and onefs_open_directory. + */ +static NTSTATUS onefs_create_file_unixpath(connection_struct *conn, + struct smb_request *req, + const char *fname, + uint32_t access_mask, + uint32_t share_access, + uint32_t create_disposition, + uint32_t create_options, + uint32_t file_attributes, + uint32_t oplock_request, + uint64_t allocation_size, + struct security_descriptor *sd, + struct ea_list *ea_list, + files_struct **result, + int *pinfo, + SMB_STRUCT_STAT *psbuf) +{ + SMB_STRUCT_STAT sbuf; + int info = FILE_WAS_OPENED; + files_struct *base_fsp = NULL; + files_struct *fsp = NULL; + NTSTATUS status; + + DEBUG(10,("onefs_create_file_unixpath: access_mask = 0x%x " + "file_attributes = 0x%x, share_access = 0x%x, " + "create_disposition = 0x%x create_options = 0x%x " + "oplock_request = 0x%x ea_list = 0x%p, sd = 0x%p, " + "fname = %s\n", + (unsigned int)access_mask, + (unsigned int)file_attributes, + (unsigned int)share_access, + (unsigned int)create_disposition, + (unsigned int)create_options, + (unsigned int)oplock_request, + ea_list, sd, fname)); + + if (create_options & FILE_OPEN_BY_FILE_ID) { + status = NT_STATUS_NOT_SUPPORTED; + goto fail; + } + + if (create_options & NTCREATEX_OPTIONS_INVALID_PARAM_MASK) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (req == NULL) { + oplock_request |= INTERNAL_OPEN_ONLY; + } + + if (psbuf != NULL) { + sbuf = *psbuf; + } + else { + if (SMB_VFS_STAT(conn, fname, &sbuf) == -1) { + SET_STAT_INVALID(sbuf); + } + } + + if ((conn->fs_capabilities & FILE_NAMED_STREAMS) + && (access_mask & DELETE_ACCESS) + && !is_ntfs_stream_name(fname)) { + /* + * We can't open a file with DELETE access if any of the + * streams is open without FILE_SHARE_DELETE + */ + status = open_streams_for_delete(conn, fname); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + } + + if ((conn->fs_capabilities & FILE_NAMED_STREAMS) + && is_ntfs_stream_name(fname) + && (!(create_options & NTCREATEX_OPTIONS_PRIVATE_STREAM_DELETE))) { + char *base; + uint32 base_create_disposition; + + if (create_options & FILE_DIRECTORY_FILE) { + status = NT_STATUS_NOT_A_DIRECTORY; + goto fail; + } + + status = split_ntfs_stream_name(talloc_tos(), fname, + &base, NULL); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("onefs_create_file_unixpath: " + "split_ntfs_stream_name failed: %s\n", + nt_errstr(status))); + goto fail; + } + + SMB_ASSERT(!is_ntfs_stream_name(base)); /* paranoia.. */ + + switch (create_disposition) { + case FILE_OPEN: + base_create_disposition = FILE_OPEN; + break; + default: + base_create_disposition = FILE_OPEN_IF; + break; + } + + status = onefs_create_file_unixpath( + conn, /* conn */ + NULL, /* req */ + base, /* fname */ + 0, /* access_mask */ + (FILE_SHARE_READ | + FILE_SHARE_WRITE | + FILE_SHARE_DELETE), /* share_access */ + base_create_disposition, /* create_disposition*/ + 0, /* create_options */ + 0, /* file_attributes */ + NO_OPLOCK, /* oplock_request */ + 0, /* allocation_size */ + NULL, /* sd */ + NULL, /* ea_list */ + &base_fsp, /* result */ + NULL, /* pinfo */ + NULL); /* psbuf */ + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("onefs_create_file_unixpath for base %s " + "failed: %s\n", base, nt_errstr(status))); + goto fail; + } + /* + * we don't need to low level fd: This might conflict with + * OneFS streams. + */ + fd_close(base_fsp); + } + + /* Covert generic bits in the security descriptor. */ + if (sd != NULL) { + security_acl_map_generic(sd->dacl, &file_generic_mapping); + security_acl_map_generic(sd->sacl, &file_generic_mapping); + } + + /* + * If it's a request for a directory open, deal with it separately. + */ + + if (create_options & FILE_DIRECTORY_FILE) { + + if (create_options & FILE_NON_DIRECTORY_FILE) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + /* Can't open a temp directory. IFS kit test. */ + if (!(file_attributes & FILE_FLAG_POSIX_SEMANTICS) && + (file_attributes & FILE_ATTRIBUTE_TEMPORARY)) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + /* + * We will get a create directory here if the Win32 + * app specified a security descriptor in the + * CreateDirectory() call. + */ + + status = onefs_open_directory( + conn, /* conn */ + req, /* req */ + fname, /* fname */ + access_mask, /* access_mask */ + share_access, /* share_access */ + create_disposition, /* create_disposition*/ + create_options, /* create_options */ + file_attributes, /* file_attributes */ + sd, /* sd */ + &fsp, /* result */ + &info, /* pinfo */ + &sbuf); /* psbuf */ + } else { + + /* + * Ordinary file case. + */ + + status = file_new(req, conn, &fsp); + if(!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* + * We're opening the stream element of a base_fsp + * we already opened. Set up the base_fsp pointer. + */ + if (base_fsp) { + fsp->base_fsp = base_fsp; + } + + status = onefs_open_file_ntcreate( + conn, /* conn */ + req, /* req */ + fname, /* fname */ + access_mask, /* access_mask */ + share_access, /* share_access */ + create_disposition, /* create_disposition*/ + create_options, /* create_options */ + file_attributes, /* file_attributes */ + oplock_request, /* oplock_request */ + sd, /* sd */ + fsp, /* result */ + &info, /* pinfo */ + &sbuf); /* psbuf */ + + if(!NT_STATUS_IS_OK(status)) { + file_free(req, fsp); + fsp = NULL; + } + + if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) { + + /* A stream open never opens a directory */ + + if (base_fsp) { + status = NT_STATUS_FILE_IS_A_DIRECTORY; + goto fail; + } + + /* + * Fail the open if it was explicitly a non-directory + * file. + */ + + if (create_options & FILE_NON_DIRECTORY_FILE) { + status = NT_STATUS_FILE_IS_A_DIRECTORY; + goto fail; + } + + create_options |= FILE_DIRECTORY_FILE; + + status = onefs_open_directory( + conn, /* conn */ + req, /* req */ + fname, /* fname */ + access_mask, /* access_mask */ + share_access, /* share_access */ + create_disposition, /* create_disposition*/ + create_options, /* create_options */ + file_attributes, /* file_attributes */ + sd, /* sd */ + &fsp, /* result */ + &info, /* pinfo */ + &sbuf); /* psbuf */ + } + } + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + fsp->base_fsp = base_fsp; + + SMB_ASSERT(fsp); + + if ((ea_list != NULL) && (info == FILE_WAS_CREATED)) { + status = set_ea(conn, fsp, fname, ea_list); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + } + + if (!fsp->is_directory && S_ISDIR(sbuf.st_mode)) { + status = NT_STATUS_ACCESS_DENIED; + goto fail; + } + + /* Save the requested allocation size. */ + if ((info == FILE_WAS_CREATED) || (info == FILE_WAS_OVERWRITTEN)) { + if (allocation_size + && (allocation_size > sbuf.st_size)) { + fsp->initial_allocation_size = smb_roundup( + fsp->conn, allocation_size); + if (fsp->is_directory) { + /* Can't set allocation size on a directory. */ + status = NT_STATUS_ACCESS_DENIED; + goto fail; + } + if (vfs_allocate_file_space( + fsp, fsp->initial_allocation_size) == -1) { + status = NT_STATUS_DISK_FULL; + goto fail; + } + } else { + fsp->initial_allocation_size = smb_roundup( + fsp->conn, (uint64_t)sbuf.st_size); + } + } + + DEBUG(10, ("onefs_create_file_unixpath: info=%d\n", info)); + + *result = fsp; + if (pinfo != NULL) { + *pinfo = info; + } + if (psbuf != NULL) { + if ((fsp->fh == NULL) || (fsp->fh->fd == -1)) { + *psbuf = sbuf; + } + else { + SMB_VFS_FSTAT(fsp, psbuf); + } + } + return NT_STATUS_OK; + + fail: + DEBUG(10, ("onefs_create_file_unixpath: %s\n", nt_errstr(status))); + + if (fsp != NULL) { + if (base_fsp && fsp->base_fsp == base_fsp) { + /* + * The close_file below will close + * fsp->base_fsp. + */ + base_fsp = NULL; + } + close_file(req, fsp, ERROR_CLOSE); + fsp = NULL; + } + if (base_fsp != NULL) { + close_file(req, base_fsp, ERROR_CLOSE); + base_fsp = NULL; + } + return status; +} + +/** + * SMB_VFS_CREATE_FILE interface to onefs. + */ +NTSTATUS onefs_create_file(vfs_handle_struct *handle, + struct smb_request *req, + uint16_t root_dir_fid, + const char *fname, + uint32_t create_file_flags, + uint32_t access_mask, + uint32_t share_access, + uint32_t create_disposition, + uint32_t create_options, + uint32_t file_attributes, + uint32_t oplock_request, + uint64_t allocation_size, + struct security_descriptor *sd, + struct ea_list *ea_list, + files_struct **result, + int *pinfo, + SMB_STRUCT_STAT *psbuf) +{ + connection_struct *conn = handle->conn; + struct case_semantics_state *case_state = NULL; + SMB_STRUCT_STAT sbuf; + int info = FILE_WAS_OPENED; + files_struct *fsp = NULL; + NTSTATUS status; + + DEBUG(10,("onefs_create_file: access_mask = 0x%x " + "file_attributes = 0x%x, share_access = 0x%x, " + "create_disposition = 0x%x create_options = 0x%x " + "oplock_request = 0x%x " + "root_dir_fid = 0x%x, ea_list = 0x%p, sd = 0x%p, " + "create_file_flags = 0x%x, fname = %s\n", + (unsigned int)access_mask, + (unsigned int)file_attributes, + (unsigned int)share_access, + (unsigned int)create_disposition, + (unsigned int)create_options, + (unsigned int)oplock_request, + (unsigned int)root_dir_fid, + ea_list, sd, create_file_flags, fname)); + + /* Get the file name if root_dir_fid was specified. */ + if (root_dir_fid != 0) { + char *new_fname; + + status = get_relative_fid_filename(conn, req, root_dir_fid, + fname, &new_fname); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + fname = new_fname; + } + + /* Resolve the file name if this was a DFS pathname. */ + if ((req != NULL) && (req->flags2 & FLAGS2_DFS_PATHNAMES)) { + char *resolved_fname; + + status = resolve_dfspath(talloc_tos(), conn, true, fname, + &resolved_fname); + + if (!NT_STATUS_IS_OK(status)) { + /* + * For PATH_NOT_COVERED we had + * reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, + * ERRSRV, ERRbadpath); + * Need to fix in callers + */ + goto fail; + } + fname = resolved_fname; + } + + /* Check if POSIX semantics are wanted. */ + if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) { + case_state = set_posix_case_semantics(talloc_tos(), conn); + } + + /* Convert dos path to unix path if it hasn't already been done. */ + if (create_file_flags & CFF_DOS_PATH) { + char *converted_fname; + + SET_STAT_INVALID(sbuf); + + status = unix_convert(talloc_tos(), conn, fname, False, + &converted_fname, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + fname = converted_fname; + } else { + if (psbuf != NULL) { + sbuf = *psbuf; + } else { + if (SMB_VFS_STAT(conn, fname, &sbuf) == -1) { + SET_STAT_INVALID(sbuf); + } + } + + } + + TALLOC_FREE(case_state); + + /* All file access must go through check_name() */ + status = check_name(conn, fname); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + status = onefs_create_file_unixpath( + conn, /* conn */ + req, /* req */ + fname, /* fname */ + access_mask, /* access_mask */ + share_access, /* share_access */ + create_disposition, /* create_disposition*/ + create_options, /* create_options */ + file_attributes, /* file_attributes */ + oplock_request, /* oplock_request */ + allocation_size, /* allocation_size */ + sd, /* sd */ + ea_list, /* ea_list */ + &fsp, /* result */ + &info, /* pinfo */ + &sbuf); /* psbuf */ + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + DEBUG(10, ("onefs_create_file: info=%d\n", info)); + + *result = fsp; + if (pinfo != NULL) { + *pinfo = info; + } + if (psbuf != NULL) { + *psbuf = sbuf; + } + return NT_STATUS_OK; + + fail: + DEBUG(10, ("onefs_create_file: %s\n", nt_errstr(status))); + + if (fsp != NULL) { + close_file(req, fsp, ERROR_CLOSE); + fsp = NULL; + } + return status; +} diff --git a/source3/modules/onefs_system.c b/source3/modules/onefs_system.c new file mode 100644 index 0000000000..485e7f56ac --- /dev/null +++ b/source3/modules/onefs_system.c @@ -0,0 +1,214 @@ +/* + * Unix SMB/CIFS implementation. + * Support for OneFS system interfaces. + * + * Copyright (C) Tim Prouty, 2008 + * + * 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "onefs.h" + +#include <ifs/ifs_syscalls.h> +#include <isi_acl/isi_acl_util.h> + +/* + * Initialize the sm_lock struct before passing it to ifs_createfile. + */ +static void smlock_init(connection_struct *conn, struct sm_lock *sml, + bool isexe, uint32_t access_mask, uint32_t share_access, + uint32_t create_options) +{ + sml->sm_type.doc = false; + sml->sm_type.isexe = isexe; + sml->sm_type.statonly = is_stat_open(access_mask); + sml->sm_type.access_mask = access_mask; + sml->sm_type.share_access = share_access; + + /* + * private_options was previously used for DENY_DOS/DENY_FCB checks in + * the kernel, but are now properly handled by fcb_or_dos_open. In + * these cases, ifs_createfile will return a sharing violation, which + * gives fcb_or_dos_open the chance to open a duplicate file handle. + */ + sml->sm_type.private_options = 0; + + /* 1 second delay is handled in onefs_open.c by deferring the open */ + sml->sm_timeout = timeval_set(0, 0); +} + +static void smlock_dump(int debuglevel, const struct sm_lock *sml) +{ + if (sml == NULL) { + DEBUG(debuglevel, ("sml == NULL\n")); + return; + } + + DEBUG(debuglevel, + ("smlock: doc=%s, isexec=%s, statonly=%s, access_mask=0x%x, " + "share_access=0x%x, private_options=0x%x timeout=%d/%d\n", + sml->sm_type.doc ? "True" : "False", + sml->sm_type.isexe ? "True" : "False", + sml->sm_type.statonly ? "True" : "False", + sml->sm_type.access_mask, + sml->sm_type.share_access, + sml->sm_type.private_options, + (int)sml->sm_timeout.tv_sec, + (int)sml->sm_timeout.tv_usec)); +} + +/* + * Return string value of onefs oplock types. + */ +static const char *onefs_oplock_str(enum oplock_type onefs_oplock_type) +{ + switch (onefs_oplock_type) { + case OPLOCK_NONE: + return "OPLOCK_NONE"; + case OPLOCK_EXCLUSIVE: + return "OPLOCK_EXCLUSIVE"; + case OPLOCK_BATCH: + return "OPLOCK_BATCH"; + case OPLOCK_SHARED: + return "OPLOCK_SHARED"; + default: + break; + } + return "UNKNOWN"; +} + +/* + * Convert from onefs to samba oplock. + */ +static int onefs_to_samba_oplock(enum oplock_type onefs_oplock) +{ + switch (onefs_oplock) { + case OPLOCK_NONE: + return NO_OPLOCK; + case OPLOCK_EXCLUSIVE: + return EXCLUSIVE_OPLOCK; + case OPLOCK_BATCH: + return BATCH_OPLOCK; + case OPLOCK_SHARED: + return LEVEL_II_OPLOCK; + default: + DEBUG(0, ("unknown oplock type %d found\n", onefs_oplock)); + break; + } + return NO_OPLOCK; +} + +/* + * Convert from samba to onefs oplock. + */ +static enum oplock_type samba_to_onefs_oplock(int samba_oplock_type) +{ + if (BATCH_OPLOCK_TYPE(samba_oplock_type)) return OPLOCK_BATCH; + if (EXCLUSIVE_OPLOCK_TYPE(samba_oplock_type)) return OPLOCK_EXCLUSIVE; + if (LEVEL_II_OPLOCK_TYPE(samba_oplock_type)) return OPLOCK_SHARED; + return OPLOCK_NONE; +} + +/** + * External interface to ifs_createfile + */ +int onefs_sys_create_file(connection_struct *conn, + int base_fd, + const char *path, + uint32_t access_mask, + uint32_t open_access_mask, + uint32_t share_access, + uint32_t create_options, + int flags, + mode_t mode, + int oplock_request, + uint64_t id, + struct security_descriptor *sd, + uint32_t dos_flags, + int *granted_oplock) +{ + struct sm_lock sml, *psml = NULL; + enum oplock_type onefs_oplock; + enum oplock_type onefs_granted_oplock = OPLOCK_NONE; + struct ifs_security_descriptor ifs_sd = {}, *pifs_sd = NULL; + int secinfo = 0; + int ret_fd = -1; + uint32_t onefs_dos_attributes; + + /* Setup security descriptor and get secinfo. */ + if (sd != NULL) { + NTSTATUS status; + + secinfo = (get_sec_info(sd) & IFS_SEC_INFO_KNOWN_MASK); + + status = onefs_setup_sd(secinfo, sd, &ifs_sd); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("SD initialization failure: %s", + nt_errstr(status))); + errno = EINVAL; + goto out; + } + + pifs_sd = &ifs_sd; + } + + onefs_oplock = samba_to_onefs_oplock(oplock_request); + + /* Temporary until oplock work is added to vfs_onefs */ + onefs_oplock = OPLOCK_NONE; + + /* Convert samba dos flags to UF_DOS_* attributes. */ + onefs_dos_attributes = dos_attributes_to_stat_dos_flags(dos_flags); + + DEBUG(10,("onefs_sys_create_file: base_fd = %d, " + "open_access_mask = 0x%x, flags = 0x%x, mode = 0x%x, " + "desired_oplock = %s, id = 0x%x, secinfo = 0x%x, sd = %p, " + "dos_attributes = 0x%x, path = %s\n", base_fd, + (unsigned int)open_access_mask, + (unsigned int)flags, + (unsigned int)mode, + onefs_oplock_str(onefs_oplock), + (unsigned int)id, + (unsigned int)secinfo, sd, + (unsigned int)onefs_dos_attributes, path)); + + /* Initialize smlock struct for files/dirs but not internal opens */ + if (!(oplock_request & INTERNAL_OPEN_ONLY)) { + smlock_init(conn, &sml, is_executable(path), access_mask, + share_access, create_options); + psml = &sml; + } + + smlock_dump(10, psml); + + ret_fd = ifs_createfile(base_fd, path, + (enum ifs_ace_rights)open_access_mask, flags & ~O_ACCMODE, mode, + onefs_oplock, id, psml, secinfo, pifs_sd, onefs_dos_attributes, + &onefs_granted_oplock); + + DEBUG(10,("onefs_sys_create_file(%s): ret_fd = %d, " + "onefs_granted_oplock = %s\n", + ret_fd < 0 ? strerror(errno) : "success", ret_fd, + onefs_oplock_str(onefs_granted_oplock))); + + if (granted_oplock) { + *granted_oplock = onefs_to_samba_oplock(onefs_granted_oplock); + } + + out: + aclu_free_sd(pifs_sd, false); + + return ret_fd; +} diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index d972828ba9..8fa8f6ae06 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -208,6 +208,32 @@ static int vfswrap_open(vfs_handle_struct *handle, const char *fname, return result; } +static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle, + struct smb_request *req, + uint16_t root_dir_fid, + const char *fname, + uint32_t create_file_flags, + uint32_t access_mask, + uint32_t share_access, + uint32_t create_disposition, + uint32_t create_options, + uint32_t file_attributes, + uint32_t oplock_request, + uint64_t allocation_size, + struct security_descriptor *sd, + struct ea_list *ea_list, + files_struct **result, + int *pinfo, + SMB_STRUCT_STAT *psbuf) +{ + return create_file_default(handle->conn, req, root_dir_fid, fname, + create_file_flags, access_mask, share_access, + create_disposition, create_options, + file_attributes, oplock_request, + allocation_size, sd, ea_list, result, pinfo, + psbuf); +} + static int vfswrap_close(vfs_handle_struct *handle, files_struct *fsp) { int result; @@ -1012,6 +1038,16 @@ static NTSTATUS vfswrap_streaminfo(vfs_handle_struct *handle, return NT_STATUS_OK; } +static int vfswrap_get_real_filename(struct vfs_handle_struct *handle, + const char *path, + const char *name, + TALLOC_CTX *mem_ctx, + char **found_name) +{ + return get_real_filename(handle->conn, path, name, mem_ctx, + found_name); +} + static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc) @@ -1359,6 +1395,8 @@ static vfs_op_tuple vfs_default_ops[] = { {SMB_VFS_OP(vfswrap_open), SMB_VFS_OP_OPEN, SMB_VFS_LAYER_OPAQUE}, + {SMB_VFS_OP(vfswrap_create_file), SMB_VFS_OP_CREATE_FILE, + SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(vfswrap_close), SMB_VFS_OP_CLOSE, SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(vfswrap_read), SMB_VFS_OP_READ, @@ -1431,6 +1469,8 @@ static vfs_op_tuple vfs_default_ops[] = { SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(vfswrap_streaminfo), SMB_VFS_OP_STREAMINFO, SMB_VFS_LAYER_OPAQUE}, + {SMB_VFS_OP(vfswrap_get_real_filename), SMB_VFS_OP_GET_REAL_FILENAME, + SMB_VFS_LAYER_OPAQUE}, /* NT ACL operations. */ diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c index 6342c4a14e..7970bf2644 100644 --- a/source3/modules/vfs_full_audit.c +++ b/source3/modules/vfs_full_audit.c @@ -109,6 +109,23 @@ static int smb_full_audit_closedir(vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp); static int smb_full_audit_open(vfs_handle_struct *handle, const char *fname, files_struct *fsp, int flags, mode_t mode); +static NTSTATUS smb_full_audit_create_file(vfs_handle_struct *handle, + struct smb_request *req, + uint16_t root_dir_fid, + const char *fname, + uint32_t create_file_flags, + uint32_t access_mask, + uint32_t share_access, + uint32_t create_disposition, + uint32_t create_options, + uint32_t file_attributes, + uint32_t oplock_request, + uint64_t allocation_size, + struct security_descriptor *sd, + struct ea_list *ea_list, + files_struct **result, + int *pinfo, + SMB_STRUCT_STAT *psbuf); static int smb_full_audit_close(vfs_handle_struct *handle, files_struct *fsp); static ssize_t smb_full_audit_read(vfs_handle_struct *handle, files_struct *fsp, void *data, size_t n); @@ -353,6 +370,8 @@ static vfs_op_tuple audit_op_tuples[] = { {SMB_VFS_OP(smb_full_audit_open), SMB_VFS_OP_OPEN, SMB_VFS_LAYER_LOGGER}, + {SMB_VFS_OP(smb_full_audit_create_file),SMB_VFS_OP_CREATE_FILE, + SMB_VFS_LAYER_LOGGER}, {SMB_VFS_OP(smb_full_audit_close), SMB_VFS_OP_CLOSE, SMB_VFS_LAYER_LOGGER}, {SMB_VFS_OP(smb_full_audit_read), SMB_VFS_OP_READ, @@ -1087,6 +1106,51 @@ static int smb_full_audit_open(vfs_handle_struct *handle, return result; } +static NTSTATUS smb_full_audit_create_file(vfs_handle_struct *handle, + struct smb_request *req, + uint16_t root_dir_fid, + const char *fname, + uint32_t create_file_flags, + uint32_t access_mask, + uint32_t share_access, + uint32_t create_disposition, + uint32_t create_options, + uint32_t file_attributes, + uint32_t oplock_request, + uint64_t allocation_size, + struct security_descriptor *sd, + struct ea_list *ea_list, + files_struct **result_fsp, + int *pinfo, + SMB_STRUCT_STAT *psbuf) +{ + NTSTATUS result; + + result = SMB_VFS_NEXT_CREATE_FILE( + handle, /* handle */ + req, /* req */ + root_dir_fid, /* root_dir_fid */ + fname, /* fname */ + create_file_flags, /* create_file_flags */ + access_mask, /* access_mask */ + share_access, /* share_access */ + create_disposition, /* create_disposition*/ + create_options, /* create_options */ + file_attributes, /* file_attributes */ + oplock_request, /* oplock_request */ + allocation_size, /* allocation_size */ + sd, /* sd */ + ea_list, /* ea_list */ + result_fsp, /* result */ + pinfo, /* pinfo */ + psbuf); /* psbuf */ + + do_log(SMB_VFS_OP_CREATE_FILE, (NT_STATUS_IS_OK(result)), handle, "0x%x|%s", + access_mask, fname); + + return result; +} + static int smb_full_audit_close(vfs_handle_struct *handle, files_struct *fsp) { int result; diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index fa0b4e97a5..1d7cdba014 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -1,26 +1,24 @@ /* Unix SMB/CIFS implementation. Wrap gpfs calls in vfs functions. - + Copyright (C) Christian Ambach <cambach1@de.ibm.com> 2006 - + Major code contributions by Chetan Shringarpure <chetan.sh@in.ibm.com> and Gomati Mohanan <gomati.mohanan@in.ibm.com> - + 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 the Free Software Foundation; either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. - - */ #include "includes.h" @@ -55,14 +53,14 @@ static int vfs_gpfs_setlease(vfs_handle_struct *handle, files_struct *fsp, int leasetype) { int ret; - + START_PROFILE(syscall_linux_setlease); - + if ( linux_set_lease_sighandler(fsp->fh->fd) == -1) return -1; ret = set_gpfs_lease(fsp->fh->fd,leasetype); - + if ( ret < 0 ) { /* This must have come from GPFS not being available */ /* or some other error, hence call the default */ @@ -74,7 +72,64 @@ static int vfs_gpfs_setlease(vfs_handle_struct *handle, files_struct *fsp, return ret; } +static int vfs_gpfs_get_real_filename(struct vfs_handle_struct *handle, + const char *path, + const char *name, + TALLOC_CTX *mem_ctx, + char **found_name) +{ + int result; + char *full_path; + char real_pathname[PATH_MAX+1]; + int buflen; + + full_path = talloc_asprintf(talloc_tos(), "%s/%s", path, name); + if (full_path == NULL) { + errno = ENOMEM; + return -1; + } + + buflen = sizeof(real_pathname) - 1; + + result = smbd_gpfs_get_realfilename_path(full_path, real_pathname, + &buflen); + + TALLOC_FREE(full_path); + + if (result == -1) { + DEBUG(10, ("smbd_gpfs_get_realfilename_path returned %s\n", + strerror(errno))); + return -1; + } + + /* + * GPFS does not necessarily null-terminate the returned path + * but instead returns the buffer length in buflen. + */ + + if (buflen < sizeof(real_pathname)) { + real_pathname[buflen] = '\0'; + } else { + real_pathname[sizeof(real_pathname)-1] = '\0'; + } + + DEBUG(10, ("smbd_gpfs_get_realfilename_path: %s/%s -> %s\n", + path, name, real_pathname)); + + name = strrchr_m(real_pathname, '/'); + if (name == NULL) { + errno = ENOENT; + return -1; + } + + *found_name = talloc_strdup(mem_ctx, name+1); + if (*found_name == NULL) { + errno = ENOMEM; + return -1; + } + return 0; +} static void gpfs_dumpacl(int level, struct gpfs_acl *gacl) { @@ -301,13 +356,13 @@ static bool gpfsacl_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl) gace->aceType = aceprop->aceType; gace->aceFlags = aceprop->aceFlags; gace->aceMask = aceprop->aceMask; - + /* * GPFS can't distinguish between WRITE and APPEND on * files, so one being set without the other is an * error. Sorry for the many ()'s :-) */ - + if (!fsp->is_directory && ((((gace->aceMask & ACE4_MASK_WRITE) == 0) @@ -323,9 +378,9 @@ static bool gpfsacl_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl) fsp->fsp_name)); gace->aceMask |= ACE4_MASK_WRITE|ACE4_MASK_APPEND; } - + gace->aceIFlags = (aceprop->flags&SMB_ACE4_ID_SPECIAL) ? ACE4_IFLAG_SPECIAL_ID : 0; - + if (aceprop->flags&SMB_ACE4_ID_SPECIAL) { switch(aceprop->who.special_id) @@ -478,7 +533,7 @@ static SMB_ACL_T gpfsacl_get_posix_acl(const char *path, gpfs_aclType_t type) errno = EINVAL; goto done; } - + DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d\n", pacl->acl_len, pacl->acl_level, pacl->acl_version, pacl->acl_nace)); @@ -497,7 +552,6 @@ static SMB_ACL_T gpfsacl_get_posix_acl(const char *path, gpfs_aclType_t type) } SMB_ACL_T gpfsacl_sys_acl_get_file(vfs_handle_struct *handle, - const char *path_p, SMB_ACL_TYPE_T type) { @@ -557,7 +611,7 @@ static struct gpfs_acl *smb2gpfs_acl(const SMB_ACL_T pacl, for (i=0; i<pacl->count; i++) { const struct smb_acl_entry *ace = &pacl->acl[i]; struct gpfs_ace_v1 *g_ace = &result->ace_v1[i]; - + DEBUG(10, ("Converting type %d perm %x\n", (int)ace->a_type, (int)ace->a_perm)); @@ -612,7 +666,6 @@ static struct gpfs_acl *smb2gpfs_acl(const SMB_ACL_T pacl, } int gpfsacl_sys_acl_set_file(vfs_handle_struct *handle, - const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T theacl) @@ -639,7 +692,6 @@ int gpfsacl_sys_acl_set_fd(vfs_handle_struct *handle, } int gpfsacl_sys_acl_delete_def_file(vfs_handle_struct *handle, - const char *path) { errno = ENOTSUP; @@ -661,11 +713,11 @@ static uint32 gpfsacl_mask_filter(uint32 aceType, uint32 aceMask, uint32 rwx) uint32_t posix_mask = 0x01; uint32_t posix_bit; uint32_t nfs4_bits; - + for(i=0; i<3; i++) { nfs4_bits = posix_nfs4map[i]; posix_bit = rwx & posix_mask; - + if (aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) { if (posix_bit) aceMask |= nfs4_bits; @@ -678,10 +730,10 @@ static uint32 gpfsacl_mask_filter(uint32 aceType, uint32 aceMask, uint32 rwx) else aceMask &= ~nfs4_bits; } /* other ace types are unexpected */ - + posix_mask <<= 1; } - + return aceMask; } @@ -693,30 +745,30 @@ static int gpfsacl_emu_chmod(const char *path, mode_t mode) int i; files_struct fake_fsp; /* TODO: rationalize parametrization */ SMB4ACE_T *smbace; - + DEBUG(10, ("gpfsacl_emu_chmod invoked for %s mode %o\n", path, mode)); - + result = gpfs_get_nfs4_acl(path, &pacl); if (result) return result; - + if (mode & ~(S_IRWXU | S_IRWXG | S_IRWXO)) { DEBUG(2, ("WARNING: cutting extra mode bits %o on %s\n", mode, path)); } - + for (smbace=smb_first_ace4(pacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) { SMB_ACE4PROP_T *ace = smb_get_ace4(smbace); uint32_t specid = ace->who.special_id; - + if (ace->flags&SMB_ACE4_ID_SPECIAL && ace->aceType<=SMB_ACE4_ACCESS_DENIED_ACE_TYPE && specid <= SMB_ACE4_WHO_EVERYONE) { - + uint32_t newMask; - + if (ace->aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) haveAllowEntry[specid] = True; - + /* mode >> 6 for @owner, mode >> 3 for @group, * mode >> 0 for @everyone */ newMask = gpfsacl_mask_filter(ace->aceType, ace->aceMask, @@ -735,35 +787,35 @@ static int gpfsacl_emu_chmod(const char *path, mode_t mode) */ for(i = SMB_ACE4_WHO_OWNER; i<=SMB_ACE4_WHO_EVERYONE; i++) { SMB_ACE4PROP_T ace; - + if (haveAllowEntry[i]==True) continue; - + ZERO_STRUCT(ace); ace.aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE; ace.flags |= SMB_ACE4_ID_SPECIAL; ace.who.special_id = i; - + if (i==SMB_ACE4_WHO_GROUP) /* not sure it's necessary... */ ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP; - + ace.aceMask = gpfsacl_mask_filter(ace.aceType, ace.aceMask, mode >> ((SMB_ACE4_WHO_EVERYONE - i) * 3)); - + /* don't add unnecessary aces */ if (!ace.aceMask) continue; - + /* we add it to the END - as windows expects allow aces */ smb_add_ace4(pacl, &ace); DEBUG(10, ("Added ALLOW ace for %s, mode=%o, id=%d, aceMask=%x\n", path, mode, i, ace.aceMask)); } - + /* don't add complementary DENY ACEs here */ ZERO_STRUCT(fake_fsp); fake_fsp.fsp_name = (char *)path; /* no file_new is needed here */ - + /* put the acl */ if (gpfsacl_process_smbacl(&fake_fsp, pacl) == False) return -1; @@ -774,11 +826,11 @@ static int vfs_gpfs_chmod(vfs_handle_struct *handle, const char *path, mode_t mo { SMB_STRUCT_STAT st; int rc; - + if (SMB_VFS_NEXT_STAT(handle, path, &st) != 0) { return -1; } - + /* avoid chmod() if possible, to preserve acls */ if ((st.st_mode & ~S_IFMT) == mode) { return 0; @@ -794,7 +846,7 @@ static int vfs_gpfs_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t { SMB_STRUCT_STAT st; int rc; - + if (SMB_VFS_NEXT_FSTAT(handle, fsp, &st) != 0) { return -1; } @@ -813,51 +865,55 @@ static int vfs_gpfs_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t /* VFS operations structure */ static vfs_op_tuple gpfs_op_tuples[] = { - + { SMB_VFS_OP(vfs_gpfs_kernel_flock), SMB_VFS_OP_KERNEL_FLOCK, SMB_VFS_LAYER_OPAQUE }, - + { SMB_VFS_OP(vfs_gpfs_setlease), SMB_VFS_OP_LINUX_SETLEASE, SMB_VFS_LAYER_OPAQUE }, - + + { SMB_VFS_OP(vfs_gpfs_get_real_filename), + SMB_VFS_OP_GET_REAL_FILENAME, + SMB_VFS_LAYER_OPAQUE }, + { SMB_VFS_OP(gpfsacl_fget_nt_acl), SMB_VFS_OP_FGET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(gpfsacl_get_nt_acl), SMB_VFS_OP_GET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(gpfsacl_fset_nt_acl), SMB_VFS_OP_FSET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(gpfsacl_sys_acl_get_file), SMB_VFS_OP_SYS_ACL_GET_FILE, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(gpfsacl_sys_acl_get_fd), SMB_VFS_OP_SYS_ACL_GET_FD, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(gpfsacl_sys_acl_set_file), SMB_VFS_OP_SYS_ACL_SET_FILE, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(gpfsacl_sys_acl_set_fd), SMB_VFS_OP_SYS_ACL_SET_FD, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(gpfsacl_sys_acl_delete_def_file), SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(vfs_gpfs_chmod), SMB_VFS_OP_CHMOD, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(vfs_gpfs_fchmod), SMB_VFS_OP_FCHMOD, SMB_VFS_LAYER_TRANSPARENT }, @@ -871,7 +927,7 @@ NTSTATUS vfs_gpfs_init(void); NTSTATUS vfs_gpfs_init(void) { init_gpfs(); - + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "gpfs", gpfs_op_tuples); } diff --git a/source3/modules/vfs_onefs.c b/source3/modules/vfs_onefs.c index 193a986cf6..b51858fbae 100644 --- a/source3/modules/vfs_onefs.c +++ b/source3/modules/vfs_onefs.c @@ -1,4 +1,5 @@ /* + * Unix SMB/CIFS implementation. * Support for OneFS * * Copyright (C) Tim Prouty, 2008 @@ -18,20 +19,32 @@ */ #include "includes.h" +#include "onefs.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_VFS -NTSTATUS onefs_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp, - uint32 security_info, SEC_DESC **ppdesc); - -NTSTATUS onefs_get_nt_acl(vfs_handle_struct *handle, const char* name, - uint32 security_info, SEC_DESC **ppdesc); +static int onefs_mkdir(vfs_handle_struct *handle, const char *path, + mode_t mode) +{ + DEBUG(0, ("SMB_VFS_MKDIR should never be called in vfs_onefs")); + return SMB_VFS_NEXT_MKDIR(handle, path, mode); +} -NTSTATUS onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, - uint32 security_info_sent, SEC_DESC *psd); +static int onefs_open(vfs_handle_struct *handle, const char *fname, + files_struct *fsp, int flags, mode_t mode) +{ + DEBUG(0, ("SMB_VFS_OPEN should never be called in vfs_onefs")); + return SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode); +} static vfs_op_tuple onefs_ops[] = { + {SMB_VFS_OP(onefs_mkdir), SMB_VFS_OP_MKDIR, + SMB_VFS_LAYER_OPAQUE}, + {SMB_VFS_OP(onefs_open), SMB_VFS_OP_OPEN, + SMB_VFS_LAYER_OPAQUE}, + {SMB_VFS_OP(onefs_create_file), SMB_VFS_OP_CREATE_FILE, + SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(onefs_fget_nt_acl), SMB_VFS_OP_FGET_NT_ACL, SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(onefs_get_nt_acl), SMB_VFS_OP_GET_NT_ACL, diff --git a/source3/modules/vfs_prealloc.c b/source3/modules/vfs_prealloc.c index 2a06e3d81b..5a339dbf8d 100644 --- a/source3/modules/vfs_prealloc.c +++ b/source3/modules/vfs_prealloc.c @@ -56,9 +56,9 @@ static int module_debug; static int preallocate_space(int fd, SMB_OFF_T size) { + int err; #ifndef HAVE_GPFS lock_type fl = {0}; - int err; if (size <= 0) { return 0; |