diff options
author | Simo Sorce <idra@samba.org> | 2008-02-01 14:24:31 -0500 |
---|---|---|
committer | Simo Sorce <idra@samba.org> | 2008-02-01 14:24:31 -0500 |
commit | 2fffc9a1b1fe2a1490e867bb38462e50c282d2b3 (patch) | |
tree | 428e09c9b35138db8b7ca7161c659a71aa129d29 /source3/modules | |
parent | 93a3c5b3f9927973b4ad1496f593ea147052d1e1 (diff) | |
parent | b708005a7106db26d7df689b887b419c9f2ea41c (diff) | |
download | samba-2fffc9a1b1fe2a1490e867bb38462e50c282d2b3.tar.gz samba-2fffc9a1b1fe2a1490e867bb38462e50c282d2b3.tar.bz2 samba-2fffc9a1b1fe2a1490e867bb38462e50c282d2b3.zip |
Merge branch 'v3-2-test' of ssh://git.samba.org/data/git/samba into v3-2-test
(This used to be commit 7dbfc7bdc65314466a83e8121b35c9bcb24b2631)
Diffstat (limited to 'source3/modules')
31 files changed, 4094 insertions, 507 deletions
diff --git a/source3/modules/gpfs.c b/source3/modules/gpfs.c index 300e90fa69..590dbac26f 100644 --- a/source3/modules/gpfs.c +++ b/source3/modules/gpfs.c @@ -22,9 +22,11 @@ #ifdef HAVE_GPFS #include "gpfs_gpl.h" +#include "vfs_gpfs.h" static void *libgpfs_handle = NULL; static bool gpfs_share_modes; +static bool gpfs_leases; 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); @@ -42,7 +44,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; } @@ -88,7 +90,7 @@ int set_gpfs_lease(int fd, int leasetype) { int gpfs_type = GPFS_LEASE_NONE; - if (!gpfs_share_modes) { + if (!gpfs_leases) { return True; } @@ -103,6 +105,13 @@ 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 + each time we try this with the wrong capabilities set + */ + linux_set_lease_capability(); return gpfs_set_lease_fn(fd, gpfs_type); } @@ -172,11 +181,8 @@ void init_gpfs(void) goto failed; } - if (lp_parm_bool(-1, "gpfs", "sharemodes", True)) { - gpfs_share_modes = True; - } else { - gpfs_share_modes = False; - } + gpfs_share_modes = lp_parm_bool(-1, "gpfs", "sharemodes", True); + gpfs_leases = lp_parm_bool(-1, "gpfs", "leases", True); return; diff --git a/source3/modules/nfs4_acls.c b/source3/modules/nfs4_acls.c index edcc52261c..0c3d010dcd 100644 --- a/source3/modules/nfs4_acls.c +++ b/source3/modules/nfs4_acls.c @@ -20,6 +20,9 @@ #include "includes.h" #include "nfs4_acls.h" +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_ACLS + #define SMBACL4_PARAM_TYPE_NAME "nfs4" #define SMB_ACE4_INT_MAGIC 0x76F8A967 @@ -161,24 +164,35 @@ uint32 smb_get_naces(SMB4ACL_T *acl) return aclint->naces; } -static int smbacl4_GetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf) +static int smbacl4_GetFileOwner(struct connection_struct *conn, + const char *filename, + SMB_STRUCT_STAT *psbuf) { memset(psbuf, 0, sizeof(SMB_STRUCT_STAT)); + + /* Get the stat struct for the owner info. */ + if (SMB_VFS_STAT(conn, filename, psbuf) != 0) + { + DEBUG(8, ("SMB_VFS_STAT failed with error %s\n", + strerror(errno))); + return -1; + } + + return 0; +} + +static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf) +{ + memset(psbuf, 0, sizeof(SMB_STRUCT_STAT)); + if (fsp->is_directory || fsp->fh->fd == -1) { - /* Get the stat struct for the owner info. */ - if (SMB_VFS_STAT(fsp->conn,fsp->fsp_name, psbuf) != 0) - { - DEBUG(8, ("SMB_VFS_STAT failed with error %s\n", - strerror(errno))); - return -1; - } - } else { - if (SMB_VFS_FSTAT(fsp,fsp->fh->fd, psbuf) != 0) - { - DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n", - strerror(errno))); - return -1; - } + return smbacl4_GetFileOwner(fsp->conn, fsp->fsp_name, psbuf); + } + if (SMB_VFS_FSTAT(fsp, psbuf) != 0) + { + DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n", + strerror(errno))); + return -1; } return 0; @@ -257,30 +271,24 @@ static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx, SMB4ACL_T *acl, /* in */ return True; } -NTSTATUS smb_get_nt_acl_nfs4(files_struct *fsp, +static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf, uint32 security_info, SEC_DESC **ppdesc, SMB4ACL_T *acl) { int good_aces = 0; - SMB_STRUCT_STAT sbuf; DOM_SID sid_owner, sid_group; size_t sd_size = 0; SEC_ACE *nt_ace_list = NULL; SEC_ACL *psa = NULL; TALLOC_CTX *mem_ctx = talloc_tos(); - DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", fsp->fsp_name)); - if (acl==NULL || smb_get_naces(acl)==0) return NT_STATUS_ACCESS_DENIED; /* special because we * shouldn't alloc 0 for * win */ - if (smbacl4_GetFileOwner(fsp, &sbuf)) - return map_nt_error_from_unix(errno); - - uid_to_sid(&sid_owner, sbuf.st_uid); - gid_to_sid(&sid_group, sbuf.st_gid); + uid_to_sid(&sid_owner, sbuf->st_uid); + gid_to_sid(&sid_group, sbuf->st_gid); if (smbacl4_nfs42win(mem_ctx, acl, &sid_owner, &sid_group, &nt_ace_list, &good_aces)==False) { DEBUG(8,("smbacl4_nfs42win failed\n")); @@ -303,12 +311,43 @@ NTSTATUS smb_get_nt_acl_nfs4(files_struct *fsp, return NT_STATUS_NO_MEMORY; } - DEBUG(10, ("smb_get_nt_acl_nfs4 successfully exited with sd_size %d\n", - sec_desc_size(*ppdesc))); + DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with sd_size %d\n", + ndr_size_security_descriptor(*ppdesc, 0))); return NT_STATUS_OK; } +NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp, + uint32 security_info, + SEC_DESC **ppdesc, SMB4ACL_T *acl) +{ + SMB_STRUCT_STAT sbuf; + + DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp->fsp_name)); + + if (smbacl4_fGetFileOwner(fsp, &sbuf)) { + return map_nt_error_from_unix(errno); + } + + return smb_get_nt_acl_nfs4_common(&sbuf, security_info, ppdesc, acl); +} + +NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn, + const char *name, + uint32 security_info, + SEC_DESC **ppdesc, SMB4ACL_T *acl) +{ + SMB_STRUCT_STAT sbuf; + + DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", name)); + + if (smbacl4_GetFileOwner(conn, name, &sbuf)) { + return map_nt_error_from_unix(errno); + } + + return smb_get_nt_acl_nfs4_common(&sbuf, security_info, ppdesc, acl); +} + enum smbacl4_mode_enum {e_simple=0, e_special=1}; enum smbacl4_acedup_enum {e_dontcare=0, e_reject=1, e_ignore=2, e_merge=3}; @@ -316,6 +355,7 @@ typedef struct _smbacl4_vfs_params { enum smbacl4_mode_enum mode; bool do_chown; enum smbacl4_acedup_enum acedup; + struct db_context *sid_mapping_table; } smbacl4_vfs_params; /* @@ -415,8 +455,65 @@ static SMB_ACE4PROP_T *smbacl4_find_equal_special( return NULL; } -static int smbacl4_fill_ace4( +static bool nfs4_map_sid(smbacl4_vfs_params *params, const DOM_SID *src, + DOM_SID *dst) +{ + static struct db_context *mapping_db = NULL; + TDB_DATA data; + + if (mapping_db == NULL) { + const char *dbname = lp_parm_const_string( + -1, SMBACL4_PARAM_TYPE_NAME, "sidmap", NULL); + + if (dbname == NULL) { + DEBUG(10, ("%s:sidmap not defined\n", + SMBACL4_PARAM_TYPE_NAME)); + return False; + } + + become_root(); + mapping_db = db_open(NULL, dbname, 0, TDB_DEFAULT, + O_RDONLY, 0600); + unbecome_root(); + + if (mapping_db == NULL) { + DEBUG(1, ("could not open sidmap: %s\n", + strerror(errno))); + return False; + } + } + + if (mapping_db->fetch(mapping_db, NULL, + string_term_tdb_data(sid_string_tos(src)), + &data) == -1) { + DEBUG(10, ("could not find mapping for SID %s\n", + sid_string_dbg(src))); + return False; + } + + if ((data.dptr == NULL) || (data.dsize <= 0) + || (data.dptr[data.dsize-1] != '\0')) { + DEBUG(5, ("invalid mapping for SID %s\n", + sid_string_dbg(src))); + TALLOC_FREE(data.dptr); + return False; + } + + if (!string_to_sid(dst, (char *)data.dptr)) { + DEBUG(1, ("invalid mapping %s for SID %s\n", + (char *)data.dptr, sid_string_dbg(src))); + TALLOC_FREE(data.dptr); + return False; + } + + TALLOC_FREE(data.dptr); + + return True; +} + +static bool smbacl4_fill_ace4( TALLOC_CTX *mem_ctx, + const char *filename, smbacl4_vfs_params *params, uid_t ownerUID, gid_t ownerGID, @@ -424,11 +521,6 @@ static int smbacl4_fill_ace4( SMB_ACE4PROP_T *ace_v4 /* output */ ) { - const char *dom, *name; - enum lsa_SidType type; - uid_t uid; - gid_t gid; - DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee))); memset(ace_v4, 0, sizeof(SMB_ACE4PROP_T)); @@ -449,18 +541,46 @@ static int smbacl4_fill_ace4( ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE; ace_v4->flags |= SMB_ACE4_ID_SPECIAL; } else { - if (!lookup_sid(mem_ctx, &ace_nt->trustee, &dom, &name, &type)) { - DEBUG(8, ("Could not find %s' type\n", - sid_string_dbg(&ace_nt->trustee))); - errno = EINVAL; - return -1; + const char *dom, *name; + enum lsa_SidType type; + uid_t uid; + gid_t gid; + DOM_SID sid; + + sid_copy(&sid, &ace_nt->trustee); + + if (!lookup_sid(mem_ctx, &sid, &dom, &name, &type)) { + + DOM_SID mapped; + + if (!nfs4_map_sid(params, &sid, &mapped)) { + DEBUG(1, ("nfs4_acls.c: file [%s]: SID %s " + "unknown\n", filename, sid_string_dbg(&sid))); + errno = EINVAL; + return False; + } + + DEBUG(2, ("nfs4_acls.c: file [%s]: mapped SID %s " + "to %s\n", filename, sid_string_dbg(&sid), sid_string_dbg(&mapped))); + + if (!lookup_sid(mem_ctx, &mapped, &dom, + &name, &type)) { + DEBUG(1, ("nfs4_acls.c: file [%s]: SID %s " + "mapped from %s is unknown\n", + filename, sid_string_dbg(&mapped), sid_string_dbg(&sid))); + errno = EINVAL; + return False; + } + + sid_copy(&sid, &mapped); } - + if (type == SID_NAME_USER) { - if (!sid_to_uid(&ace_nt->trustee, &uid)) { - DEBUG(2, ("Could not convert %s to uid\n", - sid_string_dbg(&ace_nt->trustee))); - return -1; + if (!sid_to_uid(&sid, &uid)) { + DEBUG(1, ("nfs4_acls.c: file [%s]: could not " + "convert %s to uid\n", filename, + sid_string_dbg(&sid))); + return False; } if (params->mode==e_special && uid==ownerUID) { @@ -470,11 +590,13 @@ static int smbacl4_fill_ace4( ace_v4->who.uid = uid; } } else { /* else group? - TODO check it... */ - if (!sid_to_gid(&ace_nt->trustee, &gid)) { - DEBUG(2, ("Could not convert %s to gid\n", - sid_string_dbg(&ace_nt->trustee))); - return -1; + if (!sid_to_gid(&sid, &gid)) { + DEBUG(1, ("nfs4_acls.c: file [%s]: could not " + "convert %s to gid\n", filename, + sid_string_dbg(&sid))); + return False; } + ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP; if (params->mode==e_special && gid==ownerGID) { @@ -486,7 +608,7 @@ static int smbacl4_fill_ace4( } } - return 0; /* OK */ + return True; /* OK */ } static int smbacl4_MergeIgnoreReject( @@ -524,6 +646,7 @@ static int smbacl4_MergeIgnoreReject( } static SMB4ACL_T *smbacl4_win2nfs4( + const char *filename, SEC_ACL *dacl, smbacl4_vfs_params *pparams, uid_t ownerUID, @@ -544,9 +667,14 @@ static SMB4ACL_T *smbacl4_win2nfs4( SMB_ACE4PROP_T ace_v4; bool addNewACE = True; - if (smbacl4_fill_ace4(mem_ctx, pparams, ownerUID, ownerGID, - dacl->aces + i, &ace_v4)) - return NULL; + if (!smbacl4_fill_ace4(mem_ctx, filename, pparams, + ownerUID, ownerGID, + dacl->aces + i, &ace_v4)) { + DEBUG(3, ("Could not fill ace for file %s, SID %s\n", + filename, + sid_string_dbg(&((dacl->aces+i)->trustee)))); + continue; + } if (pparams->acedup!=e_dontcare) { if (smbacl4_MergeIgnoreReject(pparams->acedup, acl, @@ -571,6 +699,7 @@ NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp, bool result; SMB_STRUCT_STAT sbuf; + bool need_chown = False; uid_t newUID = (uid_t)-1; gid_t newGID = (gid_t)-1; @@ -588,7 +717,7 @@ NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp, if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, fsp, ¶ms)) return NT_STATUS_NO_MEMORY; - if (smbacl4_GetFileOwner(fsp, &sbuf)) + if (smbacl4_fGetFileOwner(fsp, &sbuf)) return map_nt_error_from_unix(errno); if (params.do_chown) { @@ -599,25 +728,33 @@ NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp, return status; } if (((newUID != (uid_t)-1) && (sbuf.st_uid != newUID)) || - ((newGID != (gid_t)-1) && (sbuf.st_gid != newGID))) { - if(try_chown(fsp->conn, fsp->fsp_name, newUID, newGID)) { - DEBUG(3,("chown %s, %u, %u failed. Error = %s.\n", - fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID, strerror(errno) )); - if (errno == EPERM) { - return NT_STATUS_INVALID_OWNER; + ((newGID != (gid_t)-1) && (sbuf.st_gid != newGID))) { + need_chown = True; + } + if (need_chown) { + if ((newUID == (uid_t)-1 || newUID == current_user.ut.uid)) { + if(try_chown(fsp->conn, fsp->fsp_name, newUID, newGID)) { + DEBUG(3,("chown %s, %u, %u failed. Error = %s.\n", + fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID, + strerror(errno))); + return map_nt_error_from_unix(errno); } - return map_nt_error_from_unix(errno); + + DEBUG(10,("chown %s, %u, %u succeeded.\n", + fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID)); + if (smbacl4_GetFileOwner(fsp->conn, fsp->fsp_name, &sbuf)) + return map_nt_error_from_unix(errno); + need_chown = False; + } else { /* chown is needed, but _after_ changing acl */ + sbuf.st_uid = newUID; /* OWNER@ in case of e_special */ + sbuf.st_gid = newGID; /* GROUP@ in case of e_special */ } - DEBUG(10,("chown %s, %u, %u succeeded.\n", - fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID)); - if (smbacl4_GetFileOwner(fsp, &sbuf)) - return map_nt_error_from_unix(errno); } } if ((security_info_sent & DACL_SECURITY_INFORMATION)!=0 && psd->dacl!=NULL) { - acl = smbacl4_win2nfs4(psd->dacl, ¶ms, sbuf.st_uid, sbuf.st_gid); + acl = smbacl4_win2nfs4(fsp->fsp_name, psd->dacl, ¶ms, sbuf.st_uid, sbuf.st_gid); if (!acl) return map_nt_error_from_unix(errno); @@ -632,6 +769,20 @@ NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp, } else DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n", security_info_sent)); + /* Any chown pending? */ + if (need_chown) { + DEBUG(3,("chown#2 %s. uid = %u, gid = %u.\n", + fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID)); + if (try_chown(fsp->conn, fsp->fsp_name, newUID, newGID)) { + DEBUG(2,("chown#2 %s, %u, %u failed. Error = %s.\n", + fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID, + strerror(errno))); + return map_nt_error_from_unix(errno); + } + DEBUG(10,("chown#2 %s, %u, %u succeeded.\n", + fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID)); + } + DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n")); return NT_STATUS_OK; } diff --git a/source3/modules/nfs4_acls.h b/source3/modules/nfs4_acls.h index ceb66ec094..0f783aa977 100644 --- a/source3/modules/nfs4_acls.h +++ b/source3/modules/nfs4_acls.h @@ -129,7 +129,12 @@ SMB4ACE_T *smb_next_ace4(SMB4ACE_T *ace); uint32 smb_get_naces(SMB4ACL_T *acl); -NTSTATUS smb_get_nt_acl_nfs4(files_struct *fsp, +NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp, + uint32 security_info, + SEC_DESC **ppdesc, SMB4ACL_T *acl); + +NTSTATUS smb_get_nt_acl_nfs4(connection_struct *conn, + const char *name, uint32 security_info, SEC_DESC **ppdesc, SMB4ACL_T *acl); diff --git a/source3/modules/vfs_afsacl.c b/source3/modules/vfs_afsacl.c index a923ce188f..e35bfabb8c 100644 --- a/source3/modules/vfs_afsacl.c +++ b/source3/modules/vfs_afsacl.c @@ -585,15 +585,14 @@ static uint32 nt_to_afs_file_rights(const char *filename, const SEC_ACE *ace) return result; } -static size_t afs_to_nt_acl(struct afs_acl *afs_acl, - struct files_struct *fsp, - uint32 security_info, - struct security_descriptor **ppdesc) +static size_t afs_to_nt_acl_common(struct afs_acl *afs_acl, + SMB_STRUCT_STAT *psbuf, + uint32 security_info, + struct security_descriptor **ppdesc) { SEC_ACE *nt_ace_list; DOM_SID owner_sid, group_sid; SEC_ACCESS mask; - SMB_STRUCT_STAT sbuf; SEC_ACL *psa = NULL; int good_aces; size_t sd_size; @@ -601,19 +600,8 @@ static size_t afs_to_nt_acl(struct afs_acl *afs_acl, struct afs_ace *afs_ace; - if (fsp->is_directory || fsp->fh->fd == -1) { - /* Get the stat struct for the owner info. */ - if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) { - return 0; - } - } else { - if(SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) != 0) { - return 0; - } - } - - uid_to_sid(&owner_sid, sbuf.st_uid); - gid_to_sid(&group_sid, sbuf.st_gid); + uid_to_sid(&owner_sid, psbuf->st_uid); + gid_to_sid(&group_sid, psbuf->st_gid); if (afs_acl->num_aces) { nt_ace_list = TALLOC_ARRAY(mem_ctx, SEC_ACE, afs_acl->num_aces); @@ -639,7 +627,7 @@ static size_t afs_to_nt_acl(struct afs_acl *afs_acl, continue; } - if (fsp->is_directory) + if (S_ISDIR(psbuf->st_mode)) afs_to_nt_dir_rights(afs_ace->rights, &nt_rights, &flag); else @@ -656,7 +644,6 @@ static size_t afs_to_nt_acl(struct afs_acl *afs_acl, if (psa == NULL) return 0; - *ppdesc = make_sec_desc(mem_ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, (security_info & OWNER_SECURITY_INFORMATION) @@ -668,6 +655,42 @@ static size_t afs_to_nt_acl(struct afs_acl *afs_acl, return sd_size; } +static size_t afs_to_nt_acl(struct afs_acl *afs_acl, + struct connection_struct *conn, + const char *name, + uint32 security_info, + struct security_descriptor **ppdesc) +{ + SMB_STRUCT_STAT sbuf; + + /* Get the stat struct for the owner info. */ + if(SMB_VFS_STAT(conn, name, &sbuf) != 0) { + return 0; + } + + return afs_to_nt_acl_common(afs_acl, &sbuf, security_info, ppdesc); +} + +static size_t afs_fto_nt_acl(struct afs_acl *afs_acl, + struct files_struct *fsp, + uint32 security_info, + struct security_descriptor **ppdesc) +{ + SMB_STRUCT_STAT sbuf; + + if (fsp->is_directory || fsp->fh->fd == -1) { + /* Get the stat struct for the owner info. */ + return afs_to_nt_acl(afs_acl, fsp->conn, fsp->fsp_name, + security_info, ppdesc); + } + + if(SMB_VFS_FSTAT(fsp, &sbuf) != 0) { + return 0; + } + + return afs_to_nt_acl_common(afs_acl, &sbuf, security_info, ppdesc); +} + static bool mappable_sid(const DOM_SID *sid) { DOM_SID domain_sid; @@ -830,27 +853,6 @@ static bool afs_get_afs_acl(char *filename, struct afs_acl *acl) return True; } -static NTSTATUS afs_get_nt_acl(struct files_struct *fsp, uint32 security_info, - struct security_descriptor **ppdesc) -{ - struct afs_acl acl; - size_t sd_size; - - DEBUG(5, ("afs_get_nt_acl: %s\n", fsp->fsp_name)); - - sidpts = lp_parm_bool(SNUM(fsp->conn), "afsacl", "sidpts", False); - - if (!afs_get_afs_acl(fsp->fsp_name, &acl)) { - return NT_STATUS_ACCESS_DENIED; - } - - sd_size = afs_to_nt_acl(&acl, fsp, security_info, ppdesc); - - free_afs_acl(&acl); - - return (sd_size != 0) ? NT_STATUS_OK : NT_STATUS_ACCESS_DENIED; -} - /* For setting an AFS ACL we have to take care of the ACEs we could * not properly map to SIDs. Merge all of them into the new ACL. */ @@ -991,22 +993,53 @@ static NTSTATUS afs_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp, static NTSTATUS afsacl_fget_nt_acl(struct vfs_handle_struct *handle, struct files_struct *fsp, - int fd, uint32 security_info, + uint32 security_info, struct security_descriptor **ppdesc) { - return afs_get_nt_acl(fsp, security_info, ppdesc); + struct afs_acl acl; + size_t sd_size; + + DEBUG(5, ("afsacl_fget_nt_acl: %s\n", fsp->fsp_name)); + + sidpts = lp_parm_bool(SNUM(fsp->conn), "afsacl", "sidpts", False); + + if (!afs_get_afs_acl(fsp->fsp_name, &acl)) { + return NT_STATUS_ACCESS_DENIED; + } + + sd_size = afs_fto_nt_acl(&acl, fsp, security_info, ppdesc); + + free_afs_acl(&acl); + + return (sd_size != 0) ? NT_STATUS_OK : NT_STATUS_ACCESS_DENIED; } + static NTSTATUS afsacl_get_nt_acl(struct vfs_handle_struct *handle, - struct files_struct *fsp, const char *name, uint32 security_info, struct security_descriptor **ppdesc) { - return afs_get_nt_acl(fsp, security_info, ppdesc); + struct afs_acl acl; + size_t sd_size; + + DEBUG(5, ("afsacl_get_nt_acl: %s\n", name)); + + sidpts = lp_parm_bool(SNUM(handle->conn), "afsacl", "sidpts", False); + + if (!afs_get_afs_acl(name, &acl)) { + return NT_STATUS_ACCESS_DENIED; + } + + sd_size = afs_to_nt_acl(&acl, handle->conn, name, security_info, + ppdesc); + + free_afs_acl(&acl); + + return (sd_size != 0) ? NT_STATUS_OK : NT_STATUS_ACCESS_DENIED; } NTSTATUS afsacl_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, - int fd, uint32 security_info_sent, + uint32 security_info_sent, SEC_DESC *psd) { return afs_set_nt_acl(handle, fsp, security_info_sent, psd); diff --git a/source3/modules/vfs_aixacl.c b/source3/modules/vfs_aixacl.c index a60470ffc9..726a7f485e 100644 --- a/source3/modules/vfs_aixacl.c +++ b/source3/modules/vfs_aixacl.c @@ -80,8 +80,7 @@ SMB_ACL_T aixacl_sys_acl_get_file(vfs_handle_struct *handle, } SMB_ACL_T aixacl_sys_acl_get_fd(vfs_handle_struct *handle, - files_struct *fsp, - int fd) + files_struct *fsp) { struct acl *file_acl = (struct acl *)NULL; @@ -93,7 +92,7 @@ SMB_ACL_T aixacl_sys_acl_get_fd(vfs_handle_struct *handle, /* Get the acl using fstatacl */ DEBUG(10,("Entering AIX sys_acl_get_fd\n")); - DEBUG(10,("fd is %d\n",fd)); + DEBUG(10,("fd is %d\n",fsp->fh->fd)); file_acl = (struct acl *)SMB_MALLOC(BUFSIZ); if(file_acl == NULL) { @@ -104,7 +103,7 @@ SMB_ACL_T aixacl_sys_acl_get_fd(vfs_handle_struct *handle, memset(file_acl,0,BUFSIZ); - rc = fstatacl(fd,0,file_acl,BUFSIZ); + rc = fstatacl(fsp->fh->fd,0,file_acl,BUFSIZ); if( (rc == -1) && (errno == ENOSPC)) { struct acl *new_acl = SMB_MALLOC(file_acl->acl_len + sizeof(struct acl)); if( new_acl == NULL) { @@ -113,7 +112,7 @@ SMB_ACL_T aixacl_sys_acl_get_fd(vfs_handle_struct *handle, return NULL; } file_acl = new_acl; - rc = fstatacl(fd,0,file_acl,file_acl->acl_len + sizeof(struct acl)); + rc = fstatacl(fsp->fh->fd,0,file_acl,file_acl->acl_len + sizeof(struct acl)); if( rc == -1) { DEBUG(0,("fstatacl returned %d with errno %d\n",rc,errno)); SAFE_FREE(file_acl); @@ -154,7 +153,7 @@ int aixacl_sys_acl_set_file(vfs_handle_struct *handle, int aixacl_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, - int fd, SMB_ACL_T theacl) + SMB_ACL_T theacl) { struct acl *file_acl = NULL; unsigned int rc; @@ -163,7 +162,7 @@ int aixacl_sys_acl_set_fd(vfs_handle_struct *handle, if (!file_acl) return -1; - rc = fchacl(fd,file_acl,file_acl->acl_len); + rc = fchacl(fsp->fh->fd,file_acl,file_acl->acl_len); DEBUG(10,("errno is %d\n",errno)); DEBUG(10,("return code is %d\n",rc)); SAFE_FREE(file_acl); diff --git a/source3/modules/vfs_aixacl2.c b/source3/modules/vfs_aixacl2.c index 756977df4f..996adbbdfe 100644 --- a/source3/modules/vfs_aixacl2.c +++ b/source3/modules/vfs_aixacl2.c @@ -98,7 +98,7 @@ static AIXJFS2_ACL_T *aixjfs2_getacl_alloc(const char *fname, acl_type_t *type) return acl; } -static bool aixjfs2_get_nfs4_acl(files_struct *fsp, +static bool aixjfs2_get_nfs4_acl(const char *name, SMB4ACL_T **ppacl, bool *pretryPosix) { int32_t i; @@ -108,15 +108,15 @@ static bool aixjfs2_get_nfs4_acl(files_struct *fsp, nfs4_ace_int_t *jfs2_ace = NULL; acl_type_t type; - DEBUG(10,("jfs2 get_nt_acl invoked for %s\n", fsp->fsp_name)); + DEBUG(10,("jfs2 get_nt_acl invoked for %s\n", name)); memset(&type, 0, sizeof(acl_type_t)); type.u64 = ACL_NFS4; - pacl = aixjfs2_getacl_alloc(fsp->fsp_name, &type); + pacl = aixjfs2_getacl_alloc(name, &type); if (pacl == NULL) { DEBUG(9, ("aixjfs2_getacl_alloc failed for %s with %s\n", - fsp->fsp_name, strerror(errno))); + name, strerror(errno))); if (errno==ENOSYS) *pretryPosix = True; return False; @@ -158,38 +158,48 @@ static bool aixjfs2_get_nfs4_acl(files_struct *fsp, return True; } -static NTSTATUS aixjfs2_get_nt_acl_common(files_struct *fsp, - uint32 security_info, SEC_DESC **ppdesc) +static NTSTATUS aixjfs2_fget_nt_acl(vfs_handle_struct *handle, + files_struct *fsp, uint32 security_info, + SEC_DESC **ppdesc) { SMB4ACL_T *pacl = NULL; bool result; bool retryPosix = False; *ppdesc = NULL; - result = aixjfs2_get_nfs4_acl(fsp, &pacl, &retryPosix); + result = aixjfs2_get_nfs4_acl(fsp->fsp_name, &pacl, &retryPosix); if (retryPosix) { DEBUG(10, ("retrying with posix acl...\n")); - return get_nt_acl(fsp, security_info, ppdesc); + return posix_fget_nt_acl(fsp, security_info, ppdesc); } if (result==False) return NT_STATUS_ACCESS_DENIED; - return smb_get_nt_acl_nfs4(fsp, security_info, ppdesc, pacl); + return smb_fget_nt_acl_nfs4(fsp, security_info, ppdesc, pacl); } -NTSTATUS aixjfs2_fget_nt_acl(vfs_handle_struct *handle, - files_struct *fsp, int fd, uint32 security_info, - SEC_DESC **ppdesc) -{ - return aixjfs2_get_nt_acl_common(fsp, security_info, ppdesc); -} - -NTSTATUS aixjfs2_get_nt_acl(vfs_handle_struct *handle, +static NTSTATUS aixjfs2_get_nt_acl(vfs_handle_struct *handle, files_struct *fsp, const char *name, uint32 security_info, SEC_DESC **ppdesc) { - return aixjfs2_get_nt_acl_common(fsp, security_info, ppdesc); + SMB4ACL_T *pacl = NULL; + bool result; + bool retryPosix = False; + + *ppdesc = NULL; + result = aixjfs2_get_nfs4_acl(name, &pacl, &retryPosix); + if (retryPosix) + { + DEBUG(10, ("retrying with posix acl...\n")); + return posix_get_nt_acl(handle->conn, name security_info, + ppdesc); + } + if (result==False) + return NT_STATUS_ACCESS_DENIED; + + return smb_get_nt_acl_nfs4(handle->conn, name, security_info, ppdesc, + pacl); } static SMB_ACL_T aixjfs2_get_posix_acl(const char *path, acl_type_t type) @@ -248,8 +258,7 @@ SMB_ACL_T aixjfs2_sys_acl_get_file(vfs_handle_struct *handle, } SMB_ACL_T aixjfs2_sys_acl_get_fd(vfs_handle_struct *handle, - files_struct *fsp, - int fd) + files_struct *fsp) { acl_type_t aixjfs2_type; aixjfs2_type.u64 = ACL_AIXC; @@ -389,7 +398,7 @@ static NTSTATUS aixjfs2_set_nt_acl_common(files_struct *fsp, uint32 security_inf return result; } -NTSTATUS aixjfs2_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, int fd, uint32 security_info_sent, SEC_DESC *psd) +NTSTATUS aixjfs2_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) { return aixjfs2_set_nt_acl_common(fsp, security_info_sent, psd); } @@ -439,7 +448,7 @@ int aixjfs2_sys_acl_set_file(vfs_handle_struct *handle, int aixjfs2_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, - int fd, SMB_ACL_T theacl) + SMB_ACL_T theacl) { struct acl *acl_aixc; acl_type_t acl_type_info; @@ -458,7 +467,7 @@ int aixjfs2_sys_acl_set_fd(vfs_handle_struct *handle, return -1; rc = aclx_fput( - fd, + fsp->fh->fd, SET_ACL, /* set only the ACL, not mode bits */ acl_type_info, acl_aixc, diff --git a/source3/modules/vfs_audit.c b/source3/modules/vfs_audit.c index 91993a47d7..a63bf4f672 100644 --- a/source3/modules/vfs_audit.c +++ b/source3/modules/vfs_audit.c @@ -39,8 +39,8 @@ static int audit_rename(vfs_handle_struct *handle, const char *oldname, const ch static int audit_unlink(vfs_handle_struct *handle, const char *path); static int audit_chmod(vfs_handle_struct *handle, const char *path, mode_t mode); static int audit_chmod_acl(vfs_handle_struct *handle, const char *name, mode_t mode); -static int audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, int fd, mode_t mode); -static int audit_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, int fd, mode_t mode); +static int audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode); +static int audit_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, mode_t mode); /* VFS operations */ @@ -268,11 +268,11 @@ static int audit_chmod_acl(vfs_handle_struct *handle, const char *path, mode_t m return result; } -static int audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, int fd, mode_t mode) +static int audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode) { int result; - result = SMB_VFS_NEXT_FCHMOD(handle, fsp, fd, mode); + result = SMB_VFS_NEXT_FCHMOD(handle, fsp, mode); syslog(audit_syslog_priority(handle), "fchmod %s mode 0x%x %s%s\n", fsp->fsp_name, mode, @@ -282,11 +282,11 @@ static int audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, int fd, mo return result; } -static int audit_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, int fd, mode_t mode) +static int audit_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, mode_t mode) { int result; - result = SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, fd, mode); + result = SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, mode); syslog(audit_syslog_priority(handle), "fchmod_acl %s mode 0x%x %s%s\n", fsp->fsp_name, mode, diff --git a/source3/modules/vfs_cacheprime.c b/source3/modules/vfs_cacheprime.c index 9574087d9d..be934f6bd6 100644 --- a/source3/modules/vfs_cacheprime.c +++ b/source3/modules/vfs_cacheprime.c @@ -48,7 +48,6 @@ static void * g_readbuf = NULL; static bool prime_cache( struct vfs_handle_struct * handle, files_struct * fsp, - int fd, SMB_OFF_T offset, size_t count) { @@ -75,7 +74,7 @@ static bool prime_cache( MODULE, (long long)g_readsz, (long long)*last, fsp->fsp_name)); - nread = sys_pread(fd, g_readbuf, g_readsz, *last); + nread = sys_pread(fsp->fh->fd, g_readbuf, g_readsz, *last); if (nread < 0) { *last = -1; return False; @@ -125,51 +124,48 @@ static int cprime_connect( static ssize_t cprime_sendfile( struct vfs_handle_struct * handle, int tofd, - files_struct * fsp, - int fromfd, + files_struct * fromfsp, const DATA_BLOB * header, SMB_OFF_T offset, size_t count) { if (g_readbuf && offset == 0) { - prime_cache(handle, fsp, fromfd, offset, count); + prime_cache(handle, fromfsp, offset, count); } - return SMB_VFS_NEXT_SENDFILE(handle, tofd, fsp, fromfd, + return SMB_VFS_NEXT_SENDFILE(handle, tofd, fromfsp, header, offset, count); } static ssize_t cprime_read( vfs_handle_struct * handle, files_struct * fsp, - int fd, void * data, size_t count) { SMB_OFF_T offset; - offset = SMB_VFS_LSEEK(fsp, fd, 0, SEEK_CUR); + offset = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR); if (offset >= 0 && g_readbuf) { - prime_cache(handle, fsp, fd, offset, count); - SMB_VFS_LSEEK(fsp, fd, offset, SEEK_SET); + prime_cache(handle, fsp, offset, count); + SMB_VFS_LSEEK(fsp, offset, SEEK_SET); } - return SMB_VFS_NEXT_READ(handle, fsp, fd, data, count); + return SMB_VFS_NEXT_READ(handle, fsp, data, count); } static ssize_t cprime_pread( vfs_handle_struct * handle, files_struct * fsp, - int fd, void * data, size_t count, SMB_OFF_T offset) { if (g_readbuf) { - prime_cache(handle, fsp, fd, offset, count); + prime_cache(handle, fsp, offset, count); } - return SMB_VFS_NEXT_PREAD(handle, fsp, fd, data, count, offset); + return SMB_VFS_NEXT_PREAD(handle, fsp, data, count, offset); } static vfs_op_tuple cprime_ops [] = diff --git a/source3/modules/vfs_cap.c b/source3/modules/vfs_cap.c index f99891cb32..2f2d6a7182 100644 --- a/source3/modules/vfs_cap.c +++ b/source3/modules/vfs_cap.c @@ -363,7 +363,7 @@ size) return SMB_VFS_NEXT_LGETXATTR(handle, cappath, capname, value, size); } -static ssize_t cap_fgetxattr(vfs_handle_struct *handle, struct files_struct *fsp,int fd, const char *path, void *value, size_t size) +static ssize_t cap_fgetxattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path, void *value, size_t size) { char *cappath = capencode(talloc_tos(), path); @@ -371,7 +371,7 @@ static ssize_t cap_fgetxattr(vfs_handle_struct *handle, struct files_struct *fsp errno = ENOMEM; return -1; } - return SMB_VFS_NEXT_FGETXATTR(handle, fsp, fd, cappath, value, size); + return SMB_VFS_NEXT_FGETXATTR(handle, fsp, cappath, value, size); } static ssize_t cap_listxattr(vfs_handle_struct *handle, const char *path, char *list, size_t size) @@ -420,7 +420,7 @@ static int cap_lremovexattr(vfs_handle_struct *handle, const char *path, const c return SMB_VFS_NEXT_LREMOVEXATTR(handle, cappath, capname); } -static int cap_fremovexattr(vfs_handle_struct *handle, struct files_struct *fsp,int fd, const char *path) +static int cap_fremovexattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path) { char *cappath = capencode(talloc_tos(), path); @@ -428,7 +428,7 @@ static int cap_fremovexattr(vfs_handle_struct *handle, struct files_struct *fsp, errno = ENOMEM; return -1; } - return SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, fd, cappath); + return SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, cappath); } static int cap_setxattr(vfs_handle_struct *handle, const char *path, const char *name, const void *value, size_t size, int flags) @@ -455,7 +455,7 @@ static int cap_lsetxattr(vfs_handle_struct *handle, const char *path, const char return SMB_VFS_NEXT_LSETXATTR(handle, cappath, capname, value, size, flags); } -static int cap_fsetxattr(vfs_handle_struct *handle, struct files_struct *fsp,int fd, const char *path, const void *value, size_t size, int flags) +static int cap_fsetxattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path, const void *value, size_t size, int flags) { char *cappath = capencode(talloc_tos(), path); @@ -463,7 +463,7 @@ static int cap_fsetxattr(vfs_handle_struct *handle, struct files_struct *fsp,int errno = ENOMEM; return -1; } - return SMB_VFS_NEXT_FSETXATTR(handle, fsp, fd, cappath, value, size, flags); + return SMB_VFS_NEXT_FSETXATTR(handle, fsp, cappath, value, size, flags); } /* VFS operations structure */ diff --git a/source3/modules/vfs_catia.c b/source3/modules/vfs_catia.c index 71f478a8a9..ab48c963ec 100644 --- a/source3/modules/vfs_catia.c +++ b/source3/modules/vfs_catia.c @@ -290,8 +290,7 @@ static NTSTATUS catia_get_nt_acl(vfs_handle_struct *handle, files_struct *fsp, const char *name, uint32 security_info, struct security_descriptor **ppdesc) { - return SMB_VFS_NEXT_GET_NT_ACL(handle, fsp, name, security_info, - ppdesc); + return SMB_VFS_NEXT_GET_NT_ACL(handle, name, security_info, ppdesc); } static NTSTATUS catia_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp, diff --git a/source3/modules/vfs_commit.c b/source3/modules/vfs_commit.c index d7d81924f1..ac391cf007 100644 --- a/source3/modules/vfs_commit.c +++ b/source3/modules/vfs_commit.c @@ -217,7 +217,7 @@ static int commit_open( /* EOF commit modes require us to know the initial file size. */ if (c && (c->on_eof != EOF_NONE)) { SMB_STRUCT_STAT st; - if (SMB_VFS_FSTAT(fsp, fd, &st) == -1) { + if (SMB_VFS_FSTAT(fsp, &st) == -1) { return -1; } c->eof = st.st_size; @@ -229,12 +229,11 @@ static int commit_open( static ssize_t commit_write( vfs_handle_struct * handle, files_struct * fsp, - int fd, void * data, size_t count) { ssize_t ret; - ret = SMB_VFS_NEXT_WRITE(handle, fsp, fd, data, count); + ret = SMB_VFS_NEXT_WRITE(handle, fsp, data, count); if (ret > 0) { if (commit(handle, fsp, fsp->fh->pos, ret) == -1) { @@ -248,14 +247,13 @@ static ssize_t commit_write( static ssize_t commit_pwrite( vfs_handle_struct * handle, files_struct * fsp, - int fd, void * data, size_t count, SMB_OFF_T offset) { ssize_t ret; - ret = SMB_VFS_NEXT_PWRITE(handle, fsp, fd, data, count, offset); + ret = SMB_VFS_NEXT_PWRITE(handle, fsp, data, count, offset); if (ret > 0) { if (commit(handle, fsp, offset, ret) == -1) { return -1; @@ -278,12 +276,11 @@ static int commit_close( static int commit_ftruncate( vfs_handle_struct * handle, files_struct * fsp, - int fd, SMB_OFF_T len) { int result; - result = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, fd, len); + result = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, len); if (result == 0) { struct commit_info *c; if ((c = VFS_FETCH_FSP_EXTENSION(handle, fsp))) { diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index cce5430493..cf135dfd03 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -90,6 +90,17 @@ static int vfswrap_statvfs(struct vfs_handle_struct *handle, const char *path, return sys_statvfs(path, statbuf); } +static uint32_t vfswrap_fs_capabilities(struct vfs_handle_struct *handle) +{ +#if defined(DARWINOS) + struct vfs_statvfs_struct statbuf; + ZERO_STRUCT(statbuf); + sys_statvfs(handle->conn->connectpath, &statbuf); + return statbuf.FsCapabilities; +#endif + return FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES; +} + /* Directory operations */ static SMB_STRUCT_DIR *vfswrap_opendir(vfs_handle_struct *handle, const char *fname, const char *mask, uint32 attr) @@ -208,29 +219,29 @@ static int vfswrap_close(vfs_handle_struct *handle, files_struct *fsp, int fd) return result; } -static ssize_t vfswrap_read(vfs_handle_struct *handle, files_struct *fsp, int fd, void *data, size_t n) +static ssize_t vfswrap_read(vfs_handle_struct *handle, files_struct *fsp, void *data, size_t n) { ssize_t result; START_PROFILE_BYTES(syscall_read, n); - result = sys_read(fd, data, n); + result = sys_read(fsp->fh->fd, data, n); END_PROFILE(syscall_read); return result; } -static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, int fd, void *data, +static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, void *data, size_t n, SMB_OFF_T offset) { ssize_t result; #if defined(HAVE_PREAD) || defined(HAVE_PREAD64) START_PROFILE_BYTES(syscall_pread, n); - result = sys_pread(fd, data, n, offset); + result = sys_pread(fsp->fh->fd, data, n, offset); END_PROFILE(syscall_pread); if (result == -1 && errno == ESPIPE) { /* Maintain the fiction that pipes can be seeked (sought?) on. */ - result = SMB_VFS_READ(fsp, fd, data, n); + result = SMB_VFS_READ(fsp, data, n); fsp->fh->pos = 0; } @@ -238,23 +249,23 @@ static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, int f SMB_OFF_T curr; int lerrno; - curr = SMB_VFS_LSEEK(fsp, fd, 0, SEEK_CUR); + curr = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR); if (curr == -1 && errno == ESPIPE) { /* Maintain the fiction that pipes can be seeked (sought?) on. */ - result = SMB_VFS_READ(fsp, fd, data, n); + result = SMB_VFS_READ(fsp, data, n); fsp->fh->pos = 0; return result; } - if (SMB_VFS_LSEEK(fsp, fd, offset, SEEK_SET) == -1) { + if (SMB_VFS_LSEEK(fsp, offset, SEEK_SET) == -1) { return -1; } errno = 0; - result = SMB_VFS_READ(fsp, fd, data, n); + result = SMB_VFS_READ(fsp, data, n); lerrno = errno; - SMB_VFS_LSEEK(fsp, fd, curr, SEEK_SET); + SMB_VFS_LSEEK(fsp, curr, SEEK_SET); errno = lerrno; #endif /* HAVE_PREAD */ @@ -262,48 +273,48 @@ static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, int f return result; } -static ssize_t vfswrap_write(vfs_handle_struct *handle, files_struct *fsp, int fd, const void *data, size_t n) +static ssize_t vfswrap_write(vfs_handle_struct *handle, files_struct *fsp, const void *data, size_t n) { ssize_t result; START_PROFILE_BYTES(syscall_write, n); - result = sys_write(fd, data, n); + result = sys_write(fsp->fh->fd, data, n); END_PROFILE(syscall_write); return result; } -static ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, int fd, const void *data, +static ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, const void *data, size_t n, SMB_OFF_T offset) { ssize_t result; #if defined(HAVE_PWRITE) || defined(HAVE_PRWITE64) START_PROFILE_BYTES(syscall_pwrite, n); - result = sys_pwrite(fd, data, n, offset); + result = sys_pwrite(fsp->fh->fd, data, n, offset); END_PROFILE(syscall_pwrite); if (result == -1 && errno == ESPIPE) { /* Maintain the fiction that pipes can be sought on. */ - result = SMB_VFS_WRITE(fsp, fd, data, n); + result = SMB_VFS_WRITE(fsp, data, n); } #else /* HAVE_PWRITE */ SMB_OFF_T curr; int lerrno; - curr = SMB_VFS_LSEEK(fsp, fd, 0, SEEK_CUR); + curr = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR); if (curr == -1) { return -1; } - if (SMB_VFS_LSEEK(fsp, fd, offset, SEEK_SET) == -1) { + if (SMB_VFS_LSEEK(fsp, offset, SEEK_SET) == -1) { return -1; } - result = SMB_VFS_WRITE(fsp, fd, data, n); + result = SMB_VFS_WRITE(fsp, data, n); lerrno = errno; - SMB_VFS_LSEEK(fsp, fd, curr, SEEK_SET); + SMB_VFS_LSEEK(fsp, curr, SEEK_SET); errno = lerrno; #endif /* HAVE_PWRITE */ @@ -311,15 +322,15 @@ static ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, int return result; } -static SMB_OFF_T vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, int filedes, SMB_OFF_T offset, int whence) +static SMB_OFF_T vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, SMB_OFF_T offset, int whence) { SMB_OFF_T result = 0; START_PROFILE(syscall_lseek); /* Cope with 'stat' file opens. */ - if (filedes != -1) - result = sys_lseek(filedes, offset, whence); + if (fsp->fh->fd != -1) + result = sys_lseek(fsp->fh->fd, offset, whence); /* * We want to maintain the fiction that we can seek @@ -337,28 +348,27 @@ static SMB_OFF_T vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, int return result; } -static ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fsp, int fromfd, const DATA_BLOB *hdr, +static ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr, SMB_OFF_T offset, size_t n) { ssize_t result; START_PROFILE_BYTES(syscall_sendfile, n); - result = sys_sendfile(tofd, fromfd, hdr, offset, n); + result = sys_sendfile(tofd, fromfsp->fh->fd, hdr, offset, n); END_PROFILE(syscall_sendfile); return result; } static ssize_t vfswrap_recvfile(vfs_handle_struct *handle, int fromfd, - files_struct *fsp, - int tofd, + files_struct *tofsp, SMB_OFF_T offset, size_t n) { ssize_t result; START_PROFILE_BYTES(syscall_recvfile, n); - result = sys_recvfile(fromfd, tofd, offset, n); + result = sys_recvfile(fromfd, tofsp->fh->fd, offset, n); END_PROFILE(syscall_recvfile); return result; } @@ -467,13 +477,13 @@ static int vfswrap_rename(vfs_handle_struct *handle, const char *oldname, const return result; } -static int vfswrap_fsync(vfs_handle_struct *handle, files_struct *fsp, int fd) +static int vfswrap_fsync(vfs_handle_struct *handle, files_struct *fsp) { #ifdef HAVE_FSYNC int result; START_PROFILE(syscall_fsync); - result = fsync(fd); + result = fsync(fsp->fh->fd); END_PROFILE(syscall_fsync); return result; #else @@ -491,12 +501,12 @@ static int vfswrap_stat(vfs_handle_struct *handle, const char *fname, SMB_STRUC return result; } -static int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_STRUCT_STAT *sbuf) +static int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf) { int result; START_PROFILE(syscall_fstat); - result = sys_fstat(fd, sbuf); + result = sys_fstat(fsp->fh->fd, sbuf); END_PROFILE(syscall_fstat); return result; } @@ -549,7 +559,7 @@ static int vfswrap_chmod(vfs_handle_struct *handle, const char *path, mode_t mo return result; } -static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, int fd, mode_t mode) +static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode) { int result; @@ -563,7 +573,7 @@ static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, int fd, { int saved_errno = errno; /* We might get ENOSYS */ - if ((result = SMB_VFS_FCHMOD_ACL(fsp, fd, mode)) == 0) { + if ((result = SMB_VFS_FCHMOD_ACL(fsp, mode)) == 0) { END_PROFILE(syscall_fchmod); return result; } @@ -572,7 +582,7 @@ static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, int fd, } #if defined(HAVE_FCHMOD) - result = fchmod(fd, mode); + result = fchmod(fsp->fh->fd, mode); #else result = -1; errno = ENOSYS; @@ -592,13 +602,13 @@ static int vfswrap_chown(vfs_handle_struct *handle, const char *path, uid_t uid, return result; } -static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, int fd, uid_t uid, gid_t gid) +static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid) { #ifdef HAVE_FCHOWN int result; START_PROFILE(syscall_fchown); - result = fchown(fd, uid, gid); + result = fchown(fsp->fh->fd, uid, gid); END_PROFILE(syscall_fchown); return result; #else @@ -674,17 +684,17 @@ static int vfswrap_ntimes(vfs_handle_struct *handle, const char *path, const str allocate is set. **********************************************************************/ -static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_OFF_T len) +static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, SMB_OFF_T len) { SMB_STRUCT_STAT st; - SMB_OFF_T currpos = SMB_VFS_LSEEK(fsp, fd, 0, SEEK_CUR); + SMB_OFF_T currpos = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR); unsigned char zero_space[4096]; SMB_OFF_T space_to_write; if (currpos == -1) return -1; - if (SMB_VFS_FSTAT(fsp, fd, &st) == -1) + if (SMB_VFS_FSTAT(fsp, &st) == -1) return -1; space_to_write = len - st.st_size; @@ -699,10 +709,10 @@ static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fs /* Shrink - just ftruncate. */ if (st.st_size > len) - return sys_ftruncate(fd, len); + return sys_ftruncate(fsp->fh->fd, len); /* Write out the real space on disk. */ - if (SMB_VFS_LSEEK(fsp, fd, st.st_size, SEEK_SET) != st.st_size) + if (SMB_VFS_LSEEK(fsp, st.st_size, SEEK_SET) != st.st_size) return -1; space_to_write = len - st.st_size; @@ -712,7 +722,7 @@ static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fs SMB_OFF_T retlen; SMB_OFF_T current_len_to_write = MIN(sizeof(zero_space),space_to_write); - retlen = SMB_VFS_WRITE(fsp,fsp->fh->fd,(char *)zero_space,current_len_to_write); + retlen = SMB_VFS_WRITE(fsp,(char *)zero_space,current_len_to_write); if (retlen <= 0) return -1; @@ -720,13 +730,13 @@ static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fs } /* Seek to where we were */ - if (SMB_VFS_LSEEK(fsp, fd, currpos, SEEK_SET) != currpos) + if (SMB_VFS_LSEEK(fsp, currpos, SEEK_SET) != currpos) return -1; return 0; } -static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_OFF_T len) +static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, SMB_OFF_T len) { int result = -1; SMB_STRUCT_STAT st; @@ -736,7 +746,7 @@ static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, int f START_PROFILE(syscall_ftruncate); if (lp_strict_allocate(SNUM(fsp->conn))) { - result = strict_allocate_ftruncate(handle, fsp, fd, len); + result = strict_allocate_ftruncate(handle, fsp, len); END_PROFILE(syscall_ftruncate); return result; } @@ -747,14 +757,14 @@ static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, int f expansion and some that don't! On Linux fat can't do ftruncate extend but ext2 can. */ - result = sys_ftruncate(fd, len); + result = sys_ftruncate(fsp->fh->fd, len); if (result == 0) goto done; /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot extend a file with ftruncate. Provide alternate implementation for this */ - currpos = SMB_VFS_LSEEK(fsp, fd, 0, SEEK_CUR); + currpos = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR); if (currpos == -1) { goto done; } @@ -763,7 +773,7 @@ static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, int f size in which case the ftruncate above should have succeeded or shorter, in which case seek to len - 1 and write 1 byte of zero */ - if (SMB_VFS_FSTAT(fsp, fd, &st) == -1) { + if (SMB_VFS_FSTAT(fsp, &st) == -1) { goto done; } @@ -784,14 +794,14 @@ static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, int f goto done; } - if (SMB_VFS_LSEEK(fsp, fd, len-1, SEEK_SET) != len -1) + if (SMB_VFS_LSEEK(fsp, len-1, SEEK_SET) != len -1) goto done; - if (SMB_VFS_WRITE(fsp, fd, &c, 1)!=1) + if (SMB_VFS_WRITE(fsp, &c, 1)!=1) goto done; /* Seek to where we were */ - if (SMB_VFS_LSEEK(fsp, fd, currpos, SEEK_SET) != currpos) + if (SMB_VFS_LSEEK(fsp, currpos, SEEK_SET) != currpos) goto done; result = 0; @@ -801,36 +811,36 @@ static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, int f return result; } -static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type) +static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, SMB_OFF_T offset, SMB_OFF_T count, int type) { bool result; START_PROFILE(syscall_fcntl_lock); - result = fcntl_lock(fd, op, offset, count, type); + result = fcntl_lock(fsp->fh->fd, op, offset, count, type); END_PROFILE(syscall_fcntl_lock); return result; } -static int vfswrap_kernel_flock(vfs_handle_struct *handle, files_struct *fsp, int fd, +static int vfswrap_kernel_flock(vfs_handle_struct *handle, files_struct *fsp, uint32 share_mode) { START_PROFILE(syscall_kernel_flock); - kernel_flock(fd, share_mode); + kernel_flock(fsp->fh->fd, share_mode); END_PROFILE(syscall_kernel_flock); return 0; } -static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid) +static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid) { bool result; START_PROFILE(syscall_fcntl_getlock); - result = fcntl_getlock(fd, poffset, pcount, ptype, ppid); + result = fcntl_getlock(fsp->fh->fd, poffset, pcount, ptype, ppid); END_PROFILE(syscall_fcntl_getlock); return result; } -static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp, int fd, +static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp, int leasetype) { int result = -1; @@ -839,11 +849,11 @@ static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp, #ifdef HAVE_KERNEL_OPLOCKS_LINUX /* first set the signal handler */ - if(linux_set_lease_sighandler(fd) == -1) { + if(linux_set_lease_sighandler(fsp->fh->fd) == -1) { return -1; } - result = linux_setlease(fd, leasetype); + result = linux_setlease(fsp->fh->fd, leasetype); #else errno = ENOSYS; #endif @@ -943,31 +953,87 @@ static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle, S return file_id_create_dev(dev, inode); } +static NTSTATUS vfswrap_streaminfo(vfs_handle_struct *handle, + struct files_struct *fsp, + const char *fname, + TALLOC_CTX *mem_ctx, + unsigned int *pnum_streams, + struct stream_struct **pstreams) +{ + SMB_STRUCT_STAT sbuf; + unsigned int num_streams = 0; + struct stream_struct *streams = NULL; + int ret; + + if ((fsp != NULL) && (fsp->is_directory)) { + /* + * No default streams on directories + */ + goto done; + } + + if ((fsp != NULL) && (fsp->fh->fd != -1)) { + ret = SMB_VFS_FSTAT(fsp, &sbuf); + } + else { + ret = SMB_VFS_STAT(handle->conn, fname, &sbuf); + } + + if (ret == -1) { + return map_nt_error_from_unix(errno); + } + + if (S_ISDIR(sbuf.st_mode)) { + goto done; + } + + streams = talloc(mem_ctx, struct stream_struct); + + if (streams == NULL) { + return NT_STATUS_NO_MEMORY; + } + + streams->size = sbuf.st_size; + streams->alloc_size = get_allocation_size(handle->conn, fsp, &sbuf); + + streams->name = talloc_strdup(streams, "::$DATA"); + if (streams->name == NULL) { + TALLOC_FREE(streams); + return NT_STATUS_NO_MEMORY; + } + + num_streams = 1; + done: + *pnum_streams = num_streams; + *pstreams = streams; + return NT_STATUS_OK; +} + static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle, - files_struct *fsp, int fd, + files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc) { NTSTATUS result; START_PROFILE(fget_nt_acl); - result = get_nt_acl(fsp, security_info, ppdesc); + result = posix_fget_nt_acl(fsp, security_info, ppdesc); END_PROFILE(fget_nt_acl); return result; } static NTSTATUS vfswrap_get_nt_acl(vfs_handle_struct *handle, - files_struct *fsp, const char *name, + const char *name, uint32 security_info, SEC_DESC **ppdesc) { NTSTATUS result; START_PROFILE(get_nt_acl); - result = get_nt_acl(fsp, security_info, ppdesc); + result = posix_get_nt_acl(handle->conn, name, security_info, ppdesc); END_PROFILE(get_nt_acl); return result; } -static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, int fd, uint32 security_info_sent, SEC_DESC *psd) +static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) { NTSTATUS result; @@ -1002,7 +1068,7 @@ static int vfswrap_chmod_acl(vfs_handle_struct *handle, const char *name, mode_ #endif } -static int vfswrap_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, int fd, mode_t mode) +static int vfswrap_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, mode_t mode) { #ifdef HAVE_NO_ACL errno = ENOSYS; @@ -1011,7 +1077,7 @@ static int vfswrap_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, int int result; START_PROFILE(fchmod_acl); - result = fchmod_acl(fsp, fd, mode); + result = fchmod_acl(fsp, mode); END_PROFILE(fchmod_acl); return result; #endif @@ -1042,9 +1108,9 @@ static SMB_ACL_T vfswrap_sys_acl_get_file(vfs_handle_struct *handle, const char return sys_acl_get_file(handle, path_p, type); } -static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp, int fd) +static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp) { - return sys_acl_get_fd(handle, fsp, fd); + return sys_acl_get_fd(handle, fsp); } static int vfswrap_sys_acl_clear_perms(vfs_handle_struct *handle, SMB_ACL_PERMSET_T permset) @@ -1097,9 +1163,9 @@ static int vfswrap_sys_acl_set_file(vfs_handle_struct *handle, const char *name return sys_acl_set_file(handle, name, acltype, theacl); } -static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_ACL_T theacl) +static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, SMB_ACL_T theacl) { - return sys_acl_set_fd(handle, fsp, fd, theacl); + return sys_acl_set_fd(handle, fsp, theacl); } static int vfswrap_sys_acl_delete_def_file(vfs_handle_struct *handle, const char *path) @@ -1141,9 +1207,9 @@ static ssize_t vfswrap_lgetxattr(struct vfs_handle_struct *handle,const char *pa return sys_lgetxattr(path, name, value, size); } -static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp,int fd, const char *name, void *value, size_t size) +static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, void *value, size_t size) { - return sys_fgetxattr(fd, name, value, size); + return sys_fgetxattr(fsp->fh->fd, name, value, size); } static ssize_t vfswrap_listxattr(struct vfs_handle_struct *handle, const char *path, char *list, size_t size) @@ -1156,9 +1222,9 @@ ssize_t vfswrap_llistxattr(struct vfs_handle_struct *handle, const char *path, c return sys_llistxattr(path, list, size); } -ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp,int fd, char *list, size_t size) +ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size) { - return sys_flistxattr(fd, list, size); + return sys_flistxattr(fsp->fh->fd, list, size); } static int vfswrap_removexattr(struct vfs_handle_struct *handle, const char *path, const char *name) @@ -1171,9 +1237,9 @@ static int vfswrap_lremovexattr(struct vfs_handle_struct *handle, const char *pa return sys_lremovexattr(path, name); } -static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp,int fd, const char *name) +static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name) { - return sys_fremovexattr(fd, name); + return sys_fremovexattr(fsp->fh->fd, name); } static int vfswrap_setxattr(struct vfs_handle_struct *handle, const char *path, const char *name, const void *value, size_t size, int flags) @@ -1186,9 +1252,9 @@ static int vfswrap_lsetxattr(struct vfs_handle_struct *handle, const char *path, return sys_lsetxattr(path, name, value, size, flags); } -static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp,int fd, const char *name, const void *value, size_t size, int flags) +static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags) { - return sys_fsetxattr(fd, name, value, size, flags); + return sys_fsetxattr(fsp->fh->fd, name, value, size, flags); } static int vfswrap_aio_read(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb) @@ -1206,9 +1272,9 @@ static ssize_t vfswrap_aio_return(struct vfs_handle_struct *handle, struct files return sys_aio_return(aiocb); } -static int vfswrap_aio_cancel(struct vfs_handle_struct *handle, struct files_struct *fsp, int fd, SMB_STRUCT_AIOCB *aiocb) +static int vfswrap_aio_cancel(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb) { - return sys_aio_cancel(fd, aiocb); + return sys_aio_cancel(fsp->fh->fd, aiocb); } static int vfswrap_aio_error(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb) @@ -1226,6 +1292,36 @@ static int vfswrap_aio_suspend(struct vfs_handle_struct *handle, struct files_st return sys_aio_suspend(aiocb, n, timeout); } +static bool vfswrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp) +{ + return false; +} + +static bool vfswrap_is_offline(struct vfs_handle_struct *handle, const char *path, SMB_STRUCT_STAT *sbuf) +{ + if (ISDOT(path) || ISDOTDOT(path)) { + return false; + } + + if (!lp_dmapi_support(SNUM(handle->conn)) || !dmapi_have_session()) { +#if defined(ENOTSUP) + errno = ENOTSUP; +#endif + return false; + } + + return (dmapi_file_flags(path) & FILE_ATTRIBUTE_OFFLINE) != 0; +} + +static int vfswrap_set_offline(struct vfs_handle_struct *handle, const char *path) +{ + /* We don't know how to set offline bit by default, needs to be overriden in the vfs modules */ +#if defined(ENOTSUP) + errno = ENOTSUP; +#endif + return -1; +} + static vfs_op_tuple vfs_default_ops[] = { /* Disk operations */ @@ -1244,6 +1340,8 @@ static vfs_op_tuple vfs_default_ops[] = { SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(vfswrap_statvfs), SMB_VFS_OP_STATVFS, SMB_VFS_LAYER_OPAQUE}, + {SMB_VFS_OP(vfswrap_fs_capabilities), SMB_VFS_OP_FS_CAPABILITIES, + SMB_VFS_LAYER_OPAQUE}, /* Directory operations */ @@ -1338,6 +1436,8 @@ static vfs_op_tuple vfs_default_ops[] = { SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(vfswrap_file_id_create), SMB_VFS_OP_FILE_ID_CREATE, SMB_VFS_LAYER_OPAQUE}, + {SMB_VFS_OP(vfswrap_streaminfo), SMB_VFS_OP_STREAMINFO, + SMB_VFS_LAYER_OPAQUE}, /* NT ACL operations. */ @@ -1443,6 +1543,14 @@ static vfs_op_tuple vfs_default_ops[] = { {SMB_VFS_OP(vfswrap_aio_suspend),SMB_VFS_OP_AIO_SUSPEND, SMB_VFS_LAYER_OPAQUE}, + {SMB_VFS_OP(vfswrap_aio_force), SMB_VFS_OP_AIO_FORCE, + SMB_VFS_LAYER_OPAQUE}, + + {SMB_VFS_OP(vfswrap_is_offline),SMB_VFS_OP_IS_OFFLINE, + SMB_VFS_LAYER_OPAQUE}, + {SMB_VFS_OP(vfswrap_set_offline),SMB_VFS_OP_SET_OFFLINE, + SMB_VFS_LAYER_OPAQUE}, + /* Finish VFS operations definition */ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, diff --git a/source3/modules/vfs_extd_audit.c b/source3/modules/vfs_extd_audit.c index 552c64016e..a21e281e2c 100644 --- a/source3/modules/vfs_extd_audit.c +++ b/source3/modules/vfs_extd_audit.c @@ -42,8 +42,8 @@ static int audit_rename(vfs_handle_struct *handle, const char *oldname, const ch static int audit_unlink(vfs_handle_struct *handle, const char *path); static int audit_chmod(vfs_handle_struct *handle, const char *path, mode_t mode); static int audit_chmod_acl(vfs_handle_struct *handle, const char *name, mode_t mode); -static int audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, int fd, mode_t mode); -static int audit_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, int fd, mode_t mode); +static int audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode); +static int audit_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, mode_t mode); /* VFS operations */ @@ -310,11 +310,11 @@ static int audit_chmod_acl(vfs_handle_struct *handle, const char *path, mode_t m return result; } -static int audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, int fd, mode_t mode) +static int audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode) { int result; - result = SMB_VFS_NEXT_FCHMOD(handle, fsp, fd, mode); + result = SMB_VFS_NEXT_FCHMOD(handle, fsp, mode); syslog(audit_syslog_priority(handle), "fchmod %s mode 0x%x %s%s\n", fsp->fsp_name, mode, @@ -328,11 +328,11 @@ static int audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, int fd, mo return result; } -static int audit_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, int fd, mode_t mode) +static int audit_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, mode_t mode) { int result; - result = SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, fd, mode); + result = SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, mode); syslog(audit_syslog_priority(handle), "fchmod_acl %s mode 0x%x %s%s\n", fsp->fsp_name, mode, diff --git a/source3/modules/vfs_fake_perms.c b/source3/modules/vfs_fake_perms.c index 8157f05d52..ddad0008a7 100644 --- a/source3/modules/vfs_fake_perms.c +++ b/source3/modules/vfs_fake_perms.c @@ -46,11 +46,11 @@ static int fake_perms_stat(vfs_handle_struct *handle, const char *fname, SMB_STR return ret; } -static int fake_perms_fstat(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_STRUCT_STAT *sbuf) +static int fake_perms_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf) { int ret = -1; - ret = SMB_VFS_NEXT_FSTAT(handle, fsp, fd, sbuf); + ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf); if (ret == 0) { if (S_ISDIR(sbuf->st_mode)) { sbuf->st_mode = S_IFDIR | S_IRWXU; diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c index f4aeefbbf0..5aa9bab5b5 100644 --- a/source3/modules/vfs_full_audit.c +++ b/source3/modules/vfs_full_audit.c @@ -113,30 +113,30 @@ static int smb_full_audit_open(vfs_handle_struct *handle, const char *fname, files_struct *fsp, int flags, mode_t mode); static int smb_full_audit_close(vfs_handle_struct *handle, files_struct *fsp, int fd); static ssize_t smb_full_audit_read(vfs_handle_struct *handle, files_struct *fsp, - int fd, void *data, size_t n); + void *data, size_t n); static ssize_t smb_full_audit_pread(vfs_handle_struct *handle, files_struct *fsp, - int fd, void *data, size_t n, SMB_OFF_T offset); + void *data, size_t n, SMB_OFF_T offset); static ssize_t smb_full_audit_write(vfs_handle_struct *handle, files_struct *fsp, - int fd, const void *data, size_t n); + const void *data, size_t n); static ssize_t smb_full_audit_pwrite(vfs_handle_struct *handle, files_struct *fsp, - int fd, const void *data, size_t n, + const void *data, size_t n, SMB_OFF_T offset); static SMB_OFF_T smb_full_audit_lseek(vfs_handle_struct *handle, files_struct *fsp, - int filedes, SMB_OFF_T offset, int whence); + SMB_OFF_T offset, int whence); static ssize_t smb_full_audit_sendfile(vfs_handle_struct *handle, int tofd, - files_struct *fsp, int fromfd, + files_struct *fromfsp, const DATA_BLOB *hdr, SMB_OFF_T offset, size_t n); static ssize_t smb_full_audit_recvfile(vfs_handle_struct *handle, int fromfd, - files_struct *fsp, int tofd, + files_struct *tofsp, SMB_OFF_T offset, size_t n); static int smb_full_audit_rename(vfs_handle_struct *handle, const char *oldname, const char *newname); -static int smb_full_audit_fsync(vfs_handle_struct *handle, files_struct *fsp, int fd); +static int smb_full_audit_fsync(vfs_handle_struct *handle, files_struct *fsp); static int smb_full_audit_stat(vfs_handle_struct *handle, const char *fname, SMB_STRUCT_STAT *sbuf); -static int smb_full_audit_fstat(vfs_handle_struct *handle, files_struct *fsp, int fd, +static int smb_full_audit_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf); static int smb_full_audit_lstat(vfs_handle_struct *handle, const char *path, SMB_STRUCT_STAT *sbuf); @@ -144,11 +144,11 @@ static int smb_full_audit_unlink(vfs_handle_struct *handle, const char *path); static int smb_full_audit_chmod(vfs_handle_struct *handle, const char *path, mode_t mode); -static int smb_full_audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, int fd, +static int smb_full_audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode); static int smb_full_audit_chown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid); -static int smb_full_audit_fchown(vfs_handle_struct *handle, files_struct *fsp, int fd, +static int smb_full_audit_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid); static int smb_full_audit_lchown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid); @@ -159,15 +159,15 @@ static char *smb_full_audit_getwd(vfs_handle_struct *handle, static int smb_full_audit_ntimes(vfs_handle_struct *handle, const char *path, const struct timespec ts[2]); static int smb_full_audit_ftruncate(vfs_handle_struct *handle, files_struct *fsp, - int fd, SMB_OFF_T len); -static bool smb_full_audit_lock(vfs_handle_struct *handle, files_struct *fsp, int fd, + SMB_OFF_T len); +static bool smb_full_audit_lock(vfs_handle_struct *handle, files_struct *fsp, int op, SMB_OFF_T offset, SMB_OFF_T count, int type); static int smb_full_audit_kernel_flock(struct vfs_handle_struct *handle, - struct files_struct *fsp, int fd, + struct files_struct *fsp, uint32 share_mode); static int smb_full_audit_linux_setlease(vfs_handle_struct *handle, files_struct *fsp, - int fd, int leasetype); -static bool smb_full_audit_getlock(vfs_handle_struct *handle, files_struct *fsp, int fd, + int leasetype); +static bool smb_full_audit_getlock(vfs_handle_struct *handle, files_struct *fsp, SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid); static int smb_full_audit_symlink(vfs_handle_struct *handle, const char *oldpath, const char *newpath); @@ -191,13 +191,13 @@ static int smb_full_audit_chflags(vfs_handle_struct *handle, static struct file_id smb_full_audit_file_id_create(struct vfs_handle_struct *handle, SMB_DEV_T dev, SMB_INO_T inode); static NTSTATUS smb_full_audit_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp, - int fd, uint32 security_info, + uint32 security_info, SEC_DESC **ppdesc); static NTSTATUS smb_full_audit_get_nt_acl(vfs_handle_struct *handle, files_struct *fsp, const char *name, uint32 security_info, SEC_DESC **ppdesc); static NTSTATUS smb_full_audit_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, - int fd, uint32 security_info_sent, + uint32 security_info_sent, SEC_DESC *psd); static NTSTATUS smb_full_audit_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp, const char *name, uint32 security_info_sent, @@ -205,7 +205,7 @@ static NTSTATUS smb_full_audit_set_nt_acl(vfs_handle_struct *handle, files_struc static int smb_full_audit_chmod_acl(vfs_handle_struct *handle, const char *path, mode_t mode); static int smb_full_audit_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, - int fd, mode_t mode); + mode_t mode); static int smb_full_audit_sys_acl_get_entry(vfs_handle_struct *handle, SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p); @@ -221,8 +221,7 @@ static SMB_ACL_T smb_full_audit_sys_acl_get_file(vfs_handle_struct *handle, const char *path_p, SMB_ACL_TYPE_T type); static SMB_ACL_T smb_full_audit_sys_acl_get_fd(vfs_handle_struct *handle, - files_struct *fsp, - int fd); + files_struct *fsp); static int smb_full_audit_sys_acl_clear_perms(vfs_handle_struct *handle, SMB_ACL_PERMSET_T permset); static int smb_full_audit_sys_acl_add_perm(vfs_handle_struct *handle, @@ -251,7 +250,7 @@ static int smb_full_audit_sys_acl_set_file(vfs_handle_struct *handle, const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl); static int smb_full_audit_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, - int fd, SMB_ACL_T theacl); + SMB_ACL_T theacl); static int smb_full_audit_sys_acl_delete_def_file(vfs_handle_struct *handle, const char *path); static int smb_full_audit_sys_acl_get_perm(vfs_handle_struct *handle, @@ -271,14 +270,14 @@ static ssize_t smb_full_audit_lgetxattr(struct vfs_handle_struct *handle, const char *path, const char *name, void *value, size_t size); static ssize_t smb_full_audit_fgetxattr(struct vfs_handle_struct *handle, - struct files_struct *fsp, int fd, + struct files_struct *fsp, const char *name, void *value, size_t size); static ssize_t smb_full_audit_listxattr(struct vfs_handle_struct *handle, const char *path, char *list, size_t size); static ssize_t smb_full_audit_llistxattr(struct vfs_handle_struct *handle, const char *path, char *list, size_t size); static ssize_t smb_full_audit_flistxattr(struct vfs_handle_struct *handle, - struct files_struct *fsp, int fd, char *list, + struct files_struct *fsp, char *list, size_t size); static int smb_full_audit_removexattr(struct vfs_handle_struct *handle, const char *path, @@ -287,7 +286,7 @@ static int smb_full_audit_lremovexattr(struct vfs_handle_struct *handle, const char *path, const char *name); static int smb_full_audit_fremovexattr(struct vfs_handle_struct *handle, - struct files_struct *fsp, int fd, + struct files_struct *fsp, const char *name); static int smb_full_audit_setxattr(struct vfs_handle_struct *handle, const char *path, @@ -298,13 +297,13 @@ static int smb_full_audit_lsetxattr(struct vfs_handle_struct *handle, const char *name, const void *value, size_t size, int flags); static int smb_full_audit_fsetxattr(struct vfs_handle_struct *handle, - struct files_struct *fsp, int fd, const char *name, + struct files_struct *fsp, const char *name, const void *value, size_t size, int flags); static int smb_full_audit_aio_read(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb); static int smb_full_audit_aio_write(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb); static ssize_t smb_full_audit_aio_return(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb); -static int smb_full_audit_aio_cancel(struct vfs_handle_struct *handle, struct files_struct *fsp, int fd, SMB_STRUCT_AIOCB *aiocb); +static int smb_full_audit_aio_cancel(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb); static int smb_full_audit_aio_error(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb); static int smb_full_audit_aio_fsync(struct vfs_handle_struct *handle, struct files_struct *fsp, int op, SMB_STRUCT_AIOCB *aiocb); static int smb_full_audit_aio_suspend(struct vfs_handle_struct *handle, struct files_struct *fsp, const SMB_STRUCT_AIOCB * const aiocb[], int n, const struct timespec *ts); @@ -451,7 +450,7 @@ static vfs_op_tuple audit_op_tuples[] = { SMB_VFS_LAYER_LOGGER}, {SMB_VFS_OP(smb_full_audit_sys_acl_get_file), SMB_VFS_OP_SYS_ACL_GET_FILE, SMB_VFS_LAYER_LOGGER}, - {SMB_VFS_OP(smb_full_audit_sys_acl_get_fd), SMB_VFS_OP_SYS_ACL_GET_FD, +{SMB_VFS_OP(smb_full_audit_sys_acl_get_fd), SMB_VFS_OP_SYS_ACL_GET_FD, SMB_VFS_LAYER_LOGGER}, {SMB_VFS_OP(smb_full_audit_sys_acl_clear_perms), SMB_VFS_OP_SYS_ACL_CLEAR_PERMS, SMB_VFS_LAYER_LOGGER}, @@ -1088,11 +1087,11 @@ static int smb_full_audit_close(vfs_handle_struct *handle, files_struct *fsp, in } static ssize_t smb_full_audit_read(vfs_handle_struct *handle, files_struct *fsp, - int fd, void *data, size_t n) + void *data, size_t n) { ssize_t result; - result = SMB_VFS_NEXT_READ(handle, fsp, fd, data, n); + result = SMB_VFS_NEXT_READ(handle, fsp, data, n); do_log(SMB_VFS_OP_READ, (result >= 0), handle, "%s", fsp->fsp_name); @@ -1100,11 +1099,11 @@ static ssize_t smb_full_audit_read(vfs_handle_struct *handle, files_struct *fsp, } static ssize_t smb_full_audit_pread(vfs_handle_struct *handle, files_struct *fsp, - int fd, void *data, size_t n, SMB_OFF_T offset) + void *data, size_t n, SMB_OFF_T offset) { ssize_t result; - result = SMB_VFS_NEXT_PREAD(handle, fsp, fd, data, n, offset); + result = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset); do_log(SMB_VFS_OP_PREAD, (result >= 0), handle, "%s", fsp->fsp_name); @@ -1112,11 +1111,11 @@ static ssize_t smb_full_audit_pread(vfs_handle_struct *handle, files_struct *fsp } static ssize_t smb_full_audit_write(vfs_handle_struct *handle, files_struct *fsp, - int fd, const void *data, size_t n) + const void *data, size_t n) { ssize_t result; - result = SMB_VFS_NEXT_WRITE(handle, fsp, fd, data, n); + result = SMB_VFS_NEXT_WRITE(handle, fsp, data, n); do_log(SMB_VFS_OP_WRITE, (result >= 0), handle, "%s", fsp->fsp_name); @@ -1124,12 +1123,12 @@ static ssize_t smb_full_audit_write(vfs_handle_struct *handle, files_struct *fsp } static ssize_t smb_full_audit_pwrite(vfs_handle_struct *handle, files_struct *fsp, - int fd, const void *data, size_t n, + const void *data, size_t n, SMB_OFF_T offset) { ssize_t result; - result = SMB_VFS_NEXT_PWRITE(handle, fsp, fd, data, n, offset); + result = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset); do_log(SMB_VFS_OP_PWRITE, (result >= 0), handle, "%s", fsp->fsp_name); @@ -1137,11 +1136,11 @@ static ssize_t smb_full_audit_pwrite(vfs_handle_struct *handle, files_struct *fs } static SMB_OFF_T smb_full_audit_lseek(vfs_handle_struct *handle, files_struct *fsp, - int filedes, SMB_OFF_T offset, int whence) + SMB_OFF_T offset, int whence) { ssize_t result; - result = SMB_VFS_NEXT_LSEEK(handle, fsp, filedes, offset, whence); + result = SMB_VFS_NEXT_LSEEK(handle, fsp, offset, whence); do_log(SMB_VFS_OP_LSEEK, (result != (ssize_t)-1), handle, "%s", fsp->fsp_name); @@ -1150,33 +1149,31 @@ static SMB_OFF_T smb_full_audit_lseek(vfs_handle_struct *handle, files_struct *f } static ssize_t smb_full_audit_sendfile(vfs_handle_struct *handle, int tofd, - files_struct *fsp, int fromfd, + files_struct *fromfsp, const DATA_BLOB *hdr, SMB_OFF_T offset, size_t n) { ssize_t result; - result = SMB_VFS_NEXT_SENDFILE(handle, tofd, fsp, fromfd, hdr, - offset, n); + result = SMB_VFS_NEXT_SENDFILE(handle, tofd, fromfsp, hdr, offset, n); do_log(SMB_VFS_OP_SENDFILE, (result >= 0), handle, - "%s", fsp->fsp_name); + "%s", fromfsp->fsp_name); return result; } static ssize_t smb_full_audit_recvfile(vfs_handle_struct *handle, int fromfd, - files_struct *fsp, int tofd, + files_struct *tofsp, SMB_OFF_T offset, size_t n) { ssize_t result; - result = SMB_VFS_NEXT_RECVFILE(handle, fromfd, fsp, tofd, - offset, n); + result = SMB_VFS_NEXT_RECVFILE(handle, fromfd, tofsp, offset, n); do_log(SMB_VFS_OP_RECVFILE, (result >= 0), handle, - "%s", fsp->fsp_name); + "%s", tofsp->fsp_name); return result; } @@ -1193,11 +1190,11 @@ static int smb_full_audit_rename(vfs_handle_struct *handle, return result; } -static int smb_full_audit_fsync(vfs_handle_struct *handle, files_struct *fsp, int fd) +static int smb_full_audit_fsync(vfs_handle_struct *handle, files_struct *fsp) { int result; - result = SMB_VFS_NEXT_FSYNC(handle, fsp, fd); + result = SMB_VFS_NEXT_FSYNC(handle, fsp); do_log(SMB_VFS_OP_FSYNC, (result >= 0), handle, "%s", fsp->fsp_name); @@ -1216,12 +1213,12 @@ static int smb_full_audit_stat(vfs_handle_struct *handle, return result; } -static int smb_full_audit_fstat(vfs_handle_struct *handle, files_struct *fsp, int fd, +static int smb_full_audit_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf) { int result; - result = SMB_VFS_NEXT_FSTAT(handle, fsp, fd, sbuf); + result = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf); do_log(SMB_VFS_OP_FSTAT, (result >= 0), handle, "%s", fsp->fsp_name); @@ -1264,12 +1261,12 @@ static int smb_full_audit_chmod(vfs_handle_struct *handle, return result; } -static int smb_full_audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, int fd, +static int smb_full_audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode) { int result; - result = SMB_VFS_NEXT_FCHMOD(handle, fsp, fd, mode); + result = SMB_VFS_NEXT_FCHMOD(handle, fsp, mode); do_log(SMB_VFS_OP_FCHMOD, (result >= 0), handle, "%s|%o", fsp->fsp_name, mode); @@ -1290,12 +1287,12 @@ static int smb_full_audit_chown(vfs_handle_struct *handle, return result; } -static int smb_full_audit_fchown(vfs_handle_struct *handle, files_struct *fsp, int fd, +static int smb_full_audit_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid) { int result; - result = SMB_VFS_NEXT_FCHOWN(handle, fsp, fd, uid, gid); + result = SMB_VFS_NEXT_FCHOWN(handle, fsp, uid, gid); do_log(SMB_VFS_OP_FCHOWN, (result >= 0), handle, "%s|%ld|%ld", fsp->fsp_name, (long int)uid, (long int)gid); @@ -1353,11 +1350,11 @@ static int smb_full_audit_ntimes(vfs_handle_struct *handle, } static int smb_full_audit_ftruncate(vfs_handle_struct *handle, files_struct *fsp, - int fd, SMB_OFF_T len) + SMB_OFF_T len) { int result; - result = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, fd, len); + result = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, len); do_log(SMB_VFS_OP_FTRUNCATE, (result >= 0), handle, "%s", fsp->fsp_name); @@ -1365,12 +1362,12 @@ static int smb_full_audit_ftruncate(vfs_handle_struct *handle, files_struct *fsp return result; } -static bool smb_full_audit_lock(vfs_handle_struct *handle, files_struct *fsp, int fd, +static bool smb_full_audit_lock(vfs_handle_struct *handle, files_struct *fsp, int op, SMB_OFF_T offset, SMB_OFF_T count, int type) { bool result; - result = SMB_VFS_NEXT_LOCK(handle, fsp, fd, op, offset, count, type); + result = SMB_VFS_NEXT_LOCK(handle, fsp, op, offset, count, type); do_log(SMB_VFS_OP_LOCK, result, handle, "%s", fsp->fsp_name); @@ -1378,12 +1375,12 @@ static bool smb_full_audit_lock(vfs_handle_struct *handle, files_struct *fsp, in } static int smb_full_audit_kernel_flock(struct vfs_handle_struct *handle, - struct files_struct *fsp, int fd, + struct files_struct *fsp, uint32 share_mode) { int result; - result = SMB_VFS_NEXT_KERNEL_FLOCK(handle, fsp, fd, share_mode); + result = SMB_VFS_NEXT_KERNEL_FLOCK(handle, fsp, share_mode); do_log(SMB_VFS_OP_KERNEL_FLOCK, (result >= 0), handle, "%s", fsp->fsp_name); @@ -1392,11 +1389,11 @@ static int smb_full_audit_kernel_flock(struct vfs_handle_struct *handle, } static int smb_full_audit_linux_setlease(vfs_handle_struct *handle, files_struct *fsp, - int fd, int leasetype) + int leasetype) { int result; - result = SMB_VFS_NEXT_LINUX_SETLEASE(handle, fsp, fd, leasetype); + result = SMB_VFS_NEXT_LINUX_SETLEASE(handle, fsp, leasetype); do_log(SMB_VFS_OP_LINUX_SETLEASE, (result >= 0), handle, "%s", fsp->fsp_name); @@ -1404,12 +1401,12 @@ static int smb_full_audit_linux_setlease(vfs_handle_struct *handle, files_struct return result; } -static bool smb_full_audit_getlock(vfs_handle_struct *handle, files_struct *fsp, int fd, +static bool smb_full_audit_getlock(vfs_handle_struct *handle, files_struct *fsp, SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid) { bool result; - result = SMB_VFS_NEXT_GETLOCK(handle, fsp, fd, poffset, pcount, ptype, ppid); + result = SMB_VFS_NEXT_GETLOCK(handle, fsp, poffset, pcount, ptype, ppid); do_log(SMB_VFS_OP_GETLOCK, result, handle, "%s", fsp->fsp_name); @@ -1525,13 +1522,12 @@ static struct file_id smb_full_audit_file_id_create(struct vfs_handle_struct *ha } static NTSTATUS smb_full_audit_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp, - int fd, uint32 security_info, + uint32 security_info, SEC_DESC **ppdesc) { NTSTATUS result; - result = SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, fd, security_info, - ppdesc); + result = SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info, ppdesc); do_log(SMB_VFS_OP_FGET_NT_ACL, NT_STATUS_IS_OK(result), handle, "%s", fsp->fsp_name); @@ -1547,8 +1543,7 @@ static NTSTATUS smb_full_audit_get_nt_acl(vfs_handle_struct *handle, { NTSTATUS result; - result = SMB_VFS_NEXT_GET_NT_ACL(handle, fsp, name, security_info, - ppdesc); + result = SMB_VFS_NEXT_GET_NT_ACL(handle, name, security_info, ppdesc); do_log(SMB_VFS_OP_GET_NT_ACL, NT_STATUS_IS_OK(result), handle, "%s", fsp->fsp_name); @@ -1557,13 +1552,12 @@ static NTSTATUS smb_full_audit_get_nt_acl(vfs_handle_struct *handle, } static NTSTATUS smb_full_audit_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, - int fd, uint32 security_info_sent, + uint32 security_info_sent, SEC_DESC *psd) { NTSTATUS result; - result = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, fd, security_info_sent, - psd); + result = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd); do_log(SMB_VFS_OP_FSET_NT_ACL, NT_STATUS_IS_OK(result), handle, "%s", fsp->fsp_name); @@ -1598,11 +1592,11 @@ static int smb_full_audit_chmod_acl(vfs_handle_struct *handle, } static int smb_full_audit_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, - int fd, mode_t mode) + mode_t mode) { int result; - result = SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, fd, mode); + result = SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, mode); do_log(SMB_VFS_OP_FCHMOD_ACL, (result >= 0), handle, "%s|%o", fsp->fsp_name, mode); @@ -1687,11 +1681,11 @@ static SMB_ACL_T smb_full_audit_sys_acl_get_file(vfs_handle_struct *handle, } static SMB_ACL_T smb_full_audit_sys_acl_get_fd(vfs_handle_struct *handle, - files_struct *fsp, int fd) + files_struct *fsp) { SMB_ACL_T result; - result = SMB_VFS_NEXT_SYS_ACL_GET_FD(handle, fsp, fd); + result = SMB_VFS_NEXT_SYS_ACL_GET_FD(handle, fsp); do_log(SMB_VFS_OP_SYS_ACL_GET_FD, (result != NULL), handle, "%s", fsp->fsp_name); @@ -1847,11 +1841,11 @@ static int smb_full_audit_sys_acl_set_file(vfs_handle_struct *handle, } static int smb_full_audit_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, - int fd, SMB_ACL_T theacl) + SMB_ACL_T theacl) { int result; - result = SMB_VFS_NEXT_SYS_ACL_SET_FD(handle, fsp, fd, theacl); + result = SMB_VFS_NEXT_SYS_ACL_SET_FD(handle, fsp, theacl); do_log(SMB_VFS_OP_SYS_ACL_SET_FD, (result >= 0), handle, "%s", fsp->fsp_name); @@ -1960,12 +1954,12 @@ static ssize_t smb_full_audit_lgetxattr(struct vfs_handle_struct *handle, } static ssize_t smb_full_audit_fgetxattr(struct vfs_handle_struct *handle, - struct files_struct *fsp, int fd, + struct files_struct *fsp, const char *name, void *value, size_t size) { ssize_t result; - result = SMB_VFS_NEXT_FGETXATTR(handle, fsp, fd, name, value, size); + result = SMB_VFS_NEXT_FGETXATTR(handle, fsp, name, value, size); do_log(SMB_VFS_OP_FGETXATTR, (result >= 0), handle, "%s|%s", fsp->fsp_name, name); @@ -1998,12 +1992,12 @@ static ssize_t smb_full_audit_llistxattr(struct vfs_handle_struct *handle, } static ssize_t smb_full_audit_flistxattr(struct vfs_handle_struct *handle, - struct files_struct *fsp, int fd, char *list, + struct files_struct *fsp, char *list, size_t size) { ssize_t result; - result = SMB_VFS_NEXT_FLISTXATTR(handle, fsp, fd, list, size); + result = SMB_VFS_NEXT_FLISTXATTR(handle, fsp, list, size); do_log(SMB_VFS_OP_FLISTXATTR, (result >= 0), handle, "%s", fsp->fsp_name); @@ -2040,12 +2034,12 @@ static int smb_full_audit_lremovexattr(struct vfs_handle_struct *handle, } static int smb_full_audit_fremovexattr(struct vfs_handle_struct *handle, - struct files_struct *fsp, int fd, + struct files_struct *fsp, const char *name) { int result; - result = SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, fd, name); + result = SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, name); do_log(SMB_VFS_OP_FREMOVEXATTR, (result >= 0), handle, "%s|%s", fsp->fsp_name, name); @@ -2086,13 +2080,12 @@ static int smb_full_audit_lsetxattr(struct vfs_handle_struct *handle, } static int smb_full_audit_fsetxattr(struct vfs_handle_struct *handle, - struct files_struct *fsp, int fd, const char *name, + struct files_struct *fsp, const char *name, const void *value, size_t size, int flags) { int result; - result = SMB_VFS_NEXT_FSETXATTR(handle, fsp, fd, name, value, size, - flags); + result = SMB_VFS_NEXT_FSETXATTR(handle, fsp, name, value, size, flags); do_log(SMB_VFS_OP_FSETXATTR, (result >= 0), handle, "%s|%s", fsp->fsp_name, name); @@ -2133,11 +2126,11 @@ static ssize_t smb_full_audit_aio_return(struct vfs_handle_struct *handle, struc return result; } -static int smb_full_audit_aio_cancel(struct vfs_handle_struct *handle, struct files_struct *fsp, int fd, SMB_STRUCT_AIOCB *aiocb) +static int smb_full_audit_aio_cancel(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb) { int result; - result = SMB_VFS_NEXT_AIO_CANCEL(handle, fsp, fd, aiocb); + result = SMB_VFS_NEXT_AIO_CANCEL(handle, fsp, aiocb); do_log(SMB_VFS_OP_AIO_CANCEL, (result >= 0), handle, "%s", fsp->fsp_name); diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index c207bbfe2d..d10906dfb1 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -30,10 +30,10 @@ #include <gpfs_gpl.h> #include "nfs4_acls.h" - +#include "vfs_gpfs.h" static int vfs_gpfs_kernel_flock(vfs_handle_struct *handle, files_struct *fsp, - int fd, uint32 share_mode) + uint32 share_mode) { START_PROFILE(syscall_kernel_flock); @@ -52,21 +52,21 @@ static int vfs_gpfs_kernel_flock(vfs_handle_struct *handle, files_struct *fsp, } static int vfs_gpfs_setlease(vfs_handle_struct *handle, files_struct *fsp, - int fd, int leasetype) + int leasetype) { int ret; START_PROFILE(syscall_linux_setlease); - if ( linux_set_lease_sighandler(fd) == -1) + if ( linux_set_lease_sighandler(fsp->fh->fd) == -1) return -1; - ret = set_gpfs_lease(fd,leasetype); + 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 */ - ret = linux_setlease(fd, leasetype); + ret = linux_setlease(fsp->fh->fd, leasetype); } END_PROFILE(syscall_linux_setlease); @@ -153,7 +153,7 @@ static int gpfs_get_nfs4_acl(const char *fname, SMB4ACL_T **ppacl) DEBUG(10, ("gpfs_get_nfs4_acl invoked for %s\n", fname)); /* First get the real acl length */ - gacl = gpfs_getacl_alloc(fname, GPFS_ACL_TYPE_NFS4); + gacl = gpfs_getacl_alloc(fname, 0); if (gacl == NULL) { DEBUG(9, ("gpfs_getacl failed for %s with %s\n", fname, strerror(errno))); @@ -208,10 +208,10 @@ static int gpfs_get_nfs4_acl(const char *fname, SMB4ACL_T **ppacl) if (i > 0 && gace->aceType == SMB_ACE4_ACCESS_DENIED_ACE_TYPE) { struct gpfs_ace_v4 *prev = &gacl->ace_v4[i-1]; if (prev->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE && - prev->aceFlags == gace->aceFlags && - prev->aceIFlags == gace->aceIFlags && - (gace->aceMask & prev->aceMask) == 0 && - gace->aceWho == prev->aceWho) { + prev->aceFlags == gace->aceFlags && + prev->aceIFlags == gace->aceIFlags && + (gace->aceMask & prev->aceMask) == 0 && + gace->aceWho == prev->aceWho) { /* its redundent - skip it */ continue; } @@ -226,8 +226,9 @@ static int gpfs_get_nfs4_acl(const char *fname, SMB4ACL_T **ppacl) return 0; } -static NTSTATUS gpfsacl_get_nt_acl_common(files_struct *fsp, - uint32 security_info, SEC_DESC **ppdesc) +static NTSTATUS gpfsacl_fget_nt_acl(vfs_handle_struct *handle, + files_struct *fsp, uint32 security_info, + SEC_DESC **ppdesc) { SMB4ACL_T *pacl = NULL; int result; @@ -236,29 +237,37 @@ static NTSTATUS gpfsacl_get_nt_acl_common(files_struct *fsp, result = gpfs_get_nfs4_acl(fsp->fsp_name, &pacl); if (result == 0) - return smb_get_nt_acl_nfs4(fsp, security_info, ppdesc, pacl); + return smb_fget_nt_acl_nfs4(fsp, security_info, ppdesc, pacl); if (result > 0) { DEBUG(10, ("retrying with posix acl...\n")); - return get_nt_acl(fsp, security_info, ppdesc); + return posix_fget_nt_acl(fsp, security_info, ppdesc); } - + /* GPFS ACL was not read, something wrong happened, error code is set in errno */ return map_nt_error_from_unix(errno); } -NTSTATUS gpfsacl_fget_nt_acl(vfs_handle_struct *handle, - files_struct *fsp, int fd, uint32 security_info, - SEC_DESC **ppdesc) -{ - return gpfsacl_get_nt_acl_common(fsp, security_info, ppdesc); -} - -NTSTATUS gpfsacl_get_nt_acl(vfs_handle_struct *handle, - files_struct *fsp, const char *name, +static NTSTATUS gpfsacl_get_nt_acl(vfs_handle_struct *handle, + const char *name, uint32 security_info, SEC_DESC **ppdesc) { - return gpfsacl_get_nt_acl_common(fsp, security_info, ppdesc); + SMB4ACL_T *pacl = NULL; + int result; + + *ppdesc = NULL; + result = gpfs_get_nfs4_acl(name, &pacl); + + if (result == 0) + return smb_get_nt_acl_nfs4(handle->conn, name, security_info, ppdesc, pacl); + + if (result > 0) { + DEBUG(10, ("retrying with posix acl...\n")); + return posix_get_nt_acl(handle->conn, name, security_info, ppdesc); + } + + /* GPFS ACL was not read, something wrong happened, error code is set in errno */ + return map_nt_error_from_unix(errno); } static bool gpfsacl_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl) @@ -292,8 +301,31 @@ 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) + && ((gace->aceMask & ACE4_MASK_APPEND) != 0)) + || + (((gace->aceMask & ACE4_MASK_WRITE) != 0) + && ((gace->aceMask & ACE4_MASK_APPEND) == 0))) + && + lp_parm_bool(fsp->conn->params->service, "gpfs", + "merge_writeappend", True)) { + DEBUG(2, ("vfs_gpfs.c: file [%s]: ACE contains " + "WRITE^APPEND, setting WRITE|APPEND\n", + 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) @@ -338,7 +370,7 @@ static NTSTATUS gpfsacl_set_nt_acl_internal(files_struct *fsp, uint32 security_i struct gpfs_acl *acl; NTSTATUS result = NT_STATUS_ACCESS_DENIED; - acl = gpfs_getacl_alloc(fsp->fsp_name, GPFS_ACL_TYPE_ACCESS); + acl = gpfs_getacl_alloc(fsp->fsp_name, 0); if (acl == NULL) return result; @@ -354,7 +386,7 @@ static NTSTATUS gpfsacl_set_nt_acl_internal(files_struct *fsp, uint32 security_i return result; } -static NTSTATUS gpfsacl_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, int fd, uint32 security_info_sent, SEC_DESC *psd) +static NTSTATUS gpfsacl_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) { return gpfsacl_set_nt_acl_internal(fsp, security_info_sent, psd); } @@ -492,8 +524,7 @@ SMB_ACL_T gpfsacl_sys_acl_get_file(vfs_handle_struct *handle, } SMB_ACL_T gpfsacl_sys_acl_get_fd(vfs_handle_struct *handle, - files_struct *fsp, - int fd) + files_struct *fsp) { return gpfsacl_get_posix_acl(fsp->fsp_name, GPFS_ACL_TYPE_ACCESS); } @@ -607,7 +638,7 @@ int gpfsacl_sys_acl_set_file(vfs_handle_struct *handle, int gpfsacl_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, - int fd, SMB_ACL_T theacl) + SMB_ACL_T theacl) { return gpfsacl_sys_acl_set_file(handle, fsp->fsp_name, SMB_ACL_TYPE_ACCESS, theacl); } @@ -620,75 +651,225 @@ int gpfsacl_sys_acl_delete_def_file(vfs_handle_struct *handle, return -1; } +/* + * Assumed: mode bits are shiftable and standard + * Output: the new aceMask field for an smb nfs4 ace + */ +static uint32 gpfsacl_mask_filter(uint32 aceType, uint32 aceMask, uint32 rwx) +{ + const uint32 posix_nfs4map[3] = { + SMB_ACE4_EXECUTE, /* execute */ + SMB_ACE4_WRITE_DATA | SMB_ACE4_APPEND_DATA, /* write; GPFS specific */ + SMB_ACE4_READ_DATA /* read */ + }; + int i; + 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; + else + aceMask &= ~nfs4_bits; + } else { + /* add deny bits when suitable */ + if (!posix_bit) + aceMask |= nfs4_bits; + else + aceMask &= ~nfs4_bits; + } /* other ace types are unexpected */ + + posix_mask <<= 1; + } + + return aceMask; +} + +static int gpfsacl_emu_chmod(const char *path, mode_t mode) +{ + SMB4ACL_T *pacl = NULL; + int result; + bool haveAllowEntry[SMB_ACE4_WHO_EVERYONE + 1] = {False, False, False, False}; + 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, + mode >> ((SMB_ACE4_WHO_EVERYONE - specid) * 3)); + if (ace->aceMask!=newMask) { + DEBUG(10, ("ace changed for %s (%o -> %o) id=%d\n", + path, ace->aceMask, newMask, specid)); + } + ace->aceMask = newMask; + } + } + + /* make sure we have at least ALLOW entries + * for all the 3 special ids (@EVERYONE, @OWNER, @GROUP) + * - if necessary + */ + for(i = SMB_ACE4_WHO_OWNER; i<=SMB_ACE4_WHO_EVERYONE; i++) { + SMB_ACE4PROP_T ace; + + if (haveAllowEntry[i]==True) + continue; + + memset(&ace, 0, sizeof(SMB_ACE4PROP_T)); + 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 */ + memset(&fake_fsp, 0, sizeof(struct files_struct)); + 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; + return 0; /* ok for [f]chmod */ +} + static int vfs_gpfs_chmod(vfs_handle_struct *handle, const char *path, mode_t mode) { SMB_STRUCT_STAT st; + int rc; + if (SMB_VFS_NEXT_STAT(handle, path, &st) != 0) { - return -1; + return -1; } + /* avoid chmod() if possible, to preserve acls */ if ((st.st_mode & ~S_IFMT) == mode) { - return 0; + return 0; } - return SMB_VFS_NEXT_CHMOD(handle, path, mode); + + rc = gpfsacl_emu_chmod(path, mode); + if (rc == 1) + return SMB_VFS_NEXT_CHMOD(handle, path, mode); + return rc; } -static int vfs_gpfs_fchmod(vfs_handle_struct *handle, files_struct *fsp, int fd, mode_t mode) +static int vfs_gpfs_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode) { SMB_STRUCT_STAT st; - if (SMB_VFS_NEXT_FSTAT(handle, fsp, fd, &st) != 0) { - return -1; + int rc; + + if (SMB_VFS_NEXT_FSTAT(handle, fsp, &st) != 0) { + return -1; } + /* avoid chmod() if possible, to preserve acls */ if ((st.st_mode & ~S_IFMT) == mode) { - return 0; + return 0; } - return SMB_VFS_NEXT_FCHMOD(handle, fsp, fd, mode); + + rc = gpfsacl_emu_chmod(fsp->fsp_name, mode); + if (rc == 1) + return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode); + return rc; } /* 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(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_set_nt_acl), SMB_VFS_OP_SET_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(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(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_set_nt_acl), + SMB_VFS_OP_SET_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 }, + 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 }, { SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP } diff --git a/source3/modules/vfs_gpfs.h b/source3/modules/vfs_gpfs.h new file mode 100644 index 0000000000..3c499b0850 --- /dev/null +++ b/source3/modules/vfs_gpfs.h @@ -0,0 +1,32 @@ +/* + 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 2 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + +*/ + +bool set_gpfs_sharemode(files_struct *fsp, uint32 access_mask, + uint32 share_access); +int set_gpfs_lease(int fd, int leasetype); +int smbd_gpfs_getacl(char *pathname, int flags, void *acl); +int smbd_gpfs_putacl(char *pathname, int flags, void *acl); +void init_gpfs(void); diff --git a/source3/modules/vfs_hpuxacl.c b/source3/modules/vfs_hpuxacl.c index edce161c19..f9293405fb 100644 --- a/source3/modules/vfs_hpuxacl.c +++ b/source3/modules/vfs_hpuxacl.c @@ -1,7 +1,7 @@ /* * Unix SMB/Netbios implementation. * VFS module to get and set HP-UX ACLs - * Copyright (C) Michael Adam 2006 + * Copyright (C) Michael Adam 2006,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 @@ -140,7 +140,7 @@ SMB_ACL_T hpuxacl_sys_acl_get_file(vfs_handle_struct *handle, { SMB_ACL_T result = NULL; int count; - HPUX_ACL_T hpux_acl; + HPUX_ACL_T hpux_acl = NULL; DEBUG(10, ("hpuxacl_sys_acl_get_file called for file '%s'.\n", path_p)); @@ -182,15 +182,14 @@ SMB_ACL_T hpuxacl_sys_acl_get_file(vfs_handle_struct *handle, * get the access ACL of a file referred to by a fd */ SMB_ACL_T hpuxacl_sys_acl_get_fd(vfs_handle_struct *handle, - files_struct *fsp, - int fd) + files_struct *fsp) { /* * HPUX doesn't have the facl call. Fake it using the path.... JRA. */ /* For all I see, the info should already be in the fsp * parameter, but get it again to be safe --- necessary? */ - files_struct *file_struct_p = file_find_fd(fd); + files_struct *file_struct_p = file_find_fd(fsp->fh->fd); if (file_struct_p == NULL) { errno = EBADF; return NULL; @@ -214,7 +213,7 @@ int hpuxacl_sys_acl_set_file(vfs_handle_struct *handle, { int ret = -1; SMB_STRUCT_STAT s; - HPUX_ACL_T hpux_acl; + HPUX_ACL_T hpux_acl = NULL; int count; DEBUG(10, ("hpuxacl_sys_acl_set_file called for file '%s'\n", @@ -307,14 +306,14 @@ int hpuxacl_sys_acl_set_file(vfs_handle_struct *handle, */ int hpuxacl_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, - int fd, SMB_ACL_T theacl) + SMB_ACL_T theacl) { /* * HPUX doesn't have the facl call. Fake it using the path.... JRA. */ /* For all I see, the info should already be in the fsp * parameter, but get it again to be safe --- necessary? */ - files_struct *file_struct_p = file_find_fd(fd); + files_struct *file_struct_p = file_find_fd(fsp->fh->fd); if (file_struct_p == NULL) { errno = EBADF; return -1; diff --git a/source3/modules/vfs_irixacl.c b/source3/modules/vfs_irixacl.c index dab6deb747..6484e8f3eb 100644 --- a/source3/modules/vfs_irixacl.c +++ b/source3/modules/vfs_irixacl.c @@ -1,7 +1,7 @@ /* Unix SMB/Netbios implementation. VFS module to get and set irix acls - Copyright (C) Michael Adam 2006 + Copyright (C) Michael Adam 2006,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 @@ -32,8 +32,7 @@ SMB_ACL_T irixacl_sys_acl_get_file(vfs_handle_struct *handle, } SMB_ACL_T irixacl_sys_acl_get_fd(vfs_handle_struct *handle, - files_struct *fsp, - int fd) + files_struct *fsp) { errno = ENOTSUP; return NULL; @@ -50,7 +49,7 @@ int irixacl_sys_acl_set_file(vfs_handle_struct *handle, int irixacl_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, - int fd, SMB_ACL_T theacl) + SMB_ACL_T theacl) { errno = ENOTSUP; return -1; diff --git a/source3/modules/vfs_posixacl.c b/source3/modules/vfs_posixacl.c index fb0c0bc8e9..21fb2ada31 100644 --- a/source3/modules/vfs_posixacl.c +++ b/source3/modules/vfs_posixacl.c @@ -63,11 +63,10 @@ SMB_ACL_T posixacl_sys_acl_get_file(vfs_handle_struct *handle, } SMB_ACL_T posixacl_sys_acl_get_fd(vfs_handle_struct *handle, - files_struct *fsp, - int fd) + files_struct *fsp) { struct smb_acl_t *result; - acl_t acl = acl_get_fd(fd); + acl_t acl = acl_get_fd(fsp->fh->fd); if (acl == NULL) { return NULL; @@ -114,14 +113,14 @@ int posixacl_sys_acl_set_file(vfs_handle_struct *handle, int posixacl_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, - int fd, SMB_ACL_T theacl) + SMB_ACL_T theacl) { int res; acl_t acl = smb_acl_to_posix(theacl); if (acl == NULL) { return -1; } - res = acl_set_fd(fd, acl); + res = acl_set_fd(fsp->fh->fd, acl); acl_free(acl); return res; } diff --git a/source3/modules/vfs_prealloc.c b/source3/modules/vfs_prealloc.c index cebf3a3933..cb3508dc30 100644 --- a/source3/modules/vfs_prealloc.c +++ b/source3/modules/vfs_prealloc.c @@ -47,11 +47,16 @@ #define lock_type struct flock64 #endif +#ifdef HAVE_GPFS +#include "gpfs_gpl.h" +#endif + #define MODULE "prealloc" static int module_debug; static int preallocate_space(int fd, SMB_OFF_T size) { +#ifndef HAVE_GPFS lock_type fl = {0}; int err; @@ -78,6 +83,9 @@ static int preallocate_space(int fd, SMB_OFF_T size) err = -1; errno = ENOSYS; #endif +#else /* GPFS uses completely different interface */ + err = gpfs_prealloc(fd, (gpfs_off64_t)0, (gpfs_off64_t)size); +#endif if (err) { DEBUG(module_debug, @@ -184,11 +192,10 @@ normal_open: static int prealloc_ftruncate(vfs_handle_struct * handle, files_struct * fsp, - int fd, SMB_OFF_T offset) { SMB_OFF_T *psize; - int ret = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, fd, offset); + int ret = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset); /* Maintain the allocated space even in the face of truncates. */ if ((psize = VFS_FETCH_FSP_EXTENSION(handle, fsp))) { diff --git a/source3/modules/vfs_readahead.c b/source3/modules/vfs_readahead.c index 5b663a7b26..df75814b72 100644 --- a/source3/modules/vfs_readahead.c +++ b/source3/modules/vfs_readahead.c @@ -17,10 +17,6 @@ #include "includes.h" -#if !defined(HAVE_LINUX_READAHEAD) && !defined(HAVE_POSIX_FADVISE) -static bool didmsg; -#endif - struct readahead_data { SMB_OFF_T off_bound; SMB_OFF_T len; @@ -39,8 +35,7 @@ struct readahead_data { static ssize_t readahead_sendfile(struct vfs_handle_struct *handle, int tofd, - files_struct *fsp, - int fromfd, + files_struct *fromfsp, const DATA_BLOB *header, SMB_OFF_T offset, size_t count) @@ -49,16 +44,16 @@ static ssize_t readahead_sendfile(struct vfs_handle_struct *handle, if ( offset % rhd->off_bound == 0) { #if defined(HAVE_LINUX_READAHEAD) - int err = readahead(fromfd, offset, (size_t)rhd->len); + int err = readahead(fromfsp->fh->fd, offset, (size_t)rhd->len); DEBUG(10,("readahead_sendfile: readahead on fd %u, offset %llu, len %u returned %d\n", - (unsigned int)fromfd, + (unsigned int)fromfsp->fh->fd, (unsigned long long)offset, (unsigned int)rhd->len, err )); #elif defined(HAVE_POSIX_FADVISE) - int err = posix_fadvise(fromfd, offset, (off_t)rhd->len, POSIX_FADV_WILLNEED); + int err = posix_fadvise(fromfsp->fh->fd, offset, (off_t)rhd->len, POSIX_FADV_WILLNEED); DEBUG(10,("readahead_sendfile: posix_fadvise on fd %u, offset %llu, len %u returned %d\n", - (unsigned int)fromfd, + (unsigned int)fromfsp->fh->fd, (unsigned long long)offset, (unsigned int)rhd->len, err )); @@ -71,8 +66,7 @@ static ssize_t readahead_sendfile(struct vfs_handle_struct *handle, } return SMB_VFS_NEXT_SENDFILE(handle, tofd, - fsp, - fromfd, + fromfsp, header, offset, count); @@ -84,7 +78,6 @@ static ssize_t readahead_sendfile(struct vfs_handle_struct *handle, static ssize_t readahead_pread(vfs_handle_struct *handle, files_struct *fsp, - int fd, void *data, size_t count, SMB_OFF_T offset) @@ -93,16 +86,16 @@ static ssize_t readahead_pread(vfs_handle_struct *handle, if ( offset % rhd->off_bound == 0) { #if defined(HAVE_LINUX_READAHEAD) - int err = readahead(fd, offset, (size_t)rhd->len); + int err = readahead(fsp->fh->fd, offset, (size_t)rhd->len); DEBUG(10,("readahead_pread: readahead on fd %u, offset %llu, len %u returned %d\n", - (unsigned int)fd, + (unsigned int)fsp->fh->fd, (unsigned long long)offset, (unsigned int)rhd->len, err )); #elif defined(HAVE_POSIX_FADVISE) - int err = posix_fadvise(fd, offset, (off_t)rhd->len, POSIX_FADV_WILLNEED); + int err = posix_fadvise(fsp->fh->fd, offset, (off_t)rhd->len, POSIX_FADV_WILLNEED); DEBUG(10,("readahead_pread: posix_fadvise on fd %u, offset %llu, len %u returned %d\n", - (unsigned int)fd, + (unsigned int)fsp->fh->fd, (unsigned long long)offset, (unsigned int)rhd->len, err )); @@ -113,7 +106,7 @@ static ssize_t readahead_pread(vfs_handle_struct *handle, } #endif } - return SMB_VFS_NEXT_PREAD(handle, fsp, fd, data, count, offset); + return SMB_VFS_NEXT_PREAD(handle, fsp, data, count, offset); } /******************************************************************* diff --git a/source3/modules/vfs_recycle.c b/source3/modules/vfs_recycle.c index fef65efa77..da1716719a 100644 --- a/source3/modules/vfs_recycle.c +++ b/source3/modules/vfs_recycle.c @@ -269,6 +269,7 @@ static bool recycle_create_dir(vfs_handle_struct *handle, const char *dname) char *token; char *tok_str; bool ret = False; + char *saveptr; mode = recycle_directory_mode(handle); @@ -286,7 +287,8 @@ static bool recycle_create_dir(vfs_handle_struct *handle, const char *dname) } /* Create directory tree if neccessary */ - for(token = strtok(tok_str, "/"); token; token = strtok(NULL, "/")) { + for(token = strtok_r(tok_str, "/", &saveptr); token; + token = strtok_r(NULL, "/", &saveptr)) { safe_strcat(new_dir, token, len); if (recycle_directory_exist(handle, new_dir)) DEBUG(10, ("recycle: dir %s already exists\n", new_dir)); diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c new file mode 100644 index 0000000000..ddbc5aab18 --- /dev/null +++ b/source3/modules/vfs_shadow_copy2.c @@ -0,0 +1,637 @@ +/* + * implementation of an Shadow Copy module - version 2 + * + * Copyright (C) Andrew Tridgell 2007 + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "includes.h" + +/* + + This is a 2nd implemetation of a shadow copy module for exposing + snapshots to windows clients as shadow copies. This version has the + following features: + + 1) you don't need to populate your shares with symlinks to the + snapshots. This can be very important when you have thousands of + shares, or use [homes] + + 2) the inode number of the files is altered so it is different + from the original. This allows the 'restore' button to work + without a sharing violation + + Module options: + + shadow:snapdir = <directory where snapshots are kept> + + This is the directory containing the @GMT-* snapshot directories. If it is an absolute + path it is used as-is. If it is a relative path, then it is taken relative to the mount + point of the filesystem that the root of this share is on + + shadow:basedir = <base directory that snapshots are from> + + This is an optional parameter that specifies the directory that + the snapshots are relative to. It defaults to the filesystem + mount point + + shadow:fixinodes = yes/no + + If you enable shadow:fixinodes then this module will modify the + apparent inode number of files in the snapshot directories using + a hash of the files path. This is needed for snapshot systems + where the snapshots have the same device:inode number as the + original files (such as happens with GPFS snapshots). If you + don't set this option then the 'restore' button in the shadow + copy UI will fail with a sharing violation. + + Note that the directory names in the snapshot directory must take the form + @GMT-YYYY.MM.DD-HH.MM.SS + + The following command would generate a correctly formatted directory name: + date -u +@GMT-%Y.%m.%d-%H.%M.%S + + */ + +static int vfs_shadow_copy2_debug_level = DBGC_VFS; + +#undef DBGC_CLASS +#define DBGC_CLASS vfs_shadow_copy2_debug_level + +#define GMT_NAME_LEN 24 /* length of a @GMT- name */ + +/* + make very sure it is one of our special names + */ +static inline bool shadow_copy2_match_name(const char *name) +{ + unsigned year, month, day, hr, min, sec; + if (name[0] != '@') return False; + if (strncmp(name, "@GMT-", 5) != 0) return False; + if (sscanf(name, "@GMT-%04u.%02u.%02u-%02u.%02u.%02u", &year, &month, + &day, &hr, &min, &sec) != 6) { + return False; + } + if (name[24] != 0 && name[24] != '/') { + return False; + } + return True; +} + +/* + convert a name to the shadow directory + */ + +#define _SHADOW2_NEXT(op, args, rtype, eret, extra) do { \ + const char *name = fname; \ + if (shadow_copy2_match_name(fname)) { \ + char *name2; \ + rtype ret; \ + name2 = convert_shadow2_name(handle, fname); \ + if (name2 == NULL) { \ + errno = EINVAL; \ + return eret; \ + } \ + name = name2; \ + ret = SMB_VFS_NEXT_ ## op args; \ + talloc_free(name2); \ + if (ret != eret) extra; \ + return ret; \ + } else { \ + return SMB_VFS_NEXT_ ## op args; \ + } \ +} while (0) + +/* + convert a name to the shadow directory: NTSTATUS-specific handling + */ + +#define _SHADOW2_NTSTATUS_NEXT(op, args, eret, extra) do { \ + const char *name = fname; \ + if (shadow_copy2_match_name(fname)) { \ + char *name2; \ + NTSTATUS ret; \ + name2 = convert_shadow2_name(handle, fname); \ + if (name2 == NULL) { \ + errno = EINVAL; \ + return eret; \ + } \ + name = name2; \ + ret = SMB_VFS_NEXT_ ## op args; \ + talloc_free(name2); \ + if (!NT_STATUS_EQUAL(ret, eret)) extra; \ + return ret; \ + } else { \ + return SMB_VFS_NEXT_ ## op args; \ + } \ +} while (0) + +#define SHADOW2_NTSTATUS_NEXT(op, args, eret) _SHADOW2_NTSTATUS_NEXT(op, args, eret, ) + +#define SHADOW2_NEXT(op, args, rtype, eret) _SHADOW2_NEXT(op, args, rtype, eret, ) + +#define SHADOW2_NEXT2(op, args) do { \ + if (shadow_copy2_match_name(oldname) || shadow_copy2_match_name(newname)) { \ + errno = EROFS; \ + return -1; \ + } else { \ + return SMB_VFS_NEXT_ ## op args; \ + } \ +} while (0) + + +/* + find the mount point of a filesystem + */ +static char *find_mount_point(TALLOC_CTX *mem_ctx, vfs_handle_struct *handle) +{ + char *path = talloc_strdup(mem_ctx, handle->conn->connectpath); + dev_t dev; + struct stat st; + char *p; + + if (stat(path, &st) != 0) { + talloc_free(path); + return NULL; + } + + dev = st.st_dev; + + while ((p = strrchr(path, '/')) && p > path) { + *p = 0; + if (stat(path, &st) != 0) { + talloc_free(path); + return NULL; + } + if (st.st_dev != dev) { + *p = '/'; + break; + } + } + + return path; +} + +/* + work out the location of the snapshot for this share + */ +static const char *shadow_copy2_find_snapdir(TALLOC_CTX *mem_ctx, vfs_handle_struct *handle) +{ + const char *snapdir; + char *mount_point; + const char *ret; + + snapdir = lp_parm_const_string(SNUM(handle->conn), "shadow", "snapdir", NULL); + if (snapdir == NULL) { + return NULL; + } + /* if its an absolute path, we're done */ + if (*snapdir == '/') { + return snapdir; + } + + /* other its relative to the filesystem mount point */ + mount_point = find_mount_point(mem_ctx, handle); + if (mount_point == NULL) { + return NULL; + } + + ret = talloc_asprintf(mem_ctx, "%s/%s", mount_point, snapdir); + talloc_free(mount_point); + return ret; +} + +/* + work out the location of the base directory for snapshots of this share + */ +static const char *shadow_copy2_find_basedir(TALLOC_CTX *mem_ctx, vfs_handle_struct *handle) +{ + const char *basedir = lp_parm_const_string(SNUM(handle->conn), "shadow", "basedir", NULL); + + /* other its the filesystem mount point */ + if (basedir == NULL) { + basedir = find_mount_point(mem_ctx, handle); + } + + return basedir; +} + +/* + convert a filename from a share relative path, to a path in the + snapshot directory + */ +static char *convert_shadow2_name(vfs_handle_struct *handle, const char *fname) +{ + TALLOC_CTX *tmp_ctx = talloc_new(handle->data); + const char *snapdir, *relpath, *baseoffset, *basedir; + size_t baselen; + char *ret; + + snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle); + if (snapdir == NULL) { + DEBUG(2,("no snapdir found for share at %s\n", handle->conn->connectpath)); + talloc_free(tmp_ctx); + return NULL; + } + + basedir = shadow_copy2_find_basedir(tmp_ctx, handle); + if (basedir == NULL) { + DEBUG(2,("no basedir found for share at %s\n", handle->conn->connectpath)); + talloc_free(tmp_ctx); + return NULL; + } + + relpath = fname + GMT_NAME_LEN; + baselen = strlen(basedir); + baseoffset = handle->conn->connectpath + baselen; + + /* some sanity checks */ + if (strncmp(basedir, handle->conn->connectpath, baselen) != 0 || + (handle->conn->connectpath[baselen] != 0 && handle->conn->connectpath[baselen] != '/')) { + DEBUG(0,("convert_shadow2_name: basedir %s is not a parent of %s\n", + basedir, handle->conn->connectpath)); + talloc_free(tmp_ctx); + return NULL; + } + + if (*relpath == '/') relpath++; + if (*baseoffset == '/') baseoffset++; + + ret = talloc_asprintf(handle->data, "%s/%.*s/%s/%s", + snapdir, + GMT_NAME_LEN, fname, + baseoffset, + relpath); + DEBUG(6,("convert_shadow2_name: '%s' -> '%s'\n", fname, ret)); + talloc_free(tmp_ctx); + return ret; +} + + +/* + simple string hash + */ +static uint32 string_hash(const char *s) +{ + uint32 n = 0; + while (*s) { + n = ((n << 5) + n) ^ (uint32)(*s++); + } + return n; +} + +/* + modify a sbuf return to ensure that inodes in the shadow directory + are different from those in the main directory + */ +static void convert_sbuf(vfs_handle_struct *handle, const char *fname, SMB_STRUCT_STAT *sbuf) +{ + if (lp_parm_bool(SNUM(handle->conn), "shadow", "fixinodes", False)) { + /* some snapshot systems, like GPFS, return the name + device:inode for the snapshot files as the current + files. That breaks the 'restore' button in the shadow copy + GUI, as the client gets a sharing violation. + + This is a crude way of allowing both files to be + open at once. It has a slight chance of inode + number collision, but I can't see a better approach + without significant VFS changes + */ + uint32_t shash = string_hash(fname) & 0xFF000000; + if (shash == 0) { + shash = 1; + } + sbuf->st_ino ^= shash; + } +} + +static int shadow_copy2_rename(vfs_handle_struct *handle, + const char *oldname, const char *newname) +{ + SHADOW2_NEXT2(RENAME, (handle, oldname, newname)); +} + +static int shadow_copy2_symlink(vfs_handle_struct *handle, + const char *oldname, const char *newname) +{ + SHADOW2_NEXT2(SYMLINK, (handle, oldname, newname)); +} + +static int shadow_copy2_link(vfs_handle_struct *handle, + const char *oldname, const char *newname) +{ + SHADOW2_NEXT2(LINK, (handle, oldname, newname)); +} + +static int shadow_copy2_open(vfs_handle_struct *handle, + const char *fname, files_struct *fsp, int flags, mode_t mode) +{ + SHADOW2_NEXT(OPEN, (handle, name, fsp, flags, mode), int, -1); +} + +static SMB_STRUCT_DIR *shadow_copy2_opendir(vfs_handle_struct *handle, + const char *fname, const char *mask, uint32 attr) +{ + SHADOW2_NEXT(OPENDIR, (handle, name, mask, attr), SMB_STRUCT_DIR *, NULL); +} + +static int shadow_copy2_stat(vfs_handle_struct *handle, + const char *fname, SMB_STRUCT_STAT *sbuf) +{ + _SHADOW2_NEXT(STAT, (handle, name, sbuf), int, -1, convert_sbuf(handle, fname, sbuf)); +} + +static int shadow_copy2_lstat(vfs_handle_struct *handle, + const char *fname, SMB_STRUCT_STAT *sbuf) +{ + _SHADOW2_NEXT(LSTAT, (handle, name, sbuf), int, -1, convert_sbuf(handle, fname, sbuf)); +} + +static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf) +{ + int ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf); + if (ret == 0 && shadow_copy2_match_name(fsp->fsp_name)) { + convert_sbuf(handle, fsp->fsp_name, sbuf); + } + return ret; +} + +static int shadow_copy2_unlink(vfs_handle_struct *handle, const char *fname) +{ + SHADOW2_NEXT(UNLINK, (handle, name), int, -1); +} + +static int shadow_copy2_chmod(vfs_handle_struct *handle, + const char *fname, mode_t mode) +{ + SHADOW2_NEXT(CHMOD, (handle, name, mode), int, -1); +} + +static int shadow_copy2_chown(vfs_handle_struct *handle, + const char *fname, uid_t uid, gid_t gid) +{ + SHADOW2_NEXT(CHOWN, (handle, name, uid, gid), int, -1); +} + +static int shadow_copy2_chdir(vfs_handle_struct *handle, + const char *fname) +{ + SHADOW2_NEXT(CHDIR, (handle, name), int, -1); +} + +static int shadow_copy2_ntimes(vfs_handle_struct *handle, + const char *fname, const struct timespec ts[2]) +{ + SHADOW2_NEXT(NTIMES, (handle, name, ts), int, -1); +} + +static int shadow_copy2_readlink(vfs_handle_struct *handle, + const char *fname, char *buf, size_t bufsiz) +{ + SHADOW2_NEXT(READLINK, (handle, name, buf, bufsiz), int, -1); +} + +static int shadow_copy2_mknod(vfs_handle_struct *handle, + const char *fname, mode_t mode, SMB_DEV_T dev) +{ + SHADOW2_NEXT(MKNOD, (handle, name, mode, dev), int, -1); +} + +static char *shadow_copy2_realpath(vfs_handle_struct *handle, + const char *fname, char *resolved_path) +{ + SHADOW2_NEXT(REALPATH, (handle, name, resolved_path), char *, NULL); +} + +static NTSTATUS shadow_copy2_get_nt_acl(vfs_handle_struct *handle, + const char *fname, uint32 security_info, + struct security_descriptor **ppdesc) +{ + SHADOW2_NTSTATUS_NEXT(GET_NT_ACL, (handle, name, security_info, ppdesc), NT_STATUS_ACCESS_DENIED); +} + +static NTSTATUS shadow_copy2_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp, + const char *fname, uint32 security_info_sent, + struct security_descriptor *psd) +{ + SHADOW2_NTSTATUS_NEXT(SET_NT_ACL, (handle, fsp, name, security_info_sent, psd), NT_STATUS_ACCESS_DENIED); +} + +static int shadow_copy2_mkdir(vfs_handle_struct *handle, const char *fname, mode_t mode) +{ + SHADOW2_NEXT(MKDIR, (handle, name, mode), int, -1); +} + +static int shadow_copy2_rmdir(vfs_handle_struct *handle, const char *fname) +{ + SHADOW2_NEXT(RMDIR, (handle, name), int, -1); +} + +static int shadow_copy2_chflags(vfs_handle_struct *handle, const char *fname, int flags) +{ + SHADOW2_NEXT(CHFLAGS, (handle, name, flags), int, -1); +} + +static ssize_t shadow_copy2_getxattr(vfs_handle_struct *handle, + const char *fname, const char *aname, void *value, size_t size) +{ + SHADOW2_NEXT(GETXATTR, (handle, name, aname, value, size), ssize_t, -1); +} + +static ssize_t shadow_copy2_lgetxattr(vfs_handle_struct *handle, + const char *fname, const char *aname, void *value, size_t size) +{ + SHADOW2_NEXT(LGETXATTR, (handle, name, aname, value, size), ssize_t, -1); +} + +static ssize_t shadow_copy2_listxattr(struct vfs_handle_struct *handle, const char *fname, + char *list, size_t size) +{ + SHADOW2_NEXT(LISTXATTR, (handle, name, list, size), ssize_t, -1); +} + +static int shadow_copy2_removexattr(struct vfs_handle_struct *handle, const char *fname, + const char *aname) +{ + SHADOW2_NEXT(REMOVEXATTR, (handle, name, aname), int, -1); +} + +static int shadow_copy2_lremovexattr(struct vfs_handle_struct *handle, const char *fname, + const char *aname) +{ + SHADOW2_NEXT(LREMOVEXATTR, (handle, name, aname), int, -1); +} + +static int shadow_copy2_setxattr(struct vfs_handle_struct *handle, const char *fname, + const char *aname, const void *value, size_t size, int flags) +{ + SHADOW2_NEXT(SETXATTR, (handle, name, aname, value, size, flags), int, -1); +} + +static int shadow_copy2_lsetxattr(struct vfs_handle_struct *handle, const char *fname, + const char *aname, const void *value, size_t size, int flags) +{ + SHADOW2_NEXT(LSETXATTR, (handle, name, aname, value, size, flags), int, -1); +} + +static int shadow_copy2_chmod_acl(vfs_handle_struct *handle, + const char *fname, mode_t mode) +{ + /* If the underlying VFS doesn't have ACL support... */ + if (!handle->vfs_next.ops.chmod_acl) { + errno = ENOSYS; + return -1; + } + SHADOW2_NEXT(CHMOD_ACL, (handle, name, mode), int, -1); +} + +static int shadow_copy2_get_shadow_copy2_data(vfs_handle_struct *handle, + files_struct *fsp, + SHADOW_COPY_DATA *shadow_copy2_data, + bool labels) +{ + SMB_STRUCT_DIR *p; + const char *snapdir; + SMB_STRUCT_DIRENT *d; + TALLOC_CTX *tmp_ctx = talloc_new(handle->data); + + snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle); + if (snapdir == NULL) { + DEBUG(0,("shadow:snapdir not found for %s in get_shadow_copy_data\n", + handle->conn->connectpath)); + errno = EINVAL; + talloc_free(tmp_ctx); + return -1; + } + + p = SMB_VFS_NEXT_OPENDIR(handle, snapdir, NULL, 0); + + if (!p) { + DEBUG(0,("shadow_copy2: SMB_VFS_NEXT_OPENDIR() failed for '%s' - %s\n", + snapdir, strerror(errno))); + talloc_free(tmp_ctx); + return -1; + } + + talloc_free(tmp_ctx); + + shadow_copy2_data->num_volumes = 0; + shadow_copy2_data->labels = NULL; + + while ((d = SMB_VFS_NEXT_READDIR(handle, p))) { + SHADOW_COPY_LABEL *tlabels; + + /* ignore names not of the right form in the snapshot directory */ + if (!shadow_copy2_match_name(d->d_name)) { + continue; + } + + if (!labels) { + /* the caller doesn't want the labels */ + shadow_copy2_data->num_volumes++; + continue; + } + + tlabels = talloc_realloc(shadow_copy2_data->mem_ctx, + shadow_copy2_data->labels, + SHADOW_COPY_LABEL, shadow_copy2_data->num_volumes+1); + if (tlabels == NULL) { + DEBUG(0,("shadow_copy2: out of memory\n")); + SMB_VFS_NEXT_CLOSEDIR(handle, p); + return -1; + } + + strlcpy(tlabels[shadow_copy2_data->num_volumes], d->d_name, sizeof(*tlabels)); + shadow_copy2_data->num_volumes++; + shadow_copy2_data->labels = tlabels; + } + + SMB_VFS_NEXT_CLOSEDIR(handle,p); + return 0; +} + +/* VFS operations structure */ + +static vfs_op_tuple shadow_copy2_ops[] = { + {SMB_VFS_OP(shadow_copy2_opendir), SMB_VFS_OP_OPENDIR, SMB_VFS_LAYER_TRANSPARENT}, + + /* directory operations */ + {SMB_VFS_OP(shadow_copy2_mkdir), SMB_VFS_OP_MKDIR, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(shadow_copy2_rmdir), SMB_VFS_OP_RMDIR, SMB_VFS_LAYER_TRANSPARENT}, + + /* xattr and flags operations */ + {SMB_VFS_OP(shadow_copy2_chflags), SMB_VFS_OP_CHFLAGS, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(shadow_copy2_getxattr), SMB_VFS_OP_GETXATTR, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(shadow_copy2_lgetxattr), SMB_VFS_OP_LGETXATTR, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(shadow_copy2_listxattr), SMB_VFS_OP_LISTXATTR, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(shadow_copy2_removexattr), SMB_VFS_OP_REMOVEXATTR, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(shadow_copy2_lremovexattr),SMB_VFS_OP_LREMOVEXATTR,SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(shadow_copy2_setxattr), SMB_VFS_OP_SETXATTR, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(shadow_copy2_lsetxattr), SMB_VFS_OP_LSETXATTR, SMB_VFS_LAYER_TRANSPARENT}, + + /* File operations */ + {SMB_VFS_OP(shadow_copy2_open), SMB_VFS_OP_OPEN, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(shadow_copy2_rename), SMB_VFS_OP_RENAME, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(shadow_copy2_stat), SMB_VFS_OP_STAT, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(shadow_copy2_lstat), SMB_VFS_OP_LSTAT, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(shadow_copy2_fstat), SMB_VFS_OP_FSTAT, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(shadow_copy2_unlink), SMB_VFS_OP_UNLINK, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(shadow_copy2_chmod), SMB_VFS_OP_CHMOD, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(shadow_copy2_chown), SMB_VFS_OP_CHOWN, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(shadow_copy2_chdir), SMB_VFS_OP_CHDIR, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(shadow_copy2_ntimes), SMB_VFS_OP_NTIMES, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(shadow_copy2_symlink), SMB_VFS_OP_SYMLINK, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(shadow_copy2_readlink), SMB_VFS_OP_READLINK, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(shadow_copy2_link), SMB_VFS_OP_LINK, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(shadow_copy2_mknod), SMB_VFS_OP_MKNOD, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(shadow_copy2_realpath), SMB_VFS_OP_REALPATH, SMB_VFS_LAYER_TRANSPARENT}, + + /* NT File ACL operations */ + {SMB_VFS_OP(shadow_copy2_get_nt_acl), SMB_VFS_OP_GET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(shadow_copy2_set_nt_acl), SMB_VFS_OP_SET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT}, + + /* POSIX ACL operations */ + {SMB_VFS_OP(shadow_copy2_chmod_acl), SMB_VFS_OP_CHMOD_ACL, SMB_VFS_LAYER_TRANSPARENT}, + + /* special shadown copy op */ + {SMB_VFS_OP(shadow_copy2_get_shadow_copy2_data), + SMB_VFS_OP_GET_SHADOW_COPY_DATA,SMB_VFS_LAYER_OPAQUE}, + + {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP} +}; + +NTSTATUS vfs_shadow_copy2_init(void); +NTSTATUS vfs_shadow_copy2_init(void) +{ + NTSTATUS ret; + + ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "shadow_copy2", shadow_copy2_ops); + + if (!NT_STATUS_IS_OK(ret)) + return ret; + + vfs_shadow_copy2_debug_level = debug_add_class("shadow_copy2"); + if (vfs_shadow_copy2_debug_level == -1) { + vfs_shadow_copy2_debug_level = DBGC_VFS; + DEBUG(0, ("%s: Couldn't register custom debugging class!\n", + "vfs_shadow_copy2_init")); + } else { + DEBUG(10, ("%s: Debug class number of '%s': %d\n", + "vfs_shadow_copy2_init","shadow_copy2",vfs_shadow_copy2_debug_level)); + } + + return ret; +} diff --git a/source3/modules/vfs_solarisacl.c b/source3/modules/vfs_solarisacl.c index 673b6805af..7bdfe8465b 100644 --- a/source3/modules/vfs_solarisacl.c +++ b/source3/modules/vfs_solarisacl.c @@ -1,7 +1,7 @@ /* Unix SMB/Netbios implementation. VFS module to get and set Solaris ACLs - Copyright (C) Michael Adam 2006 + Copyright (C) Michael Adam 2006,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 @@ -100,8 +100,7 @@ SMB_ACL_T solarisacl_sys_acl_get_file(vfs_handle_struct *handle, * get the access ACL of a file referred to by a fd */ SMB_ACL_T solarisacl_sys_acl_get_fd(vfs_handle_struct *handle, - files_struct *fsp, - int fd) + files_struct *fsp) { SMB_ACL_T result = NULL; int count; @@ -109,7 +108,7 @@ SMB_ACL_T solarisacl_sys_acl_get_fd(vfs_handle_struct *handle, DEBUG(10, ("entering solarisacl_sys_acl_get_fd.\n")); - if (!solaris_acl_get_fd(fd, &solaris_acl, &count)) { + if (!solaris_acl_get_fd(fsp->fh->fd, &solaris_acl, &count)) { goto done; } /* @@ -219,7 +218,7 @@ int solarisacl_sys_acl_set_file(vfs_handle_struct *handle, */ int solarisacl_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, - int fd, SMB_ACL_T theacl) + SMB_ACL_T theacl) { SOLARIS_ACL_T solaris_acl = NULL; SOLARIS_ACL_T default_acl = NULL; @@ -242,7 +241,7 @@ int solarisacl_sys_acl_set_fd(vfs_handle_struct *handle, strerror(errno))); goto done; } - if (!solaris_acl_get_fd(fd, &default_acl, &default_count)) { + if (!solaris_acl_get_fd(fsp->fh->fd, &default_acl, &default_count)) { DEBUG(10, ("error getting (default) acl from fd\n")); goto done; } @@ -258,14 +257,14 @@ int solarisacl_sys_acl_set_fd(vfs_handle_struct *handle, goto done; } - ret = facl(fd, SETACL, count, solaris_acl); + ret = facl(fsp->fh->fd, SETACL, count, solaris_acl); if (ret != 0) { DEBUG(10, ("call of facl failed (%s).\n", strerror(errno))); } done: - DEBUG(10, ("solarisacl_sys_acl_st_fd %s.\n", - ((ret == 0) ? "succeded" : "failed" ))); + DEBUG(10, ("solarisacl_sys_acl_set_fd %s.\n", + ((ret == 0) ? "succeeded" : "failed" ))); SAFE_FREE(solaris_acl); SAFE_FREE(default_acl); return ret; diff --git a/source3/modules/vfs_streams_depot.c b/source3/modules/vfs_streams_depot.c new file mode 100644 index 0000000000..fa85ea4a57 --- /dev/null +++ b/source3/modules/vfs_streams_depot.c @@ -0,0 +1,641 @@ +/* + * Store streams in a separate subdirectory + * + * Copyright (C) Volker Lendecke, 2007 + * + * 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" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_VFS + +/* + * Excerpt from a mail from tridge: + * + * Volker, what I'm thinking of is this: + * /mount-point/.streams/XX/YY/aaaa.bbbb/namedstream1 + * /mount-point/.streams/XX/YY/aaaa.bbbb/namedstream2 + * + * where XX/YY is a 2 level hash based on the fsid/inode. "aaaa.bbbb" + * is the fsid/inode. "namedstreamX" is a file named after the stream + * name. + */ + +static uint32_t hash_fn(DATA_BLOB key) +{ + uint32_t value; /* Used to compute the hash value. */ + uint32_t i; /* Used to cycle through random values. */ + + /* Set the initial value from the key size. */ + for (value = 0x238F13AF * key.length, i=0; i < key.length; i++) + value = (value + (key.data[i] << (i*5 % 24))); + + return (1103515243 * value + 12345); +} + +/* + * With the hashing scheme based on the inode we need to protect against + * streams showing up on files with re-used inodes. This can happen if we + * create a stream directory from within Samba, and a local process or NFS + * client deletes the file without deleting the streams directory. When the + * inode is re-used and the stream directory is still around, the streams in + * there would be show up as belonging to the new file. + * + * There are several workarounds for this, probably the easiest one is on + * systems which have a true birthtime stat element: When the file has a later + * birthtime than the streams directory, then we have to recreate the + * directory. + * + * The other workaround is to somehow mark the file as generated by Samba with + * something that a NFS client would not do. The closest one is a special + * xattr value being set. On systems which do not support xattrs, it might be + * an option to put in a special ACL entry for a non-existing group. + */ + +#define SAMBA_XATTR_MARKER "user.SAMBA_STREAMS" + +static bool file_is_valid(vfs_handle_struct *handle, const char *path) +{ + char buf; + + DEBUG(10, ("file_is_valid (%s) called\n", path)); + + if (SMB_VFS_NEXT_GETXATTR(handle, path, SAMBA_XATTR_MARKER, + &buf, sizeof(buf)) != sizeof(buf)) { + DEBUG(10, ("GETXATTR failed: %s\n", strerror(errno))); + return false; + } + + if (buf != '1') { + DEBUG(10, ("got wrong buffer content: '%c'\n", buf)); + return false; + } + + return true; +} + +static bool mark_file_valid(vfs_handle_struct *handle, const char *path) +{ + char buf = '1'; + int ret; + + DEBUG(10, ("marking file %s as valid\n", path)); + + ret = SMB_VFS_NEXT_SETXATTR(handle, path, SAMBA_XATTR_MARKER, + &buf, sizeof(buf), 0); + + if (ret == -1) { + DEBUG(10, ("SETXATTR failed: %s\n", strerror(errno))); + return false; + } + + return true; +} + +static char *stream_dir(vfs_handle_struct *handle, const char *base_path, + const SMB_STRUCT_STAT *base_sbuf, bool create_it) +{ + uint32_t hash; + char *result = NULL; + SMB_STRUCT_STAT sbuf; + uint8_t first, second; + char *tmp; + char *id_hex; + struct file_id id; + uint8 id_buf[16]; + + const char *rootdir = lp_parm_const_string( + SNUM(handle->conn), "streams", "directory", + handle->conn->connectpath); + + if (base_sbuf == NULL) { + if (SMB_VFS_NEXT_STAT(handle, base_path, &sbuf) == -1) { + /* + * base file is not there + */ + goto fail; + } + base_sbuf = &sbuf; + } + + id = SMB_VFS_FILE_ID_CREATE(handle->conn, base_sbuf->st_dev, + base_sbuf->st_ino); + + push_file_id_16((char *)id_buf, &id); + + hash = hash_fn(data_blob_const(id_buf, sizeof(id_buf))); + + first = hash & 0xff; + second = (hash >> 8) & 0xff; + + id_hex = hex_encode(talloc_tos(), id_buf, sizeof(id_buf)); + + if (id_hex == NULL) { + errno = ENOMEM; + goto fail; + } + + result = talloc_asprintf(talloc_tos(), "%s/%2.2X/%2.2X/%s", rootdir, + first, second, id_hex); + + TALLOC_FREE(id_hex); + + if (result == NULL) { + errno = ENOMEM; + return NULL; + } + + if (SMB_VFS_NEXT_STAT(handle, result, &sbuf) == 0) { + char *newname; + + if (!S_ISDIR(sbuf.st_mode)) { + errno = EINVAL; + goto fail; + } + + if (file_is_valid(handle, base_path)) { + return result; + } + + /* + * Someone has recreated a file under an existing inode + * without deleting the streams directory. For now, just move + * it away. + */ + + again: + newname = talloc_asprintf(talloc_tos(), "lost-%lu", random()); + if (newname == NULL) { + errno = ENOMEM; + goto fail; + } + + if (SMB_VFS_NEXT_RENAME(handle, result, newname) == -1) { + if ((errno == EEXIST) || (errno == ENOTEMPTY)) { + TALLOC_FREE(newname); + goto again; + } + goto fail; + } + + TALLOC_FREE(newname); + } + + if (!create_it) { + errno = ENOENT; + goto fail; + } + + if ((SMB_VFS_NEXT_MKDIR(handle, rootdir, 0755) != 0) + && (errno != EEXIST)) { + goto fail; + } + + tmp = talloc_asprintf(result, "%s/%2.2X", rootdir, first); + if (tmp == NULL) { + errno = ENOMEM; + goto fail; + } + + if ((SMB_VFS_NEXT_MKDIR(handle, tmp, 0755) != 0) + && (errno != EEXIST)) { + goto fail; + } + + TALLOC_FREE(tmp); + + tmp = talloc_asprintf(result, "%s/%2.2X/%2.2X", rootdir, first, + second); + if (tmp == NULL) { + errno = ENOMEM; + goto fail; + } + + if ((SMB_VFS_NEXT_MKDIR(handle, tmp, 0755) != 0) + && (errno != EEXIST)) { + goto fail; + } + + TALLOC_FREE(tmp); + + if ((SMB_VFS_NEXT_MKDIR(handle, result, 0755) != 0) + && (errno != EEXIST)) { + goto fail; + } + + if (!mark_file_valid(handle, base_path)) { + goto fail; + } + + return result; + + fail: + TALLOC_FREE(result); + return NULL; +} + +static char *stream_name(vfs_handle_struct *handle, const char *fname, + bool create_dir) +{ + char *base = NULL; + char *sname = NULL; + char *id_hex = NULL; + char *dirname, *stream_fname; + + if (!NT_STATUS_IS_OK(split_ntfs_stream_name(talloc_tos(), fname, + &base, &sname))) { + DEBUG(10, ("split_ntfs_stream_name failed\n")); + errno = ENOMEM; + goto fail; + } + + dirname = stream_dir(handle, base, NULL, create_dir); + + if (dirname == NULL) { + goto fail; + } + + stream_fname = talloc_asprintf(talloc_tos(), "%s/:%s", dirname, sname); + + if (stream_fname == NULL) { + errno = ENOMEM; + goto fail; + } + + DEBUG(10, ("stream filename = %s\n", stream_fname)); + + TALLOC_FREE(base); + TALLOC_FREE(sname); + TALLOC_FREE(id_hex); + + return stream_fname; + + fail: + DEBUG(5, ("stream_name failed: %s\n", strerror(errno))); + TALLOC_FREE(base); + TALLOC_FREE(sname); + TALLOC_FREE(id_hex); + return NULL; +} + +static NTSTATUS walk_streams(vfs_handle_struct *handle, + const char *fname, + const SMB_STRUCT_STAT *sbuf, + char **pdirname, + bool (*fn)(const char *dirname, + const char *dirent, + void *private_data), + void *private_data) +{ + char *dirname; + SMB_STRUCT_DIR *dirhandle = NULL; + char *dirent; + + dirname = stream_dir(handle, fname, sbuf, false); + + if (dirname == NULL) { + if (errno == ENOENT) { + /* + * no stream around + */ + return NT_STATUS_OK; + } + return map_nt_error_from_unix(errno); + } + + DEBUG(10, ("walk_streams: dirname=%s\n", dirname)); + + dirhandle = SMB_VFS_NEXT_OPENDIR(handle, dirname, NULL, 0); + + if (dirhandle == NULL) { + TALLOC_FREE(dirname); + return map_nt_error_from_unix(errno); + } + + while ((dirent = vfs_readdirname(handle->conn, dirhandle)) != NULL) { + + if (ISDOT(dirent) || ISDOTDOT(dirent)) { + continue; + } + + DEBUG(10, ("walk_streams: dirent=%s\n", dirent)); + + if (!fn(dirname, dirent, private_data)) { + break; + } + } + + SMB_VFS_NEXT_CLOSEDIR(handle, dirhandle); + + if (pdirname != NULL) { + *pdirname = dirname; + } + else { + TALLOC_FREE(dirname); + } + + return NT_STATUS_OK; +} + +static int streams_depot_stat(vfs_handle_struct *handle, const char *fname, + SMB_STRUCT_STAT *sbuf) +{ + char *stream_fname; + int ret = -1; + + DEBUG(10, ("streams_depot_stat called for [%s]\n", fname)); + + if (!is_ntfs_stream_name(fname)) { + return SMB_VFS_NEXT_STAT(handle, fname, sbuf); + } + + stream_fname = stream_name(handle, fname, false); + if (stream_fname == NULL) { + goto done; + } + + ret = SMB_VFS_NEXT_STAT(handle, stream_fname, sbuf); + + done: + TALLOC_FREE(stream_fname); + return ret; +} + +static int streams_depot_lstat(vfs_handle_struct *handle, const char *fname, + SMB_STRUCT_STAT *sbuf) +{ + char *stream_fname; + int ret = -1; + + if (!is_ntfs_stream_name(fname)) { + return SMB_VFS_NEXT_LSTAT(handle, fname, sbuf); + } + + stream_fname = stream_name(handle, fname, false); + if (stream_fname == NULL) { + goto done; + } + + ret = SMB_VFS_NEXT_LSTAT(handle, stream_fname, sbuf); + + done: + TALLOC_FREE(stream_fname); + return ret; +} + +static int streams_depot_open(vfs_handle_struct *handle, const char *fname, + files_struct *fsp, int flags, mode_t mode) +{ + TALLOC_CTX *frame; + char *base = NULL; + SMB_STRUCT_STAT base_sbuf; + char *stream_fname; + int ret = -1; + + if (!is_ntfs_stream_name(fname)) { + return SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode); + } + + frame = talloc_stackframe(); + + if (!NT_STATUS_IS_OK(split_ntfs_stream_name(talloc_tos(), fname, + &base, NULL))) { + errno = ENOMEM; + goto done; + } + + ret = SMB_VFS_NEXT_STAT(handle, base, &base_sbuf); + + if (ret == -1) { + goto done; + } + + TALLOC_FREE(base); + + stream_fname = stream_name(handle, fname, true); + if (stream_fname == NULL) { + goto done; + } + + ret = SMB_VFS_NEXT_OPEN(handle, stream_fname, fsp, flags, mode); + + done: + TALLOC_FREE(frame); + return ret; +} + +static int streams_depot_unlink(vfs_handle_struct *handle, const char *fname) +{ + int ret = -1; + SMB_STRUCT_STAT sbuf; + + DEBUG(10, ("streams_depot_unlink called for %s\n", fname)); + + if (is_ntfs_stream_name(fname)) { + char *stream_fname; + + stream_fname = stream_name(handle, fname, false); + if (stream_fname == NULL) { + return -1; + } + + ret = SMB_VFS_NEXT_UNLINK(handle, stream_fname); + + TALLOC_FREE(stream_fname); + return ret; + } + + /* + * We potentially need to delete the per-inode streams directory + */ + + if (SMB_VFS_NEXT_STAT(handle, fname, &sbuf) == -1) { + return -1; + } + + if (sbuf.st_nlink == 1) { + char *dirname = stream_dir(handle, fname, &sbuf, false); + + if (dirname != NULL) { + SMB_VFS_NEXT_RMDIR(handle, dirname); + } + TALLOC_FREE(dirname); + } + + return SMB_VFS_NEXT_UNLINK(handle, fname); +} + +static bool add_one_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams, + struct stream_struct **streams, + const char *name, SMB_OFF_T size, + SMB_OFF_T alloc_size) +{ + struct stream_struct *tmp; + + tmp = TALLOC_REALLOC_ARRAY(mem_ctx, *streams, struct stream_struct, + (*num_streams)+1); + if (tmp == NULL) { + return false; + } + + tmp[*num_streams].name = talloc_strdup(tmp, name); + if (tmp[*num_streams].name == NULL) { + return false; + } + + tmp[*num_streams].size = size; + tmp[*num_streams].alloc_size = alloc_size; + + *streams = tmp; + *num_streams += 1; + return true; +} + +struct streaminfo_state { + TALLOC_CTX *mem_ctx; + vfs_handle_struct *handle; + unsigned int num_streams; + struct stream_struct *streams; + NTSTATUS status; +}; + +static bool collect_one_stream(const char *dirname, + const char *dirent, + void *private_data) +{ + struct streaminfo_state *state = + (struct streaminfo_state *)private_data; + char *full_sname; + SMB_STRUCT_STAT sbuf; + + if (asprintf(&full_sname, "%s/%s", dirname, dirent) == -1) { + state->status = NT_STATUS_NO_MEMORY; + return false; + } + if (SMB_VFS_NEXT_STAT(state->handle, full_sname, &sbuf) == -1) { + DEBUG(10, ("Could not stat %s: %s\n", full_sname, + strerror(errno))); + SAFE_FREE(full_sname); + return true; + } + + SAFE_FREE(full_sname); + + if (!add_one_stream(state->mem_ctx, + &state->num_streams, &state->streams, + dirent, sbuf.st_size, + get_allocation_size( + state->handle->conn, NULL, &sbuf))) { + state->status = NT_STATUS_NO_MEMORY; + return false; + } + + return true; +} + +static NTSTATUS streams_depot_streaminfo(vfs_handle_struct *handle, + struct files_struct *fsp, + const char *fname, + TALLOC_CTX *mem_ctx, + unsigned int *pnum_streams, + struct stream_struct **pstreams) +{ + SMB_STRUCT_STAT sbuf; + int ret; + NTSTATUS status; + struct streaminfo_state state; + + if ((fsp != NULL) && (fsp->fh->fd != -1)) { + if (is_ntfs_stream_name(fsp->fsp_name)) { + return NT_STATUS_INVALID_PARAMETER; + } + ret = SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf); + } + else { + if (is_ntfs_stream_name(fname)) { + return NT_STATUS_INVALID_PARAMETER; + } + ret = SMB_VFS_NEXT_STAT(handle, fname, &sbuf); + } + + if (ret == -1) { + return map_nt_error_from_unix(errno); + } + + state.streams = NULL; + state.num_streams = 0; + + if (!S_ISDIR(sbuf.st_mode)) { + if (!add_one_stream(mem_ctx, + &state.num_streams, &state.streams, + "::$DATA", sbuf.st_size, + get_allocation_size(handle->conn, fsp, + &sbuf))) { + return NT_STATUS_NO_MEMORY; + } + } + + state.mem_ctx = mem_ctx; + state.handle = handle; + state.status = NT_STATUS_OK; + + status = walk_streams(handle, fname, &sbuf, NULL, collect_one_stream, + &state); + + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(state.streams); + return status; + } + + if (!NT_STATUS_IS_OK(state.status)) { + TALLOC_FREE(state.streams); + return state.status; + } + + *pnum_streams = state.num_streams; + *pstreams = state.streams; + return NT_STATUS_OK; +} + +static uint32_t streams_depot_fs_capabilities(struct vfs_handle_struct *handle) +{ + return SMB_VFS_NEXT_FS_CAPABILITIES(handle) | FILE_NAMED_STREAMS; +} + +/* VFS operations structure */ + +static vfs_op_tuple streams_depot_ops[] = { + {SMB_VFS_OP(streams_depot_fs_capabilities), SMB_VFS_OP_FS_CAPABILITIES, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(streams_depot_open), SMB_VFS_OP_OPEN, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(streams_depot_stat), SMB_VFS_OP_STAT, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(streams_depot_lstat), SMB_VFS_OP_LSTAT, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(streams_depot_unlink), SMB_VFS_OP_UNLINK, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(streams_depot_streaminfo), SMB_VFS_OP_STREAMINFO, + SMB_VFS_LAYER_OPAQUE}, + {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP} +}; + +NTSTATUS vfs_streams_depot_init(void); +NTSTATUS vfs_streams_depot_init(void) +{ + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "streams_depot", + streams_depot_ops); +} diff --git a/source3/modules/vfs_streams_xattr.c b/source3/modules/vfs_streams_xattr.c new file mode 100644 index 0000000000..766e7d10ab --- /dev/null +++ b/source3/modules/vfs_streams_xattr.c @@ -0,0 +1,685 @@ +/* + * Store streams in xattrs + * + * Copyright (C) Volker Lendecke, 2008 + * + * Partly based on James Peach's Darwin module, which is + * + * Copyright (C) James Peach 2006-2007 + * + * 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" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_VFS + +struct stream_io { + char *base; + char *xattr_name; +}; + +static SMB_INO_T stream_inode(const SMB_STRUCT_STAT *sbuf, const char *sname) +{ + struct MD5Context ctx; + unsigned char hash[16]; + SMB_INO_T result; + char *upper_sname; + + DEBUG(10, ("stream_inode called for %lu/%lu [%s]\n", + (unsigned long)sbuf->st_dev, + (unsigned long)sbuf->st_ino, sname)); + + upper_sname = talloc_strdup_upper(talloc_tos(), sname); + SMB_ASSERT(upper_sname != NULL); + + MD5Init(&ctx); + MD5Update(&ctx, (unsigned char *)&(sbuf->st_dev), + sizeof(sbuf->st_dev)); + MD5Update(&ctx, (unsigned char *)&(sbuf->st_ino), + sizeof(sbuf->st_ino)); + MD5Update(&ctx, (unsigned char *)upper_sname, + talloc_get_size(upper_sname)-1); + MD5Final(hash, &ctx); + + TALLOC_FREE(upper_sname); + + /* Hopefully all the variation is in the lower 4 (or 8) bytes! */ + memcpy(&result, hash, sizeof(result)); + + DEBUG(10, ("stream_inode returns %lu\n", (unsigned long)result)); + + return result; +} + +static ssize_t get_xattr_size(connection_struct *conn, const char *fname, + const char *xattr_name) +{ + NTSTATUS status; + struct ea_struct ea; + ssize_t result; + + status = get_ea_value(talloc_tos(), conn, NULL, fname, + xattr_name, &ea); + + if (!NT_STATUS_IS_OK(status)) { + return -1; + } + + result = ea.value.length-1; + TALLOC_FREE(ea.value.data); + return result; +} + + +static int streams_xattr_fstat(vfs_handle_struct *handle, files_struct *fsp, + SMB_STRUCT_STAT *sbuf) +{ + struct stream_io *io = (struct stream_io *) + VFS_FETCH_FSP_EXTENSION(handle, fsp); + + DEBUG(10, ("streams_xattr_fstat called for %d\n", fsp->fh->fd)); + + if (io == NULL) { + return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf); + } + + if (SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf) == -1) { + return -1; + } + + sbuf->st_size = get_xattr_size(handle->conn, io->base, io->xattr_name); + if (sbuf->st_size == -1) { + return -1; + } + + DEBUG(10, ("sbuf->st_size = %d\n", (int)sbuf->st_size)); + + sbuf->st_ino = stream_inode(sbuf, io->xattr_name); + sbuf->st_mode &= ~S_IFMT; + sbuf->st_mode |= S_IFREG; + sbuf->st_blocks = sbuf->st_size % STAT_ST_BLOCKSIZE + 1; + + return 0; +} + +static int streams_xattr_stat(vfs_handle_struct *handle, const char *fname, + SMB_STRUCT_STAT *sbuf) +{ + NTSTATUS status; + char *base = NULL, *sname = NULL; + int result = -1; + char *xattr_name; + + if (!is_ntfs_stream_name(fname)) { + return SMB_VFS_NEXT_STAT(handle, fname, sbuf); + } + + status = split_ntfs_stream_name(talloc_tos(), fname, &base, &sname); + if (!NT_STATUS_IS_OK(status)) { + errno = EINVAL; + return -1; + } + + if (SMB_VFS_STAT(handle->conn, base, sbuf) == -1) { + goto fail; + } + + xattr_name = talloc_asprintf(talloc_tos(), "%s%s", + SAMBA_XATTR_DOSSTREAM_PREFIX, sname); + if (xattr_name == NULL) { + errno = ENOMEM; + goto fail; + } + + sbuf->st_size = get_xattr_size(handle->conn, base, xattr_name); + if (sbuf->st_size == -1) { + errno = ENOENT; + goto fail; + } + + sbuf->st_ino = stream_inode(sbuf, xattr_name); + sbuf->st_mode &= ~S_IFMT; + sbuf->st_mode |= S_IFREG; + sbuf->st_blocks = sbuf->st_size % STAT_ST_BLOCKSIZE + 1; + + result = 0; + fail: + TALLOC_FREE(base); + TALLOC_FREE(sname); + return result; +} + +static int streams_xattr_lstat(vfs_handle_struct *handle, const char *fname, + SMB_STRUCT_STAT *sbuf) +{ + NTSTATUS status; + char *base, *sname; + int result = -1; + char *xattr_name; + + if (!is_ntfs_stream_name(fname)) { + return SMB_VFS_NEXT_LSTAT(handle, fname, sbuf); + } + + status = split_ntfs_stream_name(talloc_tos(), fname, &base, &sname); + if (!NT_STATUS_IS_OK(status)) { + errno = EINVAL; + goto fail; + } + + if (SMB_VFS_LSTAT(handle->conn, base, sbuf) == -1) { + goto fail; + } + + xattr_name = talloc_asprintf(talloc_tos(), "%s%s", + SAMBA_XATTR_DOSSTREAM_PREFIX, sname); + if (xattr_name == NULL) { + errno = ENOMEM; + goto fail; + } + + sbuf->st_size = get_xattr_size(handle->conn, base, xattr_name); + if (sbuf->st_size == -1) { + errno = ENOENT; + goto fail; + } + + sbuf->st_ino = stream_inode(sbuf, xattr_name); + sbuf->st_mode &= ~S_IFMT; + sbuf->st_mode |= S_IFREG; + sbuf->st_blocks = sbuf->st_size % STAT_ST_BLOCKSIZE + 1; + + result = 0; + fail: + TALLOC_FREE(base); + TALLOC_FREE(sname); + return result; +} + +static int streams_xattr_open(vfs_handle_struct *handle, const char *fname, + files_struct *fsp, int flags, mode_t mode) +{ + TALLOC_CTX *frame; + NTSTATUS status; + struct stream_io *sio; + char *base, *sname; + struct ea_struct ea; + char *xattr_name; + int baseflags; + int hostfd = -1; + + DEBUG(10, ("streams_xattr_open called for %s\n", fname)); + + if (!is_ntfs_stream_name(fname)) { + return SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode); + } + + frame = talloc_stackframe(); + + status = split_ntfs_stream_name(talloc_tos(), fname, + &base, &sname); + if (!NT_STATUS_IS_OK(status)) { + errno = EINVAL; + goto fail; + } + + xattr_name = talloc_asprintf(talloc_tos(), "%s%s", + SAMBA_XATTR_DOSSTREAM_PREFIX, sname); + if (xattr_name == NULL) { + errno = ENOMEM; + goto fail; + } + + /* + * We use baseflags to turn off nasty side-effects when opening the + * underlying file. + */ + baseflags = flags; + baseflags &= ~O_TRUNC; + baseflags &= ~O_EXCL; + baseflags &= ~O_CREAT; + + hostfd = SMB_VFS_OPEN(handle->conn, base, fsp, baseflags, mode); + + /* It is legit to open a stream on a directory, but the base + * fd has to be read-only. + */ + if ((hostfd == -1) && (errno == EISDIR)) { + baseflags &= ~O_ACCMODE; + baseflags |= O_RDONLY; + hostfd = SMB_VFS_OPEN(handle->conn, fname, fsp, baseflags, + mode); + } + + if (hostfd == -1) { + goto fail; + } + + status = get_ea_value(talloc_tos(), handle->conn, NULL, base, + xattr_name, &ea); + + DEBUG(10, ("get_ea_value returned %s\n", nt_errstr(status))); + + if (!NT_STATUS_IS_OK(status) + && !NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { + /* + * The base file is not there. This is an error even if we got + * O_CREAT, the higher levels should have created the base + * file for us. + */ + DEBUG(10, ("streams_xattr_open: base file %s not around, " + "returning ENOENT\n", base)); + errno = ENOENT; + goto fail; + } + + if (!NT_STATUS_IS_OK(status)) { + /* + * The attribute does not exist + */ + + if (flags & O_CREAT) { + /* + * Darn, xattrs need at least 1 byte + */ + char null = '\0'; + + DEBUG(10, ("creating attribute %s on file %s\n", + xattr_name, base)); + + if (SMB_VFS_SETXATTR( + handle->conn, base, xattr_name, + &null, sizeof(null), + flags & O_EXCL ? XATTR_CREATE : 0) == -1) { + goto fail; + } + } + } + + if (flags & O_TRUNC) { + char null = '\0'; + if (SMB_VFS_SETXATTR( + handle->conn, base, xattr_name, + &null, sizeof(null), + flags & O_EXCL ? XATTR_CREATE : 0) == -1) { + goto fail; + } + } + + sio = (struct stream_io *)VFS_ADD_FSP_EXTENSION(handle, fsp, + struct stream_io); + if (sio == NULL) { + errno = ENOMEM; + goto fail; + } + + sio->xattr_name = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(handle, fsp), + xattr_name); + sio->base = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(handle, fsp), + base); + + if ((sio->xattr_name == NULL) || (sio->base == NULL)) { + errno = ENOMEM; + goto fail; + } + + TALLOC_FREE(frame); + return hostfd; + + fail: + if (hostfd >= 0) { + /* + * BUGBUGBUG -- we would need to call fd_close_posix here, but + * we don't have a full fsp yet + */ + SMB_VFS_CLOSE(fsp, hostfd); + } + + TALLOC_FREE(frame); + return -1; +} + +static int streams_xattr_unlink(vfs_handle_struct *handle, const char *fname) +{ + NTSTATUS status; + char *base = NULL; + char *sname = NULL; + int ret = -1; + char *xattr_name; + + if (!is_ntfs_stream_name(fname)) { + return SMB_VFS_NEXT_UNLINK(handle, fname); + } + + status = split_ntfs_stream_name(talloc_tos(), fname, &base, &sname); + if (!NT_STATUS_IS_OK(status)) { + errno = EINVAL; + goto fail; + } + + xattr_name = talloc_asprintf(talloc_tos(), "%s%s", + SAMBA_XATTR_DOSSTREAM_PREFIX, sname); + if (xattr_name == NULL) { + errno = ENOMEM; + goto fail; + } + + ret = SMB_VFS_REMOVEXATTR(handle->conn, base, xattr_name); + + if ((ret == -1) && (errno == ENOATTR)) { + errno = ENOENT; + goto fail; + } + + ret = 0; + + fail: + TALLOC_FREE(base); + TALLOC_FREE(sname); + return ret; +} + +static NTSTATUS walk_xattr_streams(connection_struct *conn, files_struct *fsp, + const char *fname, + bool (*fn)(struct ea_struct *ea, + void *private_data), + void *private_data) +{ + NTSTATUS status; + char **names; + size_t i, num_names; + size_t prefix_len = strlen(SAMBA_XATTR_DOSSTREAM_PREFIX); + + status = get_ea_names_from_file(talloc_tos(), conn, fsp, fname, + &names, &num_names); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + for (i=0; i<num_names; i++) { + struct ea_struct ea; + + if (strncmp(names[i], SAMBA_XATTR_DOSSTREAM_PREFIX, + prefix_len) != 0) { + continue; + } + + status = get_ea_value(names, conn, fsp, fname, names[i], &ea); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("Could not get ea %s for file %s: %s\n", + names[i], fname, nt_errstr(status))); + continue; + } + + ea.name = talloc_asprintf(ea.value.data, ":%s", + names[i] + prefix_len); + if (ea.name == NULL) { + DEBUG(0, ("talloc failed\n")); + continue; + } + + if (!fn(&ea, private_data)) { + TALLOC_FREE(ea.value.data); + return NT_STATUS_OK; + } + + TALLOC_FREE(ea.value.data); + } + + TALLOC_FREE(names); + return NT_STATUS_OK; +} + +static bool add_one_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams, + struct stream_struct **streams, + const char *name, SMB_OFF_T size, + SMB_OFF_T alloc_size) +{ + struct stream_struct *tmp; + + tmp = TALLOC_REALLOC_ARRAY(mem_ctx, *streams, struct stream_struct, + (*num_streams)+1); + if (tmp == NULL) { + return false; + } + + tmp[*num_streams].name = talloc_strdup(tmp, name); + if (tmp[*num_streams].name == NULL) { + return false; + } + + tmp[*num_streams].size = size; + tmp[*num_streams].alloc_size = alloc_size; + + *streams = tmp; + *num_streams += 1; + return true; +} + +struct streaminfo_state { + TALLOC_CTX *mem_ctx; + vfs_handle_struct *handle; + unsigned int num_streams; + struct stream_struct *streams; + NTSTATUS status; +}; + +static bool collect_one_stream(struct ea_struct *ea, void *private_data) +{ + struct streaminfo_state *state = + (struct streaminfo_state *)private_data; + + if (!add_one_stream(state->mem_ctx, + &state->num_streams, &state->streams, + ea->name, ea->value.length-1, + smb_roundup(state->handle->conn, + ea->value.length-1))) { + state->status = NT_STATUS_NO_MEMORY; + return false; + } + + return true; +} + +static NTSTATUS streams_xattr_streaminfo(vfs_handle_struct *handle, + struct files_struct *fsp, + const char *fname, + TALLOC_CTX *mem_ctx, + unsigned int *pnum_streams, + struct stream_struct **pstreams) +{ + SMB_STRUCT_STAT sbuf; + int ret; + NTSTATUS status; + struct streaminfo_state state; + + if ((fsp != NULL) && (fsp->fh->fd != -1)) { + if (is_ntfs_stream_name(fsp->fsp_name)) { + return NT_STATUS_INVALID_PARAMETER; + } + ret = SMB_VFS_FSTAT(fsp, &sbuf); + } + else { + if (is_ntfs_stream_name(fname)) { + return NT_STATUS_INVALID_PARAMETER; + } + ret = SMB_VFS_STAT(handle->conn, fname, &sbuf); + } + + if (ret == -1) { + return map_nt_error_from_unix(errno); + } + + state.streams = NULL; + state.num_streams = 0; + + if (!S_ISDIR(sbuf.st_mode)) { + if (!add_one_stream(mem_ctx, + &state.num_streams, &state.streams, + "::$DATA", sbuf.st_size, + get_allocation_size(handle->conn, fsp, + &sbuf))) { + return NT_STATUS_NO_MEMORY; + } + } + + state.mem_ctx = mem_ctx; + state.handle = handle; + state.status = NT_STATUS_OK; + + status = walk_xattr_streams(handle->conn, fsp, fname, + collect_one_stream, &state); + + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(state.streams); + return status; + } + + if (!NT_STATUS_IS_OK(state.status)) { + TALLOC_FREE(state.streams); + return state.status; + } + + *pnum_streams = state.num_streams; + *pstreams = state.streams; + return NT_STATUS_OK; +} + +static uint32_t streams_xattr_fs_capabilities(struct vfs_handle_struct *handle) +{ + return SMB_VFS_NEXT_FS_CAPABILITIES(handle) | FILE_NAMED_STREAMS; +} + +static ssize_t streams_xattr_pwrite(vfs_handle_struct *handle, + files_struct *fsp, const void *data, + size_t n, SMB_OFF_T offset) +{ + struct stream_io *sio = + (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp); + struct ea_struct ea; + NTSTATUS status; + int ret; + + DEBUG(10, ("streams_xattr_pwrite called for %d bytes\n", (int)n)); + + if (sio == NULL) { + return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset); + } + + status = get_ea_value(talloc_tos(), handle->conn, fsp->base_fsp, + sio->base, sio->xattr_name, &ea); + if (!NT_STATUS_IS_OK(status)) { + return -1; + } + + if ((offset + n) > ea.value.length-1) { + uint8 *tmp; + + tmp = TALLOC_REALLOC_ARRAY(talloc_tos(), ea.value.data, uint8, + offset + n + 1); + + if (tmp == NULL) { + TALLOC_FREE(ea.value.data); + errno = ENOMEM; + return -1; + } + ea.value.data = tmp; + ea.value.length = offset + n + 1; + ea.value.data[offset+n] = 0; + } + + memcpy(ea.value.data + offset, data, n); + + ret = SMB_VFS_SETXATTR(fsp->conn, fsp->base_fsp->fsp_name, + sio->xattr_name, + ea.value.data, ea.value.length, 0); + + TALLOC_FREE(ea.value.data); + + if (ret == -1) { + return -1; + } + + return n; +} + +static ssize_t streams_xattr_pread(vfs_handle_struct *handle, + files_struct *fsp, void *data, + size_t n, SMB_OFF_T offset) +{ + struct stream_io *sio = + (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp); + struct ea_struct ea; + NTSTATUS status; + size_t length, overlap; + + if (sio == NULL) { + return SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset); + } + + status = get_ea_value(talloc_tos(), handle->conn, fsp->base_fsp, + sio->base, sio->xattr_name, &ea); + if (!NT_STATUS_IS_OK(status)) { + return -1; + } + + length = ea.value.length-1; + + /* Attempt to read past EOF. */ + if (length <= offset) { + errno = EINVAL; + return -1; + } + + overlap = (offset + n) > length ? (length - offset) : n; + memcpy(data, ea.value.data + offset, overlap); + + TALLOC_FREE(ea.value.data); + return overlap; +} + +/* VFS operations structure */ + +static vfs_op_tuple streams_xattr_ops[] = { + {SMB_VFS_OP(streams_xattr_fs_capabilities), SMB_VFS_OP_FS_CAPABILITIES, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(streams_xattr_open), SMB_VFS_OP_OPEN, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(streams_xattr_stat), SMB_VFS_OP_STAT, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(streams_xattr_fstat), SMB_VFS_OP_FSTAT, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(streams_xattr_lstat), SMB_VFS_OP_LSTAT, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(streams_xattr_pread), SMB_VFS_OP_PREAD, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(streams_xattr_pwrite), SMB_VFS_OP_PWRITE, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(streams_xattr_lstat), SMB_VFS_OP_LSTAT, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(streams_xattr_unlink), SMB_VFS_OP_UNLINK, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(streams_xattr_streaminfo), SMB_VFS_OP_STREAMINFO, + SMB_VFS_LAYER_OPAQUE}, + {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP} +}; + +NTSTATUS vfs_streams_xattr_init(void); +NTSTATUS vfs_streams_xattr_init(void) +{ + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "streams_xattr", + streams_xattr_ops); +} diff --git a/source3/modules/vfs_tru64acl.c b/source3/modules/vfs_tru64acl.c index 43cae0f826..b23a7ddcfa 100644 --- a/source3/modules/vfs_tru64acl.c +++ b/source3/modules/vfs_tru64acl.c @@ -1,7 +1,7 @@ /* Unix SMB/Netbios implementation. VFS module to get and set Tru64 acls - Copyright (C) Michael Adam 2006 + Copyright (C) Michael Adam 2006,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 @@ -67,11 +67,10 @@ SMB_ACL_T tru64acl_sys_acl_get_file(vfs_handle_struct *handle, } SMB_ACL_T tru64acl_sys_acl_get_fd(vfs_handle_struct *handle, - files_struct *fsp, - int fd) + files_struct *fsp) { struct smb_acl_t *result; - acl_t tru64_acl = acl_get_fd(fd, ACL_TYPE_ACCESS); + acl_t tru64_acl = acl_get_fd(fsp->fh->fd, ACL_TYPE_ACCESS); if (tru64_acl == NULL) { return NULL; @@ -129,14 +128,14 @@ fail: int tru64acl_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, - int fd, SMB_ACL_T theacl) + SMB_ACL_T theacl) { int res; acl_t tru64_acl = smb_acl_to_tru64_acl(theacl); if (tru64_acl == NULL) { return -1; } - res = acl_set_fd(fd, ACL_TYPE_ACCESS, tru64_acl); + res = acl_set_fd(fsp->fh->fd, ACL_TYPE_ACCESS, tru64_acl); acl_free(tru64_acl); return res; diff --git a/source3/modules/vfs_tsmsm.c b/source3/modules/vfs_tsmsm.c new file mode 100644 index 0000000000..2805488e8b --- /dev/null +++ b/source3/modules/vfs_tsmsm.c @@ -0,0 +1,341 @@ +/* + Unix SMB/CIFS implementation. + Samba VFS module for handling offline files + with Tivoli Storage Manager Space Management + + (c) Alexander Bokovoy, 2007 + (c) Andrew Tridgell, 2007 + + 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/>. + */ +/* + This VFS module accepts following options: + tsmsm: hsm script = <path to hsm script> (/bin/true by default, i.e. does nothing) + hsm script should point to a shell script which accepts two arguments: + <operation> <filepath> + where <operation> is currently 'offline' to set offline status of the <filepath> + + tsmsm: online ratio = ratio to check reported size against actual file size (0.5 by default) + + The TSMSM VFS module tries to avoid calling expensive DMAPI calls with some heuristics + based on the fact that number of blocks reported of a file multiplied by 512 will be + bigger than 'online ratio' of actual size for online (non-migrated) files. + + If checks fail, we call DMAPI and ask for specific IBM attribute which present for + offline (migrated) files. If this attribute presents, we consider file offline. + */ + +#include "includes.h" + +#ifndef USE_DMAPI +#error "This module requires DMAPI support!" +#endif + +#ifdef HAVE_XFS_DMAPI_H +#include <xfs/dmapi.h> +#elif defined(HAVE_SYS_DMI_H) +#include <sys/dmi.h> +#elif defined(HAVE_SYS_JFSDMAPI_H) +#include <sys/jfsdmapi.h> +#elif defined(HAVE_SYS_DMAPI_H) +#include <sys/dmapi.h> +#elif defined(HAVE_DMAPI_H) +#include <dmapi.h> +#endif + +#ifndef _ISOC99_SOURCE +#define _ISOC99_SOURCE +#endif + +#include <math.h> + +/* optimisation tunables - used to avoid the DMAPI slow path */ +#define FILE_IS_ONLINE_RATIO 0.5 +#define DM_ATTRIB_OBJECT "IBMObj" +#define DM_ATTRIB_MIGRATED "IBMMig" + +struct tsmsm_struct { + dm_sessid_t sid; + float online_ratio; + char *hsmscript; +}; + +#define TSM_STRINGIFY(a) #a +#define TSM_TOSTRING(a) TSM_STRINGIFY(a) + +static void tsmsm_free_data(void **pptr) { + struct tsmsm_struct **tsmd = (struct tsmsm_struct **)pptr; + if(!tsmd) return; + TALLOC_FREE(*tsmd); +} + +static int tsmsm_connect(struct vfs_handle_struct *handle, + const char *service, + const char *user) { + struct tsmsm_struct *tsmd = TALLOC_ZERO_P(handle, struct tsmsm_struct); + const char *hsmscript, *tsmname; + const char *fres; + + if (!tsmd) { + DEBUG(0,("tsmsm_connect: out of memory!\n")); + return -1; + } + + tsmd->sid = *(dm_sessid_t*) dmapi_get_current_session(); + + if (tsmd->sid == DM_NO_SESSION) { + DEBUG(0,("tsmsm_connect: no DMAPI session for Samba is available!\n")); + TALLOC_FREE(tsmd); + return -1; + } + + tsmname = (handle->param ? handle->param : "tsmsm"); + hsmscript = lp_parm_const_string(SNUM(handle->conn), tsmname, + "hsm script", NULL); + if (hsmscript) { + tsmd->hsmscript = talloc_strdup(tsmd, hsmscript); + if(!tsmd->hsmscript) { + DEBUG(1, ("tsmsm_connect: can't allocate memory for hsm script path")); + TALLOC_FREE(tsmd); + return -1; + } + } else { + DEBUG(1, ("tsmsm_connect: can't call hsm script because it " + "is not set to anything in the smb.conf\n" + "Use %s: 'hsm script = path' to set it\n", + tsmname)); + TALLOC_FREE(tsmd); + return -1; + } + + fres = lp_parm_const_string(SNUM(handle->conn), tsmname, + "online ratio", TSM_TOSTRING(FILE_IS_ONLINE_RATIO)); + tsmd->online_ratio = strtof(fres, NULL); + if((tsmd->online_ratio == (float)0) || ((errno == ERANGE) && + ((tsmd->online_ratio == HUGE_VALF) || + (tsmd->online_ratio == HUGE_VALL)))) { + DEBUG(1, ("tsmsm_connect: error while getting online ratio from smb.conf." + "Default to %s.\n", TSM_TOSTRING(FILE_IS_ONLINE_RATIO))); + tsmd->online_ratio = FILE_IS_ONLINE_RATIO; + } + + /* Store the private data. */ + SMB_VFS_HANDLE_SET_DATA(handle, tsmd, tsmsm_free_data, + struct tsmsm_struct, return -1); + return SMB_VFS_NEXT_CONNECT(handle, service, user); +} + +static bool tsmsm_is_offline(struct vfs_handle_struct *handle, + const char *path, + SMB_STRUCT_STAT *stbuf) { + struct tsmsm_struct *tsmd = (struct tsmsm_struct *) handle->data; + void *dmhandle = NULL; + size_t dmhandle_len = 0; + size_t rlen; + dm_attrname_t dmname; + int ret; + bool offline; + + /* if the file has more than FILE_IS_ONLINE_RATIO of blocks available, + then assume it is not offline (it may not be 100%, as it could be sparse) */ + if (512 * (off_t)stbuf->st_blocks >= stbuf->st_size * tsmd->online_ratio) { + DEBUG(10,("%s not offline: st_blocks=%ld st_size=%ld online_ratio=%.2f\n", + path, stbuf->st_blocks, stbuf->st_size, tsmd->online_ratio)); + return false; + } + + /* using POSIX capabilities does not work here. It's a slow path, so + * become_root() is just as good anyway (tridge) + */ + + /* Also, AIX has DMAPI but no POSIX capablities support. In this case, + * we need to be root to do DMAPI manipulations. + */ + become_root(); + + /* go the slow DMAPI route */ + if (dm_path_to_handle((char*)path, &dmhandle, &dmhandle_len) != 0) { + DEBUG(2,("dm_path_to_handle failed - assuming offline (%s) - %s\n", + path, strerror(errno))); + offline = true; + goto done; + } + + memset(&dmname, 0, sizeof(dmname)); + strlcpy((char *)&dmname.an_chars[0], DM_ATTRIB_OBJECT, sizeof(dmname.an_chars)); + + ret = dm_get_dmattr(tsmd->sid, dmhandle, dmhandle_len, + DM_NO_TOKEN, &dmname, 0, NULL, &rlen); + + /* its offline if the IBMObj attribute exists */ + offline = (ret == 0 || (ret == -1 && errno == E2BIG)); + + DEBUG(10,("dm_get_dmattr %s ret=%d (%s)\n", path, ret, strerror(errno))); + + ret = 0; + + dm_handle_free(dmhandle, dmhandle_len); + +done: + unbecome_root(); + return offline; +} + + +static bool tsmsm_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp) +{ + SMB_STRUCT_STAT sbuf; + struct tsmsm_struct *tsmd = (struct tsmsm_struct *) handle->data; + /* see if the file might be offline. This is called before each IO + to ensure we use AIO if the file is offline. We don't do the full dmapi + call as that would be too slow, instead we err on the side of using AIO + if the file might be offline + */ + if(SMB_VFS_FSTAT(fsp, &sbuf) == 0) { + DEBUG(10,("tsmsm_aio_force st_blocks=%ld st_size=%ld online_ratio=%.2f\n", + sbuf.st_blocks, sbuf.st_size, tsmd->online_ratio)); + return !(512 * (off_t)sbuf.st_blocks >= sbuf.st_size * tsmd->online_ratio); + } + return false; +} + +static ssize_t tsmsm_aio_return(struct vfs_handle_struct *handle, struct files_struct *fsp, + SMB_STRUCT_AIOCB *aiocb) +{ + ssize_t result; + + result = SMB_VFS_NEXT_AIO_RETURN(handle, fsp, aiocb); + if(result >= 0) { + notify_fname(handle->conn, NOTIFY_ACTION_MODIFIED, + FILE_NOTIFY_CHANGE_ATTRIBUTES, + fsp->fsp_name); + } + + return result; +} + +static ssize_t tsmsm_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fsp, const DATA_BLOB *hdr, + SMB_OFF_T offset, size_t n) +{ + bool file_online = tsmsm_aio_force(handle, fsp); + + if(!file_online) + return ENOSYS; + + return SMB_VFS_NEXT_SENDFILE(handle, tofd, fsp, hdr, offset, n); +} + +/* We do overload pread to allow notification when file becomes online after offline status */ +/* We don't intercept SMB_VFS_READ here because all file I/O now goes through SMB_VFS_PREAD instead */ +static ssize_t tsmsm_pread(struct vfs_handle_struct *handle, struct files_struct *fsp, + void *data, size_t n, SMB_OFF_T offset) { + ssize_t result; + bool notify_online = tsmsm_aio_force(handle, fsp); + + result = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset); + if((result != -1) && notify_online) { + /* We can't actually force AIO at this point (came here not from reply_read_and_X) + what we can do is to send notification that file became online + */ + notify_fname(handle->conn, NOTIFY_ACTION_MODIFIED, + FILE_NOTIFY_CHANGE_ATTRIBUTES, + fsp->fsp_name); + } + + return result; +} + +static ssize_t tsmsm_pwrite(struct vfs_handle_struct *handle, struct files_struct *fsp, + void *data, size_t n, SMB_OFF_T offset) { + ssize_t result; + bool notify_online = tsmsm_aio_force(handle, fsp); + + result = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset); + if((result != -1) && notify_online) { + /* We can't actually force AIO at this point (came here not from reply_read_and_X) + what we can do is to send notification that file became online + */ + notify_fname(handle->conn, NOTIFY_ACTION_MODIFIED, + FILE_NOTIFY_CHANGE_ATTRIBUTES, + fsp->fsp_name); + } + + return result; +} + +static int tsmsm_set_offline(struct vfs_handle_struct *handle, + const char *path) { + struct tsmsm_struct *tsmd = (struct tsmsm_struct *) handle->data; + int result = 0; + char *command; + + /* Now, call the script */ + command = talloc_asprintf(tsmd, "%s offline \"%s\"", tsmd->hsmscript, path); + if(!command) { + DEBUG(1, ("tsmsm_set_offline: can't allocate memory to run hsm script")); + return -1; + } + DEBUG(10, ("tsmsm_set_offline: Running [%s]\n", command)); + if((result = smbrun(command, NULL)) != 0) { + DEBUG(1,("tsmsm_set_offline: Running [%s] returned %d\n", command, result)); + } + TALLOC_FREE(command); + return result; +} + +static bool tsmsm_statvfs(struct vfs_handle_struct *handle, const char *path, vfs_statvfs_struct *statbuf) +{ + bool result; + + result = SMB_VFS_NEXT_STATVFS(handle, path, statbuf); + statbuf->FsCapabilities | = FILE_SUPPORTS_REMOTE_STORAGE | FILE_SUPPORTS_REPARSE_POINTS; + + return result; +} + +static vfs_op_tuple vfs_tsmsm_ops[] = { + + /* Disk operations */ + + {SMB_VFS_OP(tsmsm_connect), SMB_VFS_OP_CONNECT, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(tsmsm_statvfs), SMB_VFS_OP_STATVFS, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(tsmsm_aio_force), SMB_VFS_OP_AIO_FORCE, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(tsmsm_aio_return), SMB_VFS_OP_AIO_RETURN, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(tsmsm_pread), SMB_VFS_OP_PREAD, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(tsmsm_pwrite), SMB_VFS_OP_PWRITE, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(tsmsm_sendfile), SMB_VFS_OP_SENDFILE, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(tsmsm_is_offline), SMB_VFS_OP_IS_OFFLINE, + SMB_VFS_LAYER_OPAQUE}, + {SMB_VFS_OP(tsmsm_set_offline), SMB_VFS_OP_SET_OFFLINE, + SMB_VFS_LAYER_OPAQUE}, + + /* Finish VFS operations definition */ + + {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, + SMB_VFS_LAYER_NOOP} +}; + +NTSTATUS vfs_tsmsm_init(void); +NTSTATUS vfs_tsmsm_init(void) +{ + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, + "tsmsm", vfs_tsmsm_ops); +} diff --git a/source3/modules/vfs_xattr_tdb.c b/source3/modules/vfs_xattr_tdb.c new file mode 100644 index 0000000000..171022b01b --- /dev/null +++ b/source3/modules/vfs_xattr_tdb.c @@ -0,0 +1,755 @@ +/* + * Store posix-level xattrs in a tdb + * + * Copyright (C) Volker Lendecke, 2007 + * + * 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" +#include "librpc/gen_ndr/xattr.h" +#include "librpc/gen_ndr/ndr_xattr.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_VFS + +/* + * unmarshall tdb_xattrs + */ + +static NTSTATUS xattr_tdb_pull_attrs(TALLOC_CTX *mem_ctx, + const TDB_DATA *data, + struct tdb_xattrs **presult) +{ + DATA_BLOB blob; + enum ndr_err_code ndr_err; + struct tdb_xattrs *result; + + if (!(result = TALLOC_ZERO_P(mem_ctx, struct tdb_xattrs))) { + return NT_STATUS_NO_MEMORY; + } + + if (data->dsize == 0) { + *presult = result; + return NT_STATUS_OK; + } + + blob = data_blob_const(data->dptr, data->dsize); + + ndr_err = ndr_pull_struct_blob( + &blob, result, result, + (ndr_pull_flags_fn_t)ndr_pull_tdb_xattrs); + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(0, ("ndr_pull_tdb_xattrs failed: %s\n", + ndr_errstr(ndr_err))); + TALLOC_FREE(result); + return ndr_map_error2ntstatus(ndr_err);; + } + + *presult = result; + return NT_STATUS_OK; +} + +/* + * marshall tdb_xattrs + */ + +static NTSTATUS xattr_tdb_push_attrs(TALLOC_CTX *mem_ctx, + const struct tdb_xattrs *attribs, + TDB_DATA *data) +{ + DATA_BLOB blob; + enum ndr_err_code ndr_err; + + ndr_err = ndr_push_struct_blob( + &blob, mem_ctx, attribs, + (ndr_push_flags_fn_t)ndr_push_tdb_xattrs); + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(0, ("ndr_push_tdb_xattrs failed: %s\n", + ndr_errstr(ndr_err))); + return ndr_map_error2ntstatus(ndr_err);; + } + + *data = make_tdb_data(blob.data, blob.length); + return NT_STATUS_OK; +} + +/* + * Load tdb_xattrs for a file from the tdb + */ + +static NTSTATUS xattr_tdb_load_attrs(TALLOC_CTX *mem_ctx, + struct db_context *db_ctx, + const struct file_id *id, + struct tdb_xattrs **presult) +{ + uint8 id_buf[16]; + NTSTATUS status; + TDB_DATA data; + + push_file_id_16((char *)id_buf, id); + + if (db_ctx->fetch(db_ctx, mem_ctx, + make_tdb_data(id_buf, sizeof(id_buf)), + &data) == -1) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + status = xattr_tdb_pull_attrs(mem_ctx, &data, presult); + TALLOC_FREE(data.dptr); + return status; +} + +/* + * fetch_lock the tdb_ea record for a file + */ + +static struct db_record *xattr_tdb_lock_attrs(TALLOC_CTX *mem_ctx, + struct db_context *db_ctx, + const struct file_id *id) +{ + uint8 id_buf[16]; + push_file_id_16((char *)id_buf, id); + return db_ctx->fetch_locked(db_ctx, mem_ctx, + make_tdb_data(id_buf, sizeof(id_buf))); +} + +/* + * Save tdb_xattrs to a previously fetch_locked record + */ + +static NTSTATUS xattr_tdb_save_attrs(struct db_record *rec, + const struct tdb_xattrs *attribs) +{ + TDB_DATA data = tdb_null; + NTSTATUS status; + + status = xattr_tdb_push_attrs(talloc_tos(), attribs, &data); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("xattr_tdb_push_attrs failed: %s\n", + nt_errstr(status))); + return status; + } + + status = rec->store(rec, data, 0); + + TALLOC_FREE(data.dptr); + + return status; +} + +/* + * Worker routine for getxattr and fgetxattr + */ + +static ssize_t xattr_tdb_getattr(struct db_context *db_ctx, + const struct file_id *id, + const char *name, void *value, size_t size) +{ + struct tdb_xattrs *attribs; + uint32_t i; + ssize_t result = -1; + NTSTATUS status; + + DEBUG(10, ("xattr_tdb_getattr called for file %s, name %s\n", + file_id_string_tos(id), name)); + + status = xattr_tdb_load_attrs(talloc_tos(), db_ctx, id, &attribs); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n", + nt_errstr(status))); + errno = EINVAL; + return -1; + } + + for (i=0; i<attribs->num_xattrs; i++) { + if (strcmp(attribs->xattrs[i].name, name) == 0) { + break; + } + } + + if (i == attribs->num_xattrs) { + errno = ENOATTR; + goto fail; + } + + if (attribs->xattrs[i].value.length > size) { + errno = ERANGE; + goto fail; + } + + memcpy(value, attribs->xattrs[i].value.data, + attribs->xattrs[i].value.length); + result = attribs->xattrs[i].value.length; + + fail: + TALLOC_FREE(attribs); + return result; +} + +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; + + SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1); + + if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) { + return -1; + } + + id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino); + + return xattr_tdb_getattr(db, &id, name, value, size); +} + +static ssize_t xattr_tdb_fgetxattr(struct vfs_handle_struct *handle, + struct files_struct *fsp, + const char *name, void *value, size_t size) +{ + SMB_STRUCT_STAT sbuf; + struct file_id id; + struct db_context *db; + + SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1); + + if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) { + return -1; + } + + id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino); + + return xattr_tdb_getattr(db, &id, name, value, size); +} + +/* + * Worker routine for setxattr and fsetxattr + */ + +static int xattr_tdb_setattr(struct db_context *db_ctx, + const struct file_id *id, const char *name, + const void *value, size_t size, int flags) +{ + NTSTATUS status; + struct db_record *rec; + struct tdb_xattrs *attribs; + uint32_t i; + + DEBUG(10, ("xattr_tdb_setattr called for file %s, name %s\n", + file_id_string_tos(id), name)); + + rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id); + + if (rec == NULL) { + DEBUG(0, ("xattr_tdb_lock_attrs failed\n")); + errno = EINVAL; + return -1; + } + + status = xattr_tdb_pull_attrs(rec, &rec->value, &attribs); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n", + nt_errstr(status))); + TALLOC_FREE(rec); + return -1; + } + + for (i=0; i<attribs->num_xattrs; i++) { + if (strcmp(attribs->xattrs[i].name, name) == 0) { + if (flags & XATTR_CREATE) { + TALLOC_FREE(rec); + errno = EEXIST; + return -1; + } + break; + } + } + + if (i == attribs->num_xattrs) { + struct tdb_xattr *tmp; + + if (flags & XATTR_REPLACE) { + TALLOC_FREE(rec); + errno = ENOATTR; + return -1; + } + + tmp = TALLOC_REALLOC_ARRAY( + attribs, attribs->xattrs, struct tdb_xattr, + attribs->num_xattrs + 1); + + if (tmp == NULL) { + DEBUG(0, ("TALLOC_REALLOC_ARRAY failed\n")); + TALLOC_FREE(rec); + errno = ENOMEM; + return -1; + } + + attribs->xattrs = tmp; + attribs->num_xattrs += 1; + } + + attribs->xattrs[i].name = name; + attribs->xattrs[i].value.data = CONST_DISCARD(uint8 *, value); + attribs->xattrs[i].value.length = size; + + status = xattr_tdb_save_attrs(rec, attribs); + + TALLOC_FREE(rec); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("save failed: %s\n", nt_errstr(status))); + return -1; + } + + return 0; +} + +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; + + SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1); + + if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) { + return -1; + } + + id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino); + + return xattr_tdb_setattr(db, &id, name, value, size, flags); +} + +static int xattr_tdb_fsetxattr(struct vfs_handle_struct *handle, + struct files_struct *fsp, + const char *name, const void *value, + size_t size, int flags) +{ + SMB_STRUCT_STAT sbuf; + struct file_id id; + struct db_context *db; + + SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1); + + if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) { + return -1; + } + + id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino); + + return xattr_tdb_setattr(db, &id, name, value, size, flags); +} + +/* + * Worker routine for listxattr and flistxattr + */ + +static ssize_t xattr_tdb_listattr(struct db_context *db_ctx, + const struct file_id *id, char *list, + size_t size) +{ + NTSTATUS status; + struct tdb_xattrs *attribs; + uint32_t i; + size_t len = 0; + + status = xattr_tdb_load_attrs(talloc_tos(), db_ctx, id, &attribs); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n", + nt_errstr(status))); + errno = EINVAL; + return -1; + } + + DEBUG(10, ("xattr_tdb_listattr: Found %d xattrs\n", + attribs->num_xattrs)); + + for (i=0; i<attribs->num_xattrs; i++) { + size_t tmp; + + DEBUG(10, ("xattr_tdb_listattr: xattrs[i].name: %s\n", + attribs->xattrs[i].name)); + + tmp = strlen(attribs->xattrs[i].name); + + /* + * Try to protect against overflow + */ + + if (len + (tmp+1) < len) { + TALLOC_FREE(attribs); + errno = EINVAL; + return -1; + } + + /* + * Take care of the terminating NULL + */ + len += (tmp + 1); + } + + if (len > size) { + TALLOC_FREE(attribs); + errno = ERANGE; + return -1; + } + + len = 0; + + for (i=0; i<attribs->num_xattrs; i++) { + strlcpy(list+len, attribs->xattrs[i].name, + size-len); + len += (strlen(attribs->xattrs[i].name) + 1); + } + + TALLOC_FREE(attribs); + return len; +} + +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; + + SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1); + + if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) { + return -1; + } + + id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino); + + return xattr_tdb_listattr(db, &id, list, size); +} + +static ssize_t xattr_tdb_flistxattr(struct vfs_handle_struct *handle, + struct files_struct *fsp, char *list, + size_t size) +{ + SMB_STRUCT_STAT sbuf; + struct file_id id; + struct db_context *db; + + SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1); + + if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) { + return -1; + } + + id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino); + + return xattr_tdb_listattr(db, &id, list, size); +} + +/* + * Worker routine for removexattr and fremovexattr + */ + +static int xattr_tdb_removeattr(struct db_context *db_ctx, + const struct file_id *id, const char *name) +{ + NTSTATUS status; + struct db_record *rec; + struct tdb_xattrs *attribs; + uint32_t i; + + rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id); + + if (rec == NULL) { + DEBUG(0, ("xattr_tdb_lock_attrs failed\n")); + errno = EINVAL; + return -1; + } + + status = xattr_tdb_pull_attrs(rec, &rec->value, &attribs); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n", + nt_errstr(status))); + TALLOC_FREE(rec); + return -1; + } + + for (i=0; i<attribs->num_xattrs; i++) { + if (strcmp(attribs->xattrs[i].name, name) == 0) { + break; + } + } + + if (i == attribs->num_xattrs) { + TALLOC_FREE(rec); + errno = ENOATTR; + return -1; + } + + attribs->xattrs[i] = + attribs->xattrs[attribs->num_xattrs-1]; + attribs->num_xattrs -= 1; + + if (attribs->num_xattrs == 0) { + rec->delete_rec(rec); + TALLOC_FREE(rec); + return 0; + } + + status = xattr_tdb_save_attrs(rec, attribs); + + TALLOC_FREE(rec); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("save failed: %s\n", nt_errstr(status))); + return -1; + } + + return 0; +} + +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; + + SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1); + + if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) { + return -1; + } + + id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino); + + return xattr_tdb_removeattr(db, &id, name); +} + +static int xattr_tdb_fremovexattr(struct vfs_handle_struct *handle, + struct files_struct *fsp, const char *name) +{ + SMB_STRUCT_STAT sbuf; + struct file_id id; + struct db_context *db; + + SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1); + + if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) { + return -1; + } + + id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino); + + return xattr_tdb_removeattr(db, &id, name); +} + +/* + * Open the tdb file upon VFS_CONNECT + */ + +static bool xattr_tdb_init(int snum, struct db_context **p_db) +{ + struct db_context *db; + const char *dbname; + + dbname = lp_parm_const_string(snum, "xattr", "tdb", + lock_path("xattr.tdb")); + + if (dbname == NULL) { + errno = ENOSYS; + return false; + } + + become_root(); + db = db_open(NULL, dbname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600); + unbecome_root(); + + if (db == NULL) { + errno = ENOTSUP; + return false; + } + + *p_db = db; + return true; +} + +/* + * On unlink we need to delete the tdb record + */ +static int xattr_tdb_unlink(vfs_handle_struct *handle, const char *path) +{ + SMB_STRUCT_STAT sbuf; + struct file_id id; + struct db_context *db; + struct db_record *rec; + int ret; + + SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1); + + if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) { + return -1; + } + + ret = SMB_VFS_NEXT_UNLINK(handle, path); + + if (ret == -1) { + return -1; + } + + id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino); + + rec = xattr_tdb_lock_attrs(talloc_tos(), db, &id); + + /* + * If rec == NULL there's not much we can do about it + */ + + if (rec != NULL) { + rec->delete_rec(rec); + TALLOC_FREE(rec); + } + + return 0; +} + +/* + * On rmdir we need to delete the tdb record + */ +static int xattr_tdb_rmdir(vfs_handle_struct *handle, const char *path) +{ + SMB_STRUCT_STAT sbuf; + struct file_id id; + struct db_context *db; + struct db_record *rec; + int ret; + + SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1); + + if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) { + return -1; + } + + ret = SMB_VFS_NEXT_RMDIR(handle, path); + + if (ret == -1) { + return -1; + } + + id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino); + + rec = xattr_tdb_lock_attrs(talloc_tos(), db, &id); + + /* + * If rec == NULL there's not much we can do about it + */ + + if (rec != NULL) { + rec->delete_rec(rec); + TALLOC_FREE(rec); + } + + return 0; +} + +/* + * Destructor for the VFS private data + */ + +static void close_xattr_db(void **data) +{ + struct db_context **p_db = (struct db_context **)data; + TALLOC_FREE(*p_db); +} + +static int xattr_tdb_connect(vfs_handle_struct *handle, const char *service, + const char *user) +{ + fstring sname; + int res, snum; + struct db_context *db; + + res = SMB_VFS_NEXT_CONNECT(handle, service, user); + if (res < 0) { + return res; + } + + fstrcpy(sname, service); + snum = find_service(sname); + if (snum == -1) { + /* + * Should not happen, but we should not fail just *here*. + */ + return 0; + } + + if (!xattr_tdb_init(snum, &db)) { + DEBUG(5, ("Could not init xattr tdb\n")); + lp_do_parameter(snum, "ea support", "False"); + return 0; + } + + lp_do_parameter(snum, "ea support", "True"); + + SMB_VFS_HANDLE_SET_DATA(handle, db, close_xattr_db, + struct db_context, return -1); + + return 0; +} + +/* VFS operations structure */ + +static const vfs_op_tuple xattr_tdb_ops[] = { + {SMB_VFS_OP(xattr_tdb_getxattr), SMB_VFS_OP_GETXATTR, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(xattr_tdb_fgetxattr), SMB_VFS_OP_FGETXATTR, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(xattr_tdb_setxattr), SMB_VFS_OP_SETXATTR, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(xattr_tdb_fsetxattr), SMB_VFS_OP_FSETXATTR, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(xattr_tdb_listxattr), SMB_VFS_OP_LISTXATTR, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(xattr_tdb_flistxattr), SMB_VFS_OP_FLISTXATTR, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(xattr_tdb_removexattr), SMB_VFS_OP_REMOVEXATTR, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(xattr_tdb_fremovexattr), SMB_VFS_OP_FREMOVEXATTR, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(xattr_tdb_unlink), SMB_VFS_OP_UNLINK, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(xattr_tdb_rmdir), SMB_VFS_OP_RMDIR, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(xattr_tdb_connect), SMB_VFS_OP_CONNECT, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP} +}; + +NTSTATUS vfs_xattr_tdb_init(void); +NTSTATUS vfs_xattr_tdb_init(void) +{ + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "xattr_tdb", + xattr_tdb_ops); +} diff --git a/source3/modules/vfs_zfsacl.c b/source3/modules/vfs_zfsacl.c index 0fe21b2909..ce2e28771f 100644 --- a/source3/modules/vfs_zfsacl.c +++ b/source3/modules/vfs_zfsacl.c @@ -34,8 +34,9 @@ * read the local file's acls and return it in NT form * using the NFSv4 format conversion */ -static NTSTATUS zfs_get_nt_acl(struct files_struct *fsp, uint32 security_info, - struct security_descriptor **ppdesc) +static NTSTATUS zfs_get_nt_acl_common(const char *name, + uint32 security_info, + SMB4ACL_T **ppacl) { int naces, i; ace_t *acebuf; @@ -43,11 +44,13 @@ static NTSTATUS zfs_get_nt_acl(struct files_struct *fsp, uint32 security_info, TALLOC_CTX *mem_ctx; /* read the number of file aces */ - if((naces = acl(fsp->fsp_name, ACE_GETACLCNT, 0, NULL)) == -1) { + if((naces = acl(name, ACE_GETACLCNT, 0, NULL)) == -1) { if(errno == ENOSYS) { - DEBUG(9, ("acl(ACE_GETACLCNT, %s): Operation is not supported on the filesystem where the file reside")); + DEBUG(9, ("acl(ACE_GETACLCNT, %s): Operation is not " + "supported on the filesystem where the file " + "reside", name)); } else { - DEBUG(9, ("acl(ACE_GETACLCNT, %s): %s ", fsp->fsp_name, + DEBUG(9, ("acl(ACE_GETACLCNT, %s): %s ", name, strerror(errno))); } return map_nt_error_from_unix(errno); @@ -59,8 +62,8 @@ static NTSTATUS zfs_get_nt_acl(struct files_struct *fsp, uint32 security_info, return NT_STATUS_NO_MEMORY; } /* read the aces into the field */ - if(acl(fsp->fsp_name, ACE_GETACL, naces, acebuf) < 0) { - DEBUG(9, ("acl(ACE_GETACL, %s): %s ", fsp->fsp_name, + if(acl(name, ACE_GETACL, naces, acebuf) < 0) { + DEBUG(9, ("acl(ACE_GETACL, %s): %s ", name, strerror(errno))); return map_nt_error_from_unix(errno); } @@ -92,7 +95,8 @@ static NTSTATUS zfs_get_nt_acl(struct files_struct *fsp, uint32 security_info, return NT_STATUS_NO_MEMORY; } - return smb_get_nt_acl_nfs4(fsp, security_info, ppdesc, pacl); + *ppacl = pacl; + return NT_STATUS_OK; } /* call-back function processing the NT acl -> ZFS acl using NFSv4 conv. */ @@ -143,7 +147,9 @@ static bool zfs_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl) /* store acl */ if(acl(fsp->fsp_name, ACE_SETACL, naces, acebuf)) { if(errno == ENOSYS) { - DEBUG(9, ("acl(ACE_SETACL, %s): Operation is not supported on the filesystem where the file reside")); + DEBUG(9, ("acl(ACE_SETACL, %s): Operation is not " + "supported on the filesystem where the file " + "reside", fsp->fsp_name)); } else { DEBUG(9, ("acl(ACE_SETACL, %s): %s ", fsp->fsp_name, strerror(errno))); @@ -168,23 +174,39 @@ static NTSTATUS zfs_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp, static NTSTATUS zfsacl_fget_nt_acl(struct vfs_handle_struct *handle, struct files_struct *fsp, - int fd, uint32 security_info, + uint32 security_info, struct security_descriptor **ppdesc) { - return zfs_get_nt_acl(fsp, security_info, ppdesc); + SMB4ACL_T *pacl; + NTSTATUS status; + + status = zfs_get_nt_acl_common(fsp->fsp_name, security_info, &pacl); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + return smb_fget_nt_acl_nfs4(fsp, security_info, ppdesc, pacl); } static NTSTATUS zfsacl_get_nt_acl(struct vfs_handle_struct *handle, - struct files_struct *fsp, const char *name, uint32 security_info, struct security_descriptor **ppdesc) { - return zfs_get_nt_acl(fsp, security_info, ppdesc); + SMB4ACL_T *pacl; + NTSTATUS status; + + status = zfs_get_nt_acl_common(name, security_info, &pacl); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + return smb_get_nt_acl_nfs4(handle->conn, name, security_info, ppdesc, + pacl); } static NTSTATUS zfsacl_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, - int fd, uint32 security_info_sent, + uint32 security_info_sent, SEC_DESC *psd) { return zfs_set_nt_acl(handle, fsp, security_info_sent, psd); @@ -200,7 +222,7 @@ static NTSTATUS zfsacl_set_nt_acl(vfs_handle_struct *handle, /* VFS operations structure */ -static vfs_op_tuple zfsacl_ops[] = { +static vfs_op_tuple zfsacl_ops[] = { {SMB_VFS_OP(zfsacl_fget_nt_acl), SMB_VFS_OP_FGET_NT_ACL, SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(zfsacl_get_nt_acl), SMB_VFS_OP_GET_NT_ACL, |