summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerald Carter <jerry@samba.org>2006-07-19 19:20:28 +0000
committerGerald Carter <jerry@samba.org>2006-07-19 19:20:28 +0000
commitcb10e23454954118034c133a30849394da73752d (patch)
tree796e8b041848b65f1d9b73df31daa370e4a65117
parentb4bb14b5950debe92edfb9cea233833cd8d768b6 (diff)
downloadsamba-cb10e23454954118034c133a30849394da73752d.tar.gz
samba-cb10e23454954118034c133a30849394da73752d.tar.xz
samba-cb10e23454954118034c133a30849394da73752d.zip
r17143: svn merge -r17091:17138 ../SAMBA_3_0_23/
-rw-r--r--source/configure.in14
-rw-r--r--source/libsmb/namequery.c20
-rw-r--r--source/nsswitch/pam_winbind.c4
-rw-r--r--source/nsswitch/winbindd_cache.c6
-rw-r--r--source/nsswitch/winbindd_nss.h76
-rw-r--r--source/nsswitch/winbindd_util.c4
-rw-r--r--source/nsswitch/wins.c1
-rw-r--r--source/rpc_parse/parse_lsa.c3
-rw-r--r--source/sam/idmap_ad.c21
-rw-r--r--source/smbd/open.c188
-rw-r--r--source/smbd/posix_acls.c188
11 files changed, 363 insertions, 162 deletions
diff --git a/source/configure.in b/source/configure.in
index d285647df37..6db439c0d35 100644
--- a/source/configure.in
+++ b/source/configure.in
@@ -4752,6 +4752,20 @@ if test "x$with_spinlocks" = "xyes"; then
fi
#################################################
+# check for cluster extensions
+
+AC_MSG_CHECKING(whether to include cluster support)
+AC_ARG_WITH(cluster-support,
+[ --with-cluster-support Enable cluster extensions (default=no)])
+if test "x$with_cluster_support" = "xyes"; then
+ AC_DEFINE(CLUSTER_SUPPORT,1,[Whether to enable cluster extensions])
+ AC_MSG_RESULT(yes)
+else
+ AC_MSG_RESULT(no)
+fi
+
+
+#################################################
# check for ACL support
AC_MSG_CHECKING(whether to support ACLs)
diff --git a/source/libsmb/namequery.c b/source/libsmb/namequery.c
index 0172ab9514e..f6dbe3c5483 100644
--- a/source/libsmb/namequery.c
+++ b/source/libsmb/namequery.c
@@ -1051,16 +1051,18 @@ static BOOL resolve_ads(const char *name, int name_type,
return False;
}
- i = 0;
- while ( i < numdcs ) {
+ *return_count = 0;
+
+ for (i=0;i<numdcs;i++) {
+ struct ip_service *r = &(*return_iplist)[*return_count];
/* use the IP address from the SRV structure if we have one */
if ( is_zero_ip( dcs[i].ip ) )
- (*return_iplist)[i].ip = *interpret_addr2(dcs[i].hostname);
+ r->ip = *interpret_addr2(dcs[i].hostname);
else
- (*return_iplist)[i].ip = dcs[i].ip;
+ r->ip = dcs[i].ip;
- (*return_iplist)[i].port = dcs[i].port;
+ r->port = dcs[i].port;
/* make sure it is a valid IP. I considered checking the negative
connection cache, but this is the wrong place for it. Maybe only
@@ -1069,15 +1071,11 @@ static BOOL resolve_ads(const char *name, int name_type,
The standard reason for falling back to netbios lookups is that
our DNS server doesn't know anything about the DC's -- jerry */
- if ( is_zero_ip((*return_iplist)[i].ip) )
- continue;
-
- i++;
+ if ( ! is_zero_ip(r->ip) )
+ (*return_count)++;
}
TALLOC_FREE( dcs );
-
- *return_count = i;
return True;
}
diff --git a/source/nsswitch/pam_winbind.c b/source/nsswitch/pam_winbind.c
index 2264c5b8bd1..bbb27f21c9e 100644
--- a/source/nsswitch/pam_winbind.c
+++ b/source/nsswitch/pam_winbind.c
@@ -750,8 +750,8 @@ static int _winbind_read_password(pam_handle_t * pamh,
}
}
} else {
- _pam_log(LOG_NOTICE
- ,"could not recover authentication token");
+ _pam_log(LOG_NOTICE, "could not recover authentication token");
+ retval = PAM_AUTHTOK_RECOVER_ERR;
}
}
diff --git a/source/nsswitch/winbindd_cache.c b/source/nsswitch/winbindd_cache.c
index 5cbaa778052..b267a3f7705 100644
--- a/source/nsswitch/winbindd_cache.c
+++ b/source/nsswitch/winbindd_cache.c
@@ -1891,7 +1891,8 @@ static BOOL init_wcache(void)
/* when working offline we must not clear the cache on restart */
wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
- TDB_DEFAULT /*TDB_CLEAR_IF_FIRST*/, O_RDWR|O_CREAT, 0600);
+ lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
+ O_RDWR|O_CREAT, 0600);
if (wcache->tdb == NULL) {
DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
@@ -2133,7 +2134,8 @@ void wcache_flush_cache(void)
/* when working offline we must not clear the cache on restart */
wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
- TDB_DEFAULT /* TDB_CLEAR_IF_FIRST */, O_RDWR|O_CREAT, 0600);
+ lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
+ O_RDWR|O_CREAT, 0600);
if (!wcache->tdb) {
DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
diff --git a/source/nsswitch/winbindd_nss.h b/source/nsswitch/winbindd_nss.h
index 2afefcc12ca..e0453e81164 100644
--- a/source/nsswitch/winbindd_nss.h
+++ b/source/nsswitch/winbindd_nss.h
@@ -4,6 +4,7 @@
Winbind daemon for ntdom nss module
Copyright (C) Tim Potter 2000
+ Copyright (C) Gerald Carter 2006
You are free to use this interface definition in any way you see
fit, including without restriction, using this header in your own
@@ -36,6 +37,17 @@
#define WINBIND_INTERFACE_VERSION 14
+/* Have to deal with time_t being 4 or 8 bytes due to structure alignment.
+ On a 64bit Linux box, we have to support a constant structure size
+ between /lib/libnss_winbind.so.2 and /li64/libnss_winbind.so.2.
+ The easiest way to do this is to always use 8byte values for time_t. */
+
+#if defined(uint64)
+# define SMB_TIME_T uint64
+#else
+# define SMB_TIME_t time_t
+#endif
+
/* Socket commands */
enum winbindd_cmd {
@@ -184,6 +196,14 @@ typedef struct winbindd_gr {
/* Winbind request structure */
+/*******************************************************************************
+ * This structure MUST be the same size in the 32bit and 64bit builds
+ * for compatibility between /lib64/libnss_winbind.so and /lib/libnss_winbind.so
+ *
+ * DO NOT CHANGE THIS STRUCTURE WITHOUT TESTING THE 32BIT NSS LIB AGAINST
+ * A 64BIT WINBINDD --jerry
+ ******************************************************************************/
+
struct winbindd_request {
uint32 length;
enum winbindd_cmd cmd; /* Winbindd command to execute */
@@ -213,9 +233,9 @@ struct winbindd_request {
fstring user;
fstring domain;
fstring lm_resp;
- uint16 lm_resp_len;
+ uint32 lm_resp_len;
fstring nt_resp;
- uint16 nt_resp_len;
+ uint32 nt_resp_len;
fstring workstation;
fstring require_membership_of_sid;
} auth_crap;
@@ -255,11 +275,15 @@ struct winbindd_request {
fstring sid;
} dual_idmapset;
BOOL list_all_domains;
+
+ /* padding -- needed to fix alignment between 32bit and 64bit libs.
+ The size if the sizeof the union without the padding aligned on
+ an 8 byte boundary. --jerry */
+
+ char padding[1560];
} data;
union {
-#if defined(uint64)
- uint64 z;
-#endif
+ SMB_TIME_T padding;
char *data;
} extra_data;
uint32 extra_len;
@@ -276,6 +300,14 @@ enum winbindd_result {
/* Winbind response structure */
+/*******************************************************************************
+ * This structure MUST be the same size in the 32bit and 64bit builds
+ * for compatibility between /lib64/libnss_winbind.so and /lib/libnss_winbind.so
+ *
+ * DO NOT CHANGE THIS STRUCTURE WITHOUT TESTING THE 32BIT NSS LIB AGAINST
+ * A 64BIT WINBINDD --jerry
+ ******************************************************************************/
+
struct winbindd_response {
/* Header information */
@@ -326,30 +358,32 @@ struct winbindd_response {
char user_session_key[16];
char first_8_lm_hash[8];
fstring krb5ccname;
+ uint32 reject_reason;
+ uint32 padding;
struct policy_settings {
- uint16 min_length_password;
- uint16 password_history;
+ uint32 min_length_password;
+ uint32 password_history;
uint32 password_properties;
- time_t expire;
- time_t min_passwordage;
+ uint32 padding;
+ SMB_TIME_T expire;
+ SMB_TIME_T min_passwordage;
} policy;
- uint32 reject_reason;
struct info3_text {
- time_t logon_time;
- time_t logoff_time;
- time_t kickoff_time;
- time_t pass_last_set_time;
- time_t pass_can_change_time;
- time_t pass_must_change_time;
- uint16 logon_count;
- uint16 bad_pw_count;
+ SMB_TIME_T logon_time;
+ SMB_TIME_T logoff_time;
+ SMB_TIME_T kickoff_time;
+ SMB_TIME_T pass_last_set_time;
+ SMB_TIME_T pass_can_change_time;
+ SMB_TIME_T pass_must_change_time;
+ uint32 logon_count;
+ uint32 bad_pw_count;
uint32 user_rid;
uint32 group_rid;
- fstring dom_sid;
uint32 num_groups;
uint32 user_flgs;
uint32 acct_flags;
uint32 num_other_sids;
+ fstring dom_sid;
fstring user_name;
fstring full_name;
fstring logon_script;
@@ -381,9 +415,7 @@ struct winbindd_response {
/* Variable length return data */
union {
-#if defined(uint64)
- uint64 z;
-#endif
+ SMB_TIME_T padding;
void *data;
} extra_data;
};
diff --git a/source/nsswitch/winbindd_util.c b/source/nsswitch/winbindd_util.c
index d974ad8c56d..67b94817adb 100644
--- a/source/nsswitch/winbindd_util.c
+++ b/source/nsswitch/winbindd_util.c
@@ -1211,13 +1211,13 @@ void winbindd_flush_nscd_cache(void)
int ret = nscd_flush_cache("passwd");
if (ret) {
DEBUG(5,("failed to flush nscd cache for 'passwd' service: %s\n",
- strerror(ret)));
+ strerror(errno)));
}
ret = nscd_flush_cache("group");
if (ret) {
DEBUG(5,("failed to flush nscd cache for 'group' service: %s\n",
- strerror(ret)));
+ strerror(errno)));
}
#else
return;
diff --git a/source/nsswitch/wins.c b/source/nsswitch/wins.c
index f871a53982e..2cc7edb4c7b 100644
--- a/source/nsswitch/wins.c
+++ b/source/nsswitch/wins.c
@@ -80,6 +80,7 @@ static void nss_wins_init(void)
TimeInit();
setup_logging("nss_wins",False);
+ load_case_tables();
lp_load(dyn_CONFIGFILE,True,False,False,True);
load_interfaces();
}
diff --git a/source/rpc_parse/parse_lsa.c b/source/rpc_parse/parse_lsa.c
index ae4cff53e4b..0b138aba1b4 100644
--- a/source/rpc_parse/parse_lsa.c
+++ b/source/rpc_parse/parse_lsa.c
@@ -986,6 +986,9 @@ static BOOL lsa_io_query_info_ctr(const char *desc, prs_struct *ps, int depth, L
if(!prs_uint16("info_class", ps, depth, &ctr->info_class))
return False;
+ if(!prs_align(ps))
+ return False;
+
switch (ctr->info_class) {
case 1:
if(!lsa_io_dom_query_1("", &ctr->info.id1, ps, depth))
diff --git a/source/sam/idmap_ad.c b/source/sam/idmap_ad.c
index 5edfad487d7..2f93dd083bc 100644
--- a/source/sam/idmap_ad.c
+++ b/source/sam/idmap_ad.c
@@ -35,7 +35,6 @@
NTSTATUS init_module(void);
static ADS_STRUCT *ad_idmap_ads = NULL;
-static char *ad_idmap_uri = NULL;
static char *attr_uidnumber = NULL;
static char *attr_gidnumber = NULL;
@@ -139,17 +138,13 @@ static ADS_STRUCT *ad_idmap_cached_connection(void)
return ads;
}
-static NTSTATUS ad_idmap_init(char *uri)
+/* no op */
+static NTSTATUS ad_idmap_init(const char *uri)
{
- ad_idmap_uri = SMB_STRDUP(uri);
- if (ad_idmap_uri == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
-
return NT_STATUS_OK;
}
-static NTSTATUS ad_idmap_get_sid_from_id(DOM_SID *sid, unid_t unid, int id_type)
+static NTSTATUS ad_idmap_get_sid_from_id(DOM_SID *sid, unid_t unid, enum idmap_type id_type, int flags)
{
ADS_STATUS rc;
NTSTATUS status = NT_STATUS_NONE_MAPPED;
@@ -171,7 +166,7 @@ static NTSTATUS ad_idmap_get_sid_from_id(DOM_SID *sid, unid_t unid, int id_type)
return NT_STATUS_NOT_SUPPORTED;
}
- switch (id_type & ID_TYPEMASK) {
+ switch (id_type) {
case ID_USERID:
if (asprintf(&expr, "(&(|(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d))(%s=%d))",
ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
@@ -231,7 +226,7 @@ done:
return status;
}
-static NTSTATUS ad_idmap_get_id_from_sid(unid_t *unid, int *id_type, const DOM_SID *sid)
+static NTSTATUS ad_idmap_get_id_from_sid(unid_t *unid, enum idmap_type *id_type, const DOM_SID *sid, int flags)
{
ADS_STATUS rc;
NTSTATUS status = NT_STATUS_NONE_MAPPED;
@@ -331,7 +326,7 @@ done:
}
-static NTSTATUS ad_idmap_set_mapping(const DOM_SID *sid, unid_t id, int id_type)
+static NTSTATUS ad_idmap_set_mapping(const DOM_SID *sid, unid_t id, enum idmap_type id_type)
{
/* Not supported, and probably won't be... */
/* (It's not particularly feasible with a single-master model.) */
@@ -356,7 +351,7 @@ static NTSTATUS ad_idmap_close(void)
return NT_STATUS_OK;
}
-static NTSTATUS ad_idmap_allocate_id(unid_t *id, int id_type)
+static NTSTATUS ad_idmap_allocate_id(unid_t *id, enum idmap_type id_type)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
@@ -378,7 +373,7 @@ static struct idmap_methods ad_methods = {
/* support for new authentication subsystem */
-NTSTATUS init_module(void)
+NTSTATUS idmap_ad_init(void)
{
return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ad", &ad_methods);
}
diff --git a/source/smbd/open.c b/source/smbd/open.c
index 832a8df7559..94441c5df9b 100644
--- a/source/smbd/open.c
+++ b/source/smbd/open.c
@@ -240,7 +240,7 @@ static BOOL open_file(files_struct *fsp,
}
if ((access_mask & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) ||
- (local_flags & O_CREAT) ||
+ (!file_existed && (local_flags & O_CREAT)) ||
((local_flags & O_TRUNC) == O_TRUNC) ) {
/*
@@ -619,8 +619,11 @@ static BOOL delay_for_oplocks(struct share_mode_lock *lck,
BOOL delay_it = False;
BOOL have_level2 = False;
- if ((oplock_request & INTERNAL_OPEN_ONLY) || is_stat_open(fsp->access_mask)) {
+ if (oplock_request & INTERNAL_OPEN_ONLY) {
fsp->oplock_type = NO_OPLOCK;
+ }
+
+ if ((oplock_request & INTERNAL_OPEN_ONLY) || is_stat_open(fsp->access_mask)) {
return False;
}
@@ -1403,6 +1406,8 @@ files_struct *open_file_ntcreate(connection_struct *conn,
}
if (!NT_STATUS_IS_OK(status)) {
+ uint32 can_access_mask;
+ BOOL can_access = True;
SMB_ASSERT(NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION));
@@ -1433,31 +1438,22 @@ files_struct *open_file_ntcreate(connection_struct *conn,
* MS-Access. If a file open will fail due to share
* permissions and also for security (access) reasons,
* we need to return the access failed error, not the
- * share error. This means we must attempt to open the
- * file anyway in order to get the UNIX access error -
- * even if we're going to fail the open for share
- * reasons. This is bad, as we're burning another fd
- * if there are existing locks but there's nothing
- * else we can do. We also ensure we're not going to
- * create or tuncate the file as we only want an
- * access decision at this stage. JRA.
+ * share error. We can't open the file due to kernel
+ * oplock deadlock (it's possible we failed above on
+ * the open_mode_check()) so use a userspace check.
*/
- errno = 0;
- fsp_open = open_file(fsp,conn,fname,psbuf,
- flags|(flags2&~(O_TRUNC|O_CREAT)),
- unx_mode,access_mask);
-
- DEBUG(4,("open_file_ntcreate : share_mode deny - "
- "calling open_file with flags=0x%X "
- "flags2=0x%X mode=0%o returned %d\n",
- flags, (flags2&~(O_TRUNC|O_CREAT)),
- (unsigned int)unx_mode, (int)fsp_open ));
-
- if (!fsp_open && errno) {
- /* Default error. */
- set_saved_ntstatus(NT_STATUS_ACCESS_DENIED);
+
+ if (flags & O_RDWR) {
+ can_access_mask = FILE_READ_DATA|FILE_WRITE_DATA;
+ } else {
+ can_access_mask = FILE_READ_DATA;
}
+ if (((flags & O_RDWR) && !CAN_WRITE(conn)) ||
+ !can_access_file(conn,fname,psbuf,can_access_mask)) {
+ can_access = False;
+ }
+
/*
* If we're returning a share violation, ensure we
* cope with the braindead 1 second delay.
@@ -1502,8 +1498,9 @@ files_struct *open_file_ntcreate(connection_struct *conn,
}
TALLOC_FREE(lck);
- if (fsp_open) {
- fd_close(conn, fsp);
+ if (!can_access) {
+ set_saved_ntstatus(NT_STATUS_ACCESS_DENIED);
+ } else {
/*
* We have detected a sharing violation here
* so return the correct error code
@@ -1535,6 +1532,14 @@ files_struct *open_file_ntcreate(connection_struct *conn,
(unsigned int)flags, (unsigned int)flags2,
(unsigned int)unx_mode));
+ /* Drop the lock before doing any real file access. Allows kernel
+ oplock breaks to be processed. Handle any races after the open
+ call when we re-acquire the lock. */
+
+ if (lck) {
+ TALLOC_FREE(lck);
+ }
+
/*
* open_file strips any O_TRUNC flags itself.
*/
@@ -1543,79 +1548,103 @@ files_struct *open_file_ntcreate(connection_struct *conn,
access_mask);
if (!fsp_open) {
- if (lck != NULL) {
- TALLOC_FREE(lck);
- }
file_free(fsp);
return NULL;
}
- if (!file_existed) {
+ /*
+ * Deal with the race condition where two smbd's detect the
+ * file doesn't exist and do the create at the same time. One
+ * of them will win and set a share mode, the other (ie. this
+ * one) should check if the requested share mode for this
+ * create is allowed.
+ */
- /*
- * Deal with the race condition where two smbd's detect the
- * file doesn't exist and do the create at the same time. One
- * of them will win and set a share mode, the other (ie. this
- * one) should check if the requested share mode for this
- * create is allowed.
- */
+ /*
+ * Now the file exists and fsp is successfully opened,
+ * fsp->dev and fsp->inode are valid and should replace the
+ * dev=0,inode=0 from a non existent file. Spotted by
+ * Nadav Danieli <nadavd@exanet.com>. JRA.
+ */
- /*
- * Now the file exists and fsp is successfully opened,
- * fsp->dev and fsp->inode are valid and should replace the
- * dev=0,inode=0 from a non existent file. Spotted by
- * Nadav Danieli <nadavd@exanet.com>. JRA.
- */
+ dev = fsp->dev;
+ inode = fsp->inode;
- dev = fsp->dev;
- inode = fsp->inode;
+ lck = get_share_mode_lock(NULL, dev, inode,
+ conn->connectpath,
+ fname);
- lck = get_share_mode_lock(NULL, dev, inode,
- conn->connectpath,
- fname);
+ if (lck == NULL) {
+ DEBUG(0, ("open_file_ntcreate: Could not get share mode lock for %s\n", fname));
+ fd_close(conn, fsp);
+ file_free(fsp);
+ set_saved_ntstatus(NT_STATUS_SHARING_VIOLATION);
+ return NULL;
+ }
- if (lck == NULL) {
- DEBUG(0, ("open_file_ntcreate: Could not get share mode lock for %s\n", fname));
+ /*
+ * The share entry is again *locked*.....
+ */
+
+ /* First pass - send break only on batch oplocks. */
+ if (delay_for_oplocks(lck, fsp, 1, oplock_request)) {
+ schedule_defer_open(lck, request_time);
+ fd_close(conn, fsp);
+ file_free(fsp);
+ TALLOC_FREE(lck);
+ set_saved_ntstatus(NT_STATUS_SHARING_VIOLATION);
+ return NULL;
+ }
+
+ status = open_mode_check(conn, fname, lck,
+ access_mask, share_access,
+ create_options, &file_existed);
+
+ if (NT_STATUS_IS_OK(status)) {
+ /* We might be going to allow this open. Check oplock status again. */
+ /* Second pass - send break for both batch or exclusive oplocks. */
+ if (delay_for_oplocks(lck, fsp, 2, oplock_request)) {
+ schedule_defer_open(lck, request_time);
fd_close(conn, fsp);
file_free(fsp);
+ TALLOC_FREE(lck);
set_saved_ntstatus(NT_STATUS_SHARING_VIOLATION);
return NULL;
}
+ }
- status = open_mode_check(conn, fname, lck,
- access_mask, share_access,
- create_options, &file_existed);
-
- if (!NT_STATUS_IS_OK(status)) {
- struct deferred_open_record state;
+ if (NT_STATUS_EQUAL(status, NT_STATUS_DELETE_PENDING)) {
+ /* DELETE_PENDING is not deferred for a second */
+ fd_close(conn, fsp);
+ file_free(fsp);
+ TALLOC_FREE(lck);
+ set_saved_ntstatus(status);
+ return NULL;
+ }
- fd_close(conn, fsp);
- file_free(fsp);
+ if (!NT_STATUS_IS_OK(status)) {
+ struct deferred_open_record state;
- state.delayed_for_oplocks = False;
- state.dev = dev;
- state.inode = inode;
+ fd_close(conn, fsp);
+ file_free(fsp);
- /* Do it all over again immediately. In the second
- * round we will find that the file existed and handle
- * the DELETE_PENDING and FCB cases correctly. No need
- * to duplicate the code here. Essentially this is a
- * "goto top of this function", but don't tell
- * anybody... */
+ state.delayed_for_oplocks = False;
+ state.dev = dev;
+ state.inode = inode;
- defer_open(lck, request_time, timeval_zero(),
- &state);
- TALLOC_FREE(lck);
- return NULL;
- }
+ /* Do it all over again immediately. In the second
+ * round we will find that the file existed and handle
+ * the DELETE_PENDING and FCB cases correctly. No need
+ * to duplicate the code here. Essentially this is a
+ * "goto top of this function", but don't tell
+ * anybody... */
- /*
- * We exit this block with the share entry *locked*.....
- */
+ defer_open(lck, request_time, timeval_zero(),
+ &state);
+ TALLOC_FREE(lck);
+ return NULL;
}
- SMB_ASSERT(lck != NULL);
-
/* note that we ignore failure for the following. It is
basically a hack for NFS, and NFS will never set one of
these only read them. Nobody but Samba can ever set a deny
@@ -1655,6 +1684,11 @@ files_struct *open_file_ntcreate(connection_struct *conn,
fsp->access_mask = access_mask;
if (file_existed) {
+ /* stat opens on existing files don't get oplocks. */
+ if (is_stat_open(fsp->access_mask)) {
+ fsp->oplock_type = NO_OPLOCK;
+ }
+
if (!(flags2 & O_TRUNC)) {
info = FILE_WAS_OPENED;
} else {
diff --git a/source/smbd/posix_acls.c b/source/smbd/posix_acls.c
index 6e403dba92a..e3614a32d5d 100644
--- a/source/smbd/posix_acls.c
+++ b/source/smbd/posix_acls.c
@@ -3912,7 +3912,7 @@ BOOL set_unix_posix_acl(connection_struct *conn, files_struct *fsp, const char *
Return -1 if no match, 0 if match and denied, 1 if match and allowed.
****************************************************************************/
-static int check_posix_acl_group_write(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf)
+static int check_posix_acl_group_access(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf, uint32 access_mask)
{
SMB_ACL_T posix_acl = NULL;
int entry_id = SMB_ACL_FIRST_ENTRY;
@@ -3923,17 +3923,21 @@ static int check_posix_acl_group_write(connection_struct *conn, const char *fnam
int ret = -1;
gid_t cu_gid;
+ DEBUG(10,("check_posix_acl_group_access: requesting 0x%x on file %s\n",
+ (unsigned int)access_mask, fname ));
+
if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS)) == NULL) {
goto check_stat;
}
- /* First ensure the group mask allows group read. */
+ /* First ensure the group mask allows group access. */
/* Also check any user entries (these take preference over group). */
while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
SMB_ACL_TAG_T tagtype;
SMB_ACL_PERMSET_T permset;
int have_write = -1;
+ int have_read = -1;
/* get_next... */
if (entry_id == SMB_ACL_FIRST_ENTRY)
@@ -3947,6 +3951,11 @@ static int check_posix_acl_group_write(connection_struct *conn, const char *fnam
goto check_stat;
}
+ have_read = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ);
+ if (have_read == -1) {
+ goto check_stat;
+ }
+
have_write = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE);
if (have_write == -1) {
goto check_stat;
@@ -3957,16 +3966,36 @@ static int check_posix_acl_group_write(connection_struct *conn, const char *fnam
* canonicalize to 0 or 1.
*/
have_write = (have_write ? 1 : 0);
+ have_read = (have_read ? 1 : 0);
switch(tagtype) {
case SMB_ACL_MASK:
seen_mask = True;
- if (!have_write) {
- /* We don't have any group or explicit user write permission. */
- ret = -1; /* Allow caller to check "other" permissions. */
- DEBUG(10,("check_posix_acl_group_write: file %s \
-refusing write due to mask.\n", fname));
- goto done;
+ switch (access_mask) {
+ case FILE_READ_DATA:
+ if (!have_read) {
+ ret = -1;
+ DEBUG(10,("check_posix_acl_group_access: file %s "
+ "refusing read due to mask.\n", fname));
+ goto done;
+ }
+ break;
+ case FILE_WRITE_DATA:
+ if (!have_write) {
+ ret = -1;
+ DEBUG(10,("check_posix_acl_group_access: file %s "
+ "refusing write due to mask.\n", fname));
+ goto done;
+ }
+ break;
+ default: /* FILE_READ_DATA|FILE_WRITE_DATA */
+ if (!have_write || !have_read) {
+ ret = -1;
+ DEBUG(10,("check_posix_acl_group_access: file %s "
+ "refusing read/write due to mask.\n", fname));
+ goto done;
+ }
+ break;
}
break;
case SMB_ACL_USER:
@@ -3978,9 +4007,21 @@ refusing write due to mask.\n", fname));
}
if (current_user.ut.uid == *puid) {
/* We have a uid match but we must ensure we have seen the acl mask. */
- ret = have_write;
- DEBUG(10,("check_posix_acl_group_write: file %s \
-match on user %u -> %s.\n", fname, (unsigned int)*puid, ret ? "can write" : "cannot write"));
+ switch (access_mask) {
+ case FILE_READ_DATA:
+ ret = have_read;
+ break;
+ case FILE_WRITE_DATA:
+ ret = have_write;
+ break;
+ default: /* FILE_READ_DATA|FILE_WRITE_DATA */
+ ret = (have_write & have_read);
+ break;
+ }
+ DEBUG(10,("check_posix_acl_group_access: file %s "
+ "match on user %u -> %s.\n",
+ fname, (unsigned int)*puid,
+ ret ? "can access" : "cannot access"));
if (seen_mask) {
goto done;
}
@@ -4003,6 +4044,7 @@ match on user %u -> %s.\n", fname, (unsigned int)*puid, ret ? "can write" : "can
SMB_ACL_TAG_T tagtype;
SMB_ACL_PERMSET_T permset;
int have_write = -1;
+ int have_read = -1;
/* get_next... */
if (entry_id == SMB_ACL_FIRST_ENTRY)
@@ -4016,6 +4058,11 @@ match on user %u -> %s.\n", fname, (unsigned int)*puid, ret ? "can write" : "can
goto check_stat;
}
+ have_read = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ);
+ if (have_read == -1) {
+ goto check_stat;
+ }
+
have_write = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE);
if (have_write == -1) {
goto check_stat;
@@ -4026,6 +4073,7 @@ match on user %u -> %s.\n", fname, (unsigned int)*puid, ret ? "can write" : "can
* canonicalize to 0 or 1.
*/
have_write = (have_write ? 1 : 0);
+ have_read = (have_read ? 1 : 0);
switch(tagtype) {
case SMB_ACL_GROUP:
@@ -4050,13 +4098,25 @@ match on user %u -> %s.\n", fname, (unsigned int)*puid, ret ? "can write" : "can
for (cu_gid = get_current_user_gid_first(&i); cu_gid != (gid_t)-1;
cu_gid = get_current_user_gid_next(&i)) {
if (cu_gid == *pgid) {
- ret = have_write;
- DEBUG(10,("check_posix_acl_group_write: file %s \
-match on group %u -> can write.\n", fname, (unsigned int)cu_gid ));
+ switch (access_mask) {
+ case FILE_READ_DATA:
+ ret = have_read;
+ break;
+ case FILE_WRITE_DATA:
+ ret = have_write;
+ break;
+ default: /* FILE_READ_DATA|FILE_WRITE_DATA */
+ ret = (have_write & have_read);
+ break;
+ }
- /* If we don't have write permission this entry doesn't
+ DEBUG(10,("check_posix_acl_group_access: file %s "
+ "match on group %u -> can access.\n",
+ fname, (unsigned int)cu_gid ));
+
+ /* If we don't have access permission this entry doesn't
terminate the enumeration of the entries. */
- if (have_write) {
+ if (ret) {
goto done;
}
/* But does terminate the group iteration. */
@@ -4073,12 +4133,12 @@ match on group %u -> can write.\n", fname, (unsigned int)cu_gid ));
/* If ret is -1 here we didn't match on the user entry or
supplemental group entries. */
- DEBUG(10,("check_posix_acl_group_write: ret = %d before check_stat:\n", ret));
+ DEBUG(10,("check_posix_acl_group_access: ret = %d before check_stat:\n", ret));
check_stat:
/*
- * We only check the S_IWGRP permissions if we haven't already
+ * We only check the S_I[RW]GRP permissions if we haven't already
* seen an owning group SMB_ACL_GROUP_OBJ ace entry. If there is an
* SMB_ACL_GROUP_OBJ ace entry then the group bits in st_gid are
* the same as the SMB_ACL_MASK bits, not the SMB_ACL_GROUP_OBJ
@@ -4095,16 +4155,33 @@ match on group %u -> can write.\n", fname, (unsigned int)cu_gid ));
for (cu_gid = get_current_user_gid_first(&i); cu_gid != (gid_t)-1;
cu_gid = get_current_user_gid_next(&i)) {
if (cu_gid == psbuf->st_gid) {
- ret = (psbuf->st_mode & S_IWGRP) ? 1 : 0;
- DEBUG(10,("check_posix_acl_group_write: file %s \
-match on owning group %u -> %s.\n", fname, (unsigned int)psbuf->st_gid, ret ? "can write" : "cannot write"));
+ switch (access_mask) {
+ case FILE_READ_DATA:
+ ret = (psbuf->st_mode & S_IRGRP) ? 1 : 0;
+ break;
+ case FILE_WRITE_DATA:
+ ret = (psbuf->st_mode & S_IWGRP) ? 1 : 0;
+ break;
+ default: /* FILE_READ_DATA|FILE_WRITE_DATA */
+ if ((psbuf->st_mode & (S_IWGRP|S_IRGRP)) == (S_IWGRP|S_IRGRP)) {
+ ret = 1;
+ } else {
+ ret = 0;
+ }
+ break;
+ }
+ DEBUG(10,("check_posix_acl_group_access: file %s "
+ "match on owning group %u -> %s.\n",
+ fname, (unsigned int)psbuf->st_gid,
+ ret ? "can access" : "cannot access"));
break;
}
}
if (cu_gid == (gid_t)-1) {
- DEBUG(10,("check_posix_acl_group_write: file %s \
-failed to match on user or group in token (ret = %d).\n", fname, ret ));
+ DEBUG(10,("check_posix_acl_group_access: file %s "
+ "failed to match on user or group in token (ret = %d).\n",
+ fname, ret ));
}
}
@@ -4114,7 +4191,7 @@ failed to match on user or group in token (ret = %d).\n", fname, ret ));
SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
}
- DEBUG(10,("check_posix_acl_group_write: file %s returning (ret = %d).\n", fname, ret ));
+ DEBUG(10,("check_posix_acl_group_access: file %s returning (ret = %d).\n", fname, ret ));
return ret;
}
@@ -4170,7 +4247,7 @@ BOOL can_delete_file_in_directory(connection_struct *conn, const char *fname)
#endif
/* Check group or explicit user acl entry write access. */
- ret = check_posix_acl_group_write(conn, dname, &sbuf);
+ ret = check_posix_acl_group_access(conn, dname, &sbuf, FILE_WRITE_DATA);
if (ret == 0 || ret == 1) {
return ret ? True : False;
}
@@ -4180,15 +4257,23 @@ BOOL can_delete_file_in_directory(connection_struct *conn, const char *fname)
}
/****************************************************************************
- Actually emulate the in-kernel access checking for write access. We need
+ Actually emulate the in-kernel access checking for read/write access. We need
this to successfully check for ability to write for dos filetimes.
Note this doesn't take into account share write permissions.
****************************************************************************/
-BOOL can_write_to_file(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf)
+BOOL can_access_file(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf, uint32 access_mask)
{
int ret;
+ if (!(access_mask & (FILE_READ_DATA|FILE_WRITE_DATA))) {
+ return False;
+ }
+ access_mask &= (FILE_READ_DATA|FILE_WRITE_DATA);
+
+ DEBUG(10,("can_access_file: requesting 0x%x on file %s\n",
+ (unsigned int)access_mask, fname ));
+
if (current_user.ut.uid == 0 || conn->admin_user) {
/* I'm sorry sir, I didn't know you were root... */
return True;
@@ -4201,19 +4286,56 @@ BOOL can_write_to_file(connection_struct *conn, const char *fname, SMB_STRUCT_ST
}
}
- /* Check primary owner write access. */
+ /* Check primary owner access. */
if (current_user.ut.uid == psbuf->st_uid) {
- return (psbuf->st_mode & S_IWUSR) ? True : False;
+ switch (access_mask) {
+ case FILE_READ_DATA:
+ return (psbuf->st_mode & S_IRUSR) ? True : False;
+
+ case FILE_WRITE_DATA:
+ return (psbuf->st_mode & S_IWUSR) ? True : False;
+
+ default: /* FILE_READ_DATA|FILE_WRITE_DATA */
+
+ if ((psbuf->st_mode & (S_IWUSR|S_IRUSR)) == (S_IWUSR|S_IRUSR)) {
+ return True;
+ } else {
+ return False;
+ }
+ }
}
- /* Check group or explicit user acl entry write access. */
- ret = check_posix_acl_group_write(conn, fname, psbuf);
+ /* Check group or explicit user acl entry access. */
+ ret = check_posix_acl_group_access(conn, fname, psbuf, access_mask);
if (ret == 0 || ret == 1) {
return ret ? True : False;
}
- /* Finally check other write access. */
- return (psbuf->st_mode & S_IWOTH) ? True : False;
+ /* Finally check other access. */
+ switch (access_mask) {
+ case FILE_READ_DATA:
+ return (psbuf->st_mode & S_IROTH) ? True : False;
+
+ case FILE_WRITE_DATA:
+ return (psbuf->st_mode & S_IWOTH) ? True : False;
+
+ default: /* FILE_READ_DATA|FILE_WRITE_DATA */
+
+ if ((psbuf->st_mode & (S_IWOTH|S_IROTH)) == (S_IWOTH|S_IROTH)) {
+ return True;
+ }
+ }
+ return False;
+}
+
+/****************************************************************************
+ Userspace check for write access.
+ Note this doesn't take into account share write permissions.
+****************************************************************************/
+
+BOOL can_write_to_file(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf)
+{
+ return can_access_file(conn, fname, psbuf, FILE_WRITE_DATA);
}
/********************************************************************