From 870ebaeeccd2bde56ec5916f56aecfa41e2e2290 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 20 Dec 2012 11:50:25 -0800 Subject: [PATCH 01/17] Start to tidy-up check_user_ok(). Now we have removed "security=share" we cannot be called with vuid == UID_FIELD_INVALID. Signed-off-by: Jeremy Allison (cherry picked from commit f0450e0d80c2ff56c4834b2f1271a7f84132ca5b) --- source3/smbd/uid.c | 5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-) diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c index 30c7154..2aa9fff 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -90,12 +90,11 @@ static bool check_user_ok(connection_struct *conn, const struct auth_session_info *session_info, int snum) { - bool valid_vuid = (vuid != UID_FIELD_INVALID); unsigned int i; bool readonly_share; bool admin_user; - if (valid_vuid) { + { struct vuid_cache_entry *ent; for (i=0; iinfo->domain_name, NULL, session_info->security_token, lp_admin_users(snum)); - if (valid_vuid) { + { struct vuid_cache_entry *ent = &conn->vuid_cache.array[conn->vuid_cache.next_entry]; -- 1.7.7.3 From eceb5a5adb4efc29d4daf4190295f5710f777950 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 20 Dec 2012 11:51:55 -0800 Subject: [PATCH 02/17] Move the definition of struct vuid_cache_entry *ent outside blocks. Signed-off-by: Jeremy Allison (cherry picked from commit 092c9517acf5a4b11577ef7b5f1d645e5e463f6d) --- source3/smbd/uid.c | 6 ++---- 1 files changed, 2 insertions(+), 4 deletions(-) diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c index 2aa9fff..9361e49 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -93,10 +93,9 @@ static bool check_user_ok(connection_struct *conn, unsigned int i; bool readonly_share; bool admin_user; + struct vuid_cache_entry *ent = NULL; { - struct vuid_cache_entry *ent; - for (i=0; ivuid_cache.array[i]; if (ent->vuid == vuid) { @@ -145,8 +144,7 @@ static bool check_user_ok(connection_struct *conn, NULL, session_info->security_token, lp_admin_users(snum)); { - struct vuid_cache_entry *ent = - &conn->vuid_cache.array[conn->vuid_cache.next_entry]; + ent = &conn->vuid_cache.array[conn->vuid_cache.next_entry]; conn->vuid_cache.next_entry = (conn->vuid_cache.next_entry + 1) % VUID_CACHE_SIZE; -- 1.7.7.3 From 0d3fa3a0bf280d40a3e1d89de5bf7dd246f4f1eb Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 20 Dec 2012 11:52:27 -0800 Subject: [PATCH 03/17] Remove one set of enclosing {} braces, no longer needed. Signed-off-by: Jeremy Allison (cherry picked from commit d64ea67c78a5b09559971ff6953cd67feb2b1ec2) --- source3/smbd/uid.c | 16 +++++++--------- 1 files changed, 7 insertions(+), 9 deletions(-) diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c index 9361e49..9109f05 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -95,15 +95,13 @@ static bool check_user_ok(connection_struct *conn, bool admin_user; struct vuid_cache_entry *ent = NULL; - { - for (i=0; ivuid_cache.array[i]; - if (ent->vuid == vuid) { - free_conn_session_info_if_unused(conn); - conn->session_info = ent->session_info; - conn->read_only = ent->read_only; - return(True); - } + for (i=0; ivuid_cache.array[i]; + if (ent->vuid == vuid) { + free_conn_session_info_if_unused(conn); + conn->session_info = ent->session_info; + conn->read_only = ent->read_only; + return(True); } } -- 1.7.7.3 From 9dce4396cb67af72f8d4d203208f4b4856e58c5a Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 20 Dec 2012 11:53:11 -0800 Subject: [PATCH 04/17] Remove the second set of {} braces, no longer needed. (cherry picked from commit ed0a34d163f777b2a0d4a2b358b7fb1b170d7686) --- source3/smbd/uid.c | 38 ++++++++++++++++++-------------------- 1 files changed, 18 insertions(+), 20 deletions(-) diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c index 9109f05..9fc5d7c 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -141,33 +141,31 @@ static bool check_user_ok(connection_struct *conn, session_info->info->domain_name, NULL, session_info->security_token, lp_admin_users(snum)); - { - ent = &conn->vuid_cache.array[conn->vuid_cache.next_entry]; + ent = &conn->vuid_cache.array[conn->vuid_cache.next_entry]; - conn->vuid_cache.next_entry = - (conn->vuid_cache.next_entry + 1) % VUID_CACHE_SIZE; + conn->vuid_cache.next_entry = + (conn->vuid_cache.next_entry + 1) % VUID_CACHE_SIZE; - TALLOC_FREE(ent->session_info); + TALLOC_FREE(ent->session_info); - /* - * If force_user was set, all session_info's are based on the same - * username-based faked one. - */ - - ent->session_info = copy_session_info( - conn, conn->force_user ? conn->session_info : session_info); + /* + * If force_user was set, all session_info's are based on the same + * username-based faked one. + */ - if (ent->session_info == NULL) { - ent->vuid = UID_FIELD_INVALID; - return false; - } + ent->session_info = copy_session_info( + conn, conn->force_user ? conn->session_info : session_info); - ent->vuid = vuid; - ent->read_only = readonly_share; - free_conn_session_info_if_unused(conn); - conn->session_info = ent->session_info; + if (ent->session_info == NULL) { + ent->vuid = UID_FIELD_INVALID; + return false; } + ent->vuid = vuid; + ent->read_only = readonly_share; + free_conn_session_info_if_unused(conn); + conn->session_info = ent->session_info; + conn->read_only = readonly_share; if (admin_user) { DEBUG(2,("check_user_ok: user %s is an admin user. " -- 1.7.7.3 From 517f24aed3d08b9fde504bc62ee5da26131cef91 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 20 Dec 2012 11:54:07 -0800 Subject: [PATCH 05/17] Remove dead code now vuser can no longer be NULL. Signed-off-by: Jeremy Allison (cherry picked from commit d35ba04e25eb3c396f791ea80c0ebb74543d4005) --- source3/smbd/uid.c | 8 -------- 1 files changed, 0 insertions(+), 8 deletions(-) diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c index 9fc5d7c..298fa83 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -299,14 +299,6 @@ bool change_to_user(connection_struct *conn, uint64_t vuid) } session_info = vuser->session_info; - - if (!conn->force_user && vuser == NULL) { - DEBUG(2,("Invalid vuid used %llu in accessing share %s.\n", - (unsigned long long)vuid, - lp_servicename(talloc_tos(), snum))); - return False; - } - return change_to_user_internal(conn, session_info, vuid); } -- 1.7.7.3 From bfbf2f0389d77b6756259a95709879f90805c9d6 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 20 Dec 2012 11:55:09 -0800 Subject: [PATCH 06/17] Remove unneeded variable "const struct auth_session_info *session_info" Signed-off-by: Jeremy Allison (cherry picked from commit 5a3cda176f5eecd65b289c74132b0126357c5ef0) --- source3/smbd/uid.c | 4 +--- 1 files changed, 1 insertions(+), 3 deletions(-) diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c index 298fa83..9244f29 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -271,7 +271,6 @@ static bool change_to_user_internal(connection_struct *conn, bool change_to_user(connection_struct *conn, uint64_t vuid) { - const struct auth_session_info *session_info = NULL; struct user_struct *vuser; int snum = SNUM(conn); @@ -298,8 +297,7 @@ bool change_to_user(connection_struct *conn, uint64_t vuid) return false; } - session_info = vuser->session_info; - return change_to_user_internal(conn, session_info, vuid); + return change_to_user_internal(conn, vuser->session_info, vuid); } static bool change_to_user_by_session(connection_struct *conn, -- 1.7.7.3 From 2a07ef4c12f0a4e5b22177fd38ac302a08d954b0 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 21 Dec 2012 09:35:31 -0800 Subject: [PATCH 07/17] Remove static from create_share_access_mask(). Signed-off-by: Jeremy Allison (cherry picked from commit 48187220ff47efe70616361fcef1a794aef765b4) --- source3/smbd/proto.h | 1 + source3/smbd/service.c | 2 +- 2 files changed, 2 insertions(+), 1 deletions(-) diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index b48cf44..e004980 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -962,6 +962,7 @@ void smbd_exit_server_cleanly(const char *const reason) _NORETURN_; bool set_conn_connectpath(connection_struct *conn, const char *connectpath); NTSTATUS set_conn_force_user_group(connection_struct *conn, int snum); +void create_share_access_mask(connection_struct *conn, int snum); bool set_current_service(connection_struct *conn, uint16 flags, bool do_chdir); void load_registry_shares(void); int add_home_service(const char *service, const char *username, const char *homedir); diff --git a/source3/smbd/service.c b/source3/smbd/service.c index 2214ac0..828c036 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -515,7 +515,7 @@ NTSTATUS set_conn_force_user_group(connection_struct *conn, int snum) Setup the share access mask for a connection. ****************************************************************************/ -static void create_share_access_mask(connection_struct *conn, int snum) +void create_share_access_mask(connection_struct *conn, int snum) { const struct security_token *token = conn->session_info->security_token; -- 1.7.7.3 From 89534ae50df19dd7dcf0aff5212a172c1a39ff95 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 21 Dec 2012 09:45:03 -0800 Subject: [PATCH 08/17] Fix API for create_share_access_mask(). Return the uint32_t share_access rather than directly changing the conn struct. Signed-off-by: Jeremy Allison (cherry picked from commit 33167c070c085b30569317666a3fca079d970321) --- source3/smbd/proto.h | 2 +- source3/smbd/service.c | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index e004980..97ae1db 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -962,7 +962,7 @@ void smbd_exit_server_cleanly(const char *const reason) _NORETURN_; bool set_conn_connectpath(connection_struct *conn, const char *connectpath); NTSTATUS set_conn_force_user_group(connection_struct *conn, int snum); -void create_share_access_mask(connection_struct *conn, int snum); +uint32_t create_share_access_mask(connection_struct *conn, int snum); bool set_current_service(connection_struct *conn, uint16 flags, bool do_chdir); void load_registry_shares(void); int add_home_service(const char *service, const char *username, const char *homedir); diff --git a/source3/smbd/service.c b/source3/smbd/service.c index 828c036..1cd12a6 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -515,34 +515,37 @@ NTSTATUS set_conn_force_user_group(connection_struct *conn, int snum) Setup the share access mask for a connection. ****************************************************************************/ -void create_share_access_mask(connection_struct *conn, int snum) +uint32_t create_share_access_mask(connection_struct *conn, int snum) { const struct security_token *token = conn->session_info->security_token; + uint32_t share_access = 0; share_access_check(token, lp_servicename(talloc_tos(), snum), MAXIMUM_ALLOWED_ACCESS, - &conn->share_access); + &share_access); if (!CAN_WRITE(conn)) { - conn->share_access &= + share_access &= ~(SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA | SEC_FILE_WRITE_EA | SEC_FILE_WRITE_ATTRIBUTE | SEC_DIR_DELETE_CHILD ); } if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) { - conn->share_access |= SEC_FLAG_SYSTEM_SECURITY; + share_access |= SEC_FLAG_SYSTEM_SECURITY; } if (security_token_has_privilege(token, SEC_PRIV_RESTORE)) { - conn->share_access |= (SEC_RIGHTS_PRIV_RESTORE); + share_access |= (SEC_RIGHTS_PRIV_RESTORE); } if (security_token_has_privilege(token, SEC_PRIV_BACKUP)) { - conn->share_access |= (SEC_RIGHTS_PRIV_BACKUP); + share_access |= (SEC_RIGHTS_PRIV_BACKUP); } if (security_token_has_privilege(token, SEC_PRIV_TAKE_OWNERSHIP)) { - conn->share_access |= (SEC_STD_WRITE_OWNER); + share_access |= (SEC_STD_WRITE_OWNER); } + + return share_access; } /**************************************************************************** @@ -654,7 +657,7 @@ static NTSTATUS make_connection_snum(struct smbd_server_connection *sconn, * */ - create_share_access_mask(conn, snum); + conn->share_access = create_share_access_mask(conn, snum); if ((conn->share_access & FILE_WRITE_DATA) == 0) { if ((conn->share_access & FILE_READ_DATA) == 0) { -- 1.7.7.3 From e07aba7a957710675f15fe6c58918dfdc6fdc94a Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 4 Jan 2013 12:01:17 -0800 Subject: [PATCH 09/17] Change API for create_share_access_mask() to pass in the token. Don't automatically use the one from conn->session_info->security_token. Signed-off-by: Jeremy Allison --- source3/smbd/proto.h | 4 +++- source3/smbd/service.c | 9 ++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index 97ae1db..f0d2c93 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -962,7 +962,9 @@ void smbd_exit_server_cleanly(const char *const reason) _NORETURN_; bool set_conn_connectpath(connection_struct *conn, const char *connectpath); NTSTATUS set_conn_force_user_group(connection_struct *conn, int snum); -uint32_t create_share_access_mask(connection_struct *conn, int snum); +uint32_t create_share_access_mask(connection_struct *conn, + int snum, + const struct security_token *token); bool set_current_service(connection_struct *conn, uint16 flags, bool do_chdir); void load_registry_shares(void); int add_home_service(const char *service, const char *username, const char *homedir); diff --git a/source3/smbd/service.c b/source3/smbd/service.c index 1cd12a6..3e1d87f 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -515,9 +515,10 @@ NTSTATUS set_conn_force_user_group(connection_struct *conn, int snum) Setup the share access mask for a connection. ****************************************************************************/ -uint32_t create_share_access_mask(connection_struct *conn, int snum) +uint32_t create_share_access_mask(connection_struct *conn, + int snum, + const struct security_token *token) { - const struct security_token *token = conn->session_info->security_token; uint32_t share_access = 0; share_access_check(token, @@ -657,7 +658,9 @@ static NTSTATUS make_connection_snum(struct smbd_server_connection *sconn, * */ - conn->share_access = create_share_access_mask(conn, snum); + conn->share_access = create_share_access_mask(conn, + snum, + conn->session_info->security_token); if ((conn->share_access & FILE_WRITE_DATA) == 0) { if ((conn->share_access & FILE_READ_DATA) == 0) { -- 1.7.7.3 From 45469aee72c844b46f7d66a96de58ac43d058ce1 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 4 Jan 2013 15:04:26 -0800 Subject: [PATCH 10/17] Change API for create_share_access_mask() - remove conn struct. Eventually this will be indepentent of conn, just pass in the readonly flag. Signed-off-by: Jeremy Allison --- source3/smbd/proto.h | 4 ++-- source3/smbd/service.c | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index f0d2c93..4fdcd26 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -962,8 +962,8 @@ void smbd_exit_server_cleanly(const char *const reason) _NORETURN_; bool set_conn_connectpath(connection_struct *conn, const char *connectpath); NTSTATUS set_conn_force_user_group(connection_struct *conn, int snum); -uint32_t create_share_access_mask(connection_struct *conn, - int snum, +uint32_t create_share_access_mask(int snum, + bool readonly_share, const struct security_token *token); bool set_current_service(connection_struct *conn, uint16 flags, bool do_chdir); void load_registry_shares(void); diff --git a/source3/smbd/service.c b/source3/smbd/service.c index 3e1d87f..10f4b53 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -515,8 +515,8 @@ NTSTATUS set_conn_force_user_group(connection_struct *conn, int snum) Setup the share access mask for a connection. ****************************************************************************/ -uint32_t create_share_access_mask(connection_struct *conn, - int snum, +uint32_t create_share_access_mask(int snum, + bool readonly_share, const struct security_token *token) { uint32_t share_access = 0; @@ -526,7 +526,7 @@ uint32_t create_share_access_mask(connection_struct *conn, MAXIMUM_ALLOWED_ACCESS, &share_access); - if (!CAN_WRITE(conn)) { + if (readonly_share) { share_access &= ~(SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA | SEC_FILE_WRITE_EA | SEC_FILE_WRITE_ATTRIBUTE | @@ -658,8 +658,8 @@ static NTSTATUS make_connection_snum(struct smbd_server_connection *sconn, * */ - conn->share_access = create_share_access_mask(conn, - snum, + conn->share_access = create_share_access_mask(snum, + !CAN_WRITE(conn), conn->session_info->security_token); if ((conn->share_access & FILE_WRITE_DATA) == 0) { -- 1.7.7.3 From 973be123821018346ed109155f7f0ed7d143ca65 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 4 Jan 2013 15:06:35 -0800 Subject: [PATCH 11/17] Correctly setup the conn->share_access based on the current user token. Also use this to set conn->read_only. Cache the share_access so we only evaluate this once per new user access on this share. Signed-off-by: Jeremy Allison --- source3/smbd/uid.c | 44 ++++++++++++++++++++++++++++++++------------ 1 files changed, 32 insertions(+), 12 deletions(-) diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c index 9244f29..36b79bc 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -79,6 +79,14 @@ static void free_conn_session_info_if_unused(connection_struct *conn) } /******************************************************************* + Static cache for storing per-user share access value. This really + belongs inside the vuid_cache.array struct but we can't change the + VFS ABI for 4.0.x. This is fixed in 4.1.x. JRA. +********************************************************************/ + +static uint32_t vuid_cache_share_access_array[VUID_CACHE_SIZE]; + +/******************************************************************* Check if a username is OK. This sets up conn->session_info with a copy related to this vuser that @@ -94,6 +102,8 @@ static bool check_user_ok(connection_struct *conn, bool readonly_share; bool admin_user; struct vuid_cache_entry *ent = NULL; + uint32_t share_access = 0; + unsigned int share_array_index; for (i=0; ivuid_cache.array[i]; @@ -101,6 +111,7 @@ static bool check_user_ok(connection_struct *conn, free_conn_session_info_if_unused(conn); conn->session_info = ent->session_info; conn->read_only = ent->read_only; + conn->share_access = vuid_cache_share_access_array[i]; return(True); } } @@ -116,11 +127,24 @@ static bool check_user_ok(connection_struct *conn, session_info->security_token, conn); + share_access = create_share_access_mask(snum, + readonly_share, + session_info->security_token); + + if ((share_access & FILE_WRITE_DATA) == 0) { + if ((share_access & FILE_READ_DATA) == 0) { + /* No access, read or write. */ + DEBUG(0,("user %s connection to %s " + "denied due to share security " + "descriptor.\n", + session_info->unix_info->unix_name, + lp_servicename(talloc_tos(), snum))); + return false; + } + } + if (!readonly_share && - !share_access_check(session_info->security_token, - lp_servicename(talloc_tos(), snum), - FILE_WRITE_DATA, - NULL)) { + !(share_access & FILE_WRITE_DATA)) { /* smb.conf allows r/w, but the security descriptor denies * write. Fall back to looking at readonly. */ readonly_share = True; @@ -128,19 +152,12 @@ static bool check_user_ok(connection_struct *conn, "security descriptor\n")); } - if (!share_access_check(session_info->security_token, - lp_servicename(talloc_tos(), snum), - readonly_share ? - FILE_READ_DATA : FILE_WRITE_DATA, - NULL)) { - return False; - } - admin_user = token_contains_name_in_list( session_info->unix_info->unix_name, session_info->info->domain_name, NULL, session_info->security_token, lp_admin_users(snum)); + share_array_index = conn->vuid_cache.next_entry; ent = &conn->vuid_cache.array[conn->vuid_cache.next_entry]; conn->vuid_cache.next_entry = @@ -163,10 +180,13 @@ static bool check_user_ok(connection_struct *conn, ent->vuid = vuid; ent->read_only = readonly_share; + vuid_cache_share_access_array[share_array_index] = share_access; free_conn_session_info_if_unused(conn); conn->session_info = ent->session_info; conn->read_only = readonly_share; + conn->share_access = share_access; + if (admin_user) { DEBUG(2,("check_user_ok: user %s is an admin user. " "Setting uid as %d\n", -- 1.7.7.3 From 04904422545e5fd4abdcc2d52f3d78150a00bed6 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 4 Jan 2013 15:07:50 -0800 Subject: [PATCH 12/17] Add check_user_share_access() This factors out the share security and read_only flag setting code so this can be called from both make_connection_snum() as well as check_user_ok(). Gives a consistent share security check function. Signed-off-by: Jeremy Allison --- source3/smbd/proto.h | 4 +++ source3/smbd/uid.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 0 deletions(-) diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index 4fdcd26..cfaa0b0 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -1082,6 +1082,10 @@ void reply_transs2(struct smb_request *req); /* The following definitions come from smbd/uid.c */ bool change_to_guest(void); +NTSTATUS check_user_share_access(connection_struct *conn, + const struct auth_session_info *session_info, + uint32_t *p_share_access, + bool *p_readonly_share); bool change_to_user(connection_struct *conn, uint64_t vuid); bool change_to_root_user(void); bool smbd_change_to_root_user(void); diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c index 36b79bc..6f5ff6d 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -87,6 +87,62 @@ static void free_conn_session_info_if_unused(connection_struct *conn) static uint32_t vuid_cache_share_access_array[VUID_CACHE_SIZE]; /******************************************************************* + Calculate access mask and if this user can access this share. +********************************************************************/ + +NTSTATUS check_user_share_access(connection_struct *conn, + const struct auth_session_info *session_info, + uint32_t *p_share_access, + bool *p_readonly_share) +{ + int snum = SNUM(conn); + uint32_t share_access = 0; + bool readonly_share = false; + + if (!user_ok_token(session_info->unix_info->unix_name, + session_info->info->domain_name, + session_info->security_token, snum)) { + return NT_STATUS_ACCESS_DENIED; + } + + readonly_share = is_share_read_only_for_token( + session_info->unix_info->unix_name, + session_info->info->domain_name, + session_info->security_token, + conn); + + share_access = create_share_access_mask(snum, + readonly_share, + session_info->security_token); + + if ((share_access & FILE_WRITE_DATA) == 0) { + if ((share_access & FILE_READ_DATA) == 0) { + /* No access, read or write. */ + DEBUG(0,("user %s connection to %s " + "denied due to share security " + "descriptor.\n", + session_info->unix_info->unix_name, + lp_servicename(talloc_tos(), snum))); + return NT_STATUS_ACCESS_DENIED; + } + } + + if (!readonly_share && + !(share_access & FILE_WRITE_DATA)) { + /* smb.conf allows r/w, but the security descriptor denies + * write. Fall back to looking at readonly. */ + readonly_share = True; + DEBUG(5,("falling back to read-only access-evaluation due to " + "security descriptor\n")); + } + + *p_share_access = share_access; + *p_readonly_share = readonly_share; + + return NT_STATUS_OK; +} + +/******************************************************************* Check if a username is OK. This sets up conn->session_info with a copy related to this vuser that -- 1.7.7.3 From 9085281733977d290fbe9c273336d1615dbe038d Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 4 Jan 2013 11:05:03 -0800 Subject: [PATCH 13/17] Initialize stack variables. Prelude to factoring out calls to check_user_share_access(). Signed-off-by: Jeremy Allison --- source3/smbd/uid.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c index 6f5ff6d..dc92961 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -155,8 +155,8 @@ static bool check_user_ok(connection_struct *conn, int snum) { unsigned int i; - bool readonly_share; - bool admin_user; + bool readonly_share = false; + bool admin_user = false; struct vuid_cache_entry *ent = NULL; uint32_t share_access = 0; unsigned int share_array_index; -- 1.7.7.3 From 8f5a6844e011b973bcef0736ab84aa568603f3bf Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 4 Jan 2013 15:13:53 -0800 Subject: [PATCH 14/17] Factor code out of check_user_ok() into a call to check_user_share_access(). Signed-off-by: Jeremy Allison --- source3/smbd/uid.c | 40 +++++++--------------------------------- 1 files changed, 7 insertions(+), 33 deletions(-) diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c index dc92961..c782a77 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -160,6 +160,7 @@ static bool check_user_ok(connection_struct *conn, struct vuid_cache_entry *ent = NULL; uint32_t share_access = 0; unsigned int share_array_index; + NTSTATUS status; for (i=0; ivuid_cache.array[i]; @@ -172,41 +173,14 @@ static bool check_user_ok(connection_struct *conn, } } - if (!user_ok_token(session_info->unix_info->unix_name, - session_info->info->domain_name, - session_info->security_token, snum)) - return(False); - - readonly_share = is_share_read_only_for_token( - session_info->unix_info->unix_name, - session_info->info->domain_name, - session_info->security_token, - conn); - - share_access = create_share_access_mask(snum, - readonly_share, - session_info->security_token); - - if ((share_access & FILE_WRITE_DATA) == 0) { - if ((share_access & FILE_READ_DATA) == 0) { - /* No access, read or write. */ - DEBUG(0,("user %s connection to %s " - "denied due to share security " - "descriptor.\n", - session_info->unix_info->unix_name, - lp_servicename(talloc_tos(), snum))); - return false; - } + status = check_user_share_access(conn, + session_info, + &share_access, + &readonly_share); + if (!NT_STATUS_IS_OK(status)) { + return false; } - if (!readonly_share && - !(share_access & FILE_WRITE_DATA)) { - /* smb.conf allows r/w, but the security descriptor denies - * write. Fall back to looking at readonly. */ - readonly_share = True; - DEBUG(5,("falling back to read-only access-evaluation due to " - "security descriptor\n")); - } admin_user = token_contains_name_in_list( session_info->unix_info->unix_name, -- 1.7.7.3 From 24370ee2229864cdb62afd434a681eb0905e75e6 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 4 Jan 2013 15:15:59 -0800 Subject: [PATCH 15/17] Fix bug #9518 - conn->share_access appears not be be reset between users. Ensure make_connection_snum() uses the same logic as check_user_ok() to decide if a user can access a share. Signed-off-by: Jeremy Allison --- source3/smbd/service.c | 34 +++++++++++----------------------- 1 files changed, 11 insertions(+), 23 deletions(-) diff --git a/source3/smbd/service.c b/source3/smbd/service.c index 10f4b53..d3cda73 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -651,30 +651,18 @@ static NTSTATUS make_connection_snum(struct smbd_server_connection *sconn, TALLOC_FREE(s); } - /* - * New code to check if there's a share security descripter - * added from NT server manager. This is done after the - * smb.conf checks are done as we need a uid and token. JRA. - * - */ - - conn->share_access = create_share_access_mask(snum, - !CAN_WRITE(conn), - conn->session_info->security_token); - - if ((conn->share_access & FILE_WRITE_DATA) == 0) { - if ((conn->share_access & FILE_READ_DATA) == 0) { - /* No access, read or write. */ - DEBUG(0,("make_connection: connection to %s " - "denied due to security " - "descriptor.\n", - lp_servicename(talloc_tos(), snum))); - status = NT_STATUS_ACCESS_DENIED; - goto err_root_exit; - } else { - conn->read_only = True; - } + /* + * Set up the share security descripter + */ + + status = check_user_share_access(conn, + conn->session_info, + &conn->share_access, + &conn->read_only); + if (!NT_STATUS_IS_OK(status)) { + goto err_root_exit; } + /* Initialise VFS function pointers */ if (!smbd_vfs_init(conn)) { -- 1.7.7.3 From d7aeb17b249e80e0ba1b4c10472604a95db5afc0 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 4 Jan 2013 15:18:42 -0800 Subject: [PATCH 16/17] Move create_share_access_mask() from smbd/service.c to smbd/uid.c Make it static. Only called from uid.c now. Signed-off-by: Jeremy Allison --- source3/smbd/proto.h | 3 --- source3/smbd/service.c | 38 -------------------------------------- source3/smbd/uid.c | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 41 deletions(-) diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index cfaa0b0..a6f054b 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -962,9 +962,6 @@ void smbd_exit_server_cleanly(const char *const reason) _NORETURN_; bool set_conn_connectpath(connection_struct *conn, const char *connectpath); NTSTATUS set_conn_force_user_group(connection_struct *conn, int snum); -uint32_t create_share_access_mask(int snum, - bool readonly_share, - const struct security_token *token); bool set_current_service(connection_struct *conn, uint16 flags, bool do_chdir); void load_registry_shares(void); int add_home_service(const char *service, const char *username, const char *homedir); diff --git a/source3/smbd/service.c b/source3/smbd/service.c index d3cda73..b3abdd8 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -512,44 +512,6 @@ NTSTATUS set_conn_force_user_group(connection_struct *conn, int snum) } /**************************************************************************** - Setup the share access mask for a connection. -****************************************************************************/ - -uint32_t create_share_access_mask(int snum, - bool readonly_share, - const struct security_token *token) -{ - uint32_t share_access = 0; - - share_access_check(token, - lp_servicename(talloc_tos(), snum), - MAXIMUM_ALLOWED_ACCESS, - &share_access); - - if (readonly_share) { - share_access &= - ~(SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA | - SEC_FILE_WRITE_EA | SEC_FILE_WRITE_ATTRIBUTE | - SEC_DIR_DELETE_CHILD ); - } - - if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) { - share_access |= SEC_FLAG_SYSTEM_SECURITY; - } - if (security_token_has_privilege(token, SEC_PRIV_RESTORE)) { - share_access |= (SEC_RIGHTS_PRIV_RESTORE); - } - if (security_token_has_privilege(token, SEC_PRIV_BACKUP)) { - share_access |= (SEC_RIGHTS_PRIV_BACKUP); - } - if (security_token_has_privilege(token, SEC_PRIV_TAKE_OWNERSHIP)) { - share_access |= (SEC_STD_WRITE_OWNER); - } - - return share_access; -} - -/**************************************************************************** Make a connection, given the snum to connect to, and the vuser of the connecting user if appropriate. ****************************************************************************/ diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c index c782a77..d1c45f3 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -86,6 +86,44 @@ static void free_conn_session_info_if_unused(connection_struct *conn) static uint32_t vuid_cache_share_access_array[VUID_CACHE_SIZE]; +/**************************************************************************** + Setup the share access mask for a connection. +****************************************************************************/ + +static uint32_t create_share_access_mask(int snum, + bool readonly_share, + const struct security_token *token) +{ + uint32_t share_access = 0; + + share_access_check(token, + lp_servicename(talloc_tos(), snum), + MAXIMUM_ALLOWED_ACCESS, + &share_access); + + if (readonly_share) { + share_access &= + ~(SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA | + SEC_FILE_WRITE_EA | SEC_FILE_WRITE_ATTRIBUTE | + SEC_DIR_DELETE_CHILD ); + } + + if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) { + share_access |= SEC_FLAG_SYSTEM_SECURITY; + } + if (security_token_has_privilege(token, SEC_PRIV_RESTORE)) { + share_access |= (SEC_RIGHTS_PRIV_RESTORE); + } + if (security_token_has_privilege(token, SEC_PRIV_BACKUP)) { + share_access |= (SEC_RIGHTS_PRIV_BACKUP); + } + if (security_token_has_privilege(token, SEC_PRIV_TAKE_OWNERSHIP)) { + share_access |= (SEC_STD_WRITE_OWNER); + } + + return share_access; +} + /******************************************************************* Calculate access mask and if this user can access this share. ********************************************************************/ -- 1.7.7.3 From 46445b3da7ec2eca9b4c059a96509b4e68fd51b5 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 4 Jan 2013 11:14:04 -0800 Subject: [PATCH 17/17] selftest: show that Samba honours "write list" and valid users Reviewed-by: Jeremy Allison --- selftest/target/Samba3.pm | 7 +++++++ .../script/tests/test_smbclient_machine_auth.sh | 4 ++++ source3/script/tests/test_smbclient_s3.sh | 8 ++++++-- source3/selftest/tests.py | 5 +++++ 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index 2037a2e..6c63413 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -956,6 +956,13 @@ sub provision($$$$$$) [ro-tmp] path = $ro_shrdir guest ok = yes +[write-list-tmp] + path = $shrdir + read only = yes + write list = $unix_name +[valid-users-tmp] + path = $shrdir + valid users = $unix_name [msdfs-share] path = $msdfs_shrdir msdfs root = yes diff --git a/source3/script/tests/test_smbclient_machine_auth.sh b/source3/script/tests/test_smbclient_machine_auth.sh index f67256d..a890d48 100755 --- a/source3/script/tests/test_smbclient_machine_auth.sh +++ b/source3/script/tests/test_smbclient_machine_auth.sh @@ -19,3 +19,7 @@ incdir=`dirname $0`/../../../testprogs/blackbox . $incdir/subunit.sh testit "smbclient //$SERVER/tmp" $SMBCLIENT //$SERVER/tmp --machine-pass -I $SERVER_IP -p 139 -c quit $ADDARGS + +# Testing these here helps because we know the machine account isn't already this user/group +testit "smbclient //$SERVER/forceuser" $SMBCLIENT //$SERVER/tmp --machine-pass -I $SERVER_IP -p 139 -c quit $ADDARGS +testit "smbclient //$SERVER/forcegroup" $SMBCLIENT //$SERVER/tmp --machine-pass -I $SERVER_IP -p 139 -c quit $ADDARGS diff --git a/source3/script/tests/test_smbclient_s3.sh b/source3/script/tests/test_smbclient_s3.sh index 3341c62..aa2ba77 100755 --- a/source3/script/tests/test_smbclient_s3.sh +++ b/source3/script/tests/test_smbclient_s3.sh @@ -211,7 +211,7 @@ mkdir a_test_dir quit EOF - cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U% //$SERVER/ro-tmp -I $SERVER_IP $ADDARGS < $tmpfile 2>&1' + cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U% //$SERVER/$1" -I $SERVER_IP $ADDARGS < $tmpfile 2>&1' eval echo "$cmd" out=`eval $cmd` ret=$? @@ -529,7 +529,11 @@ testit "creating a good symlink and deleting it by path" \ failed=`expr $failed + 1` testit "writing into a read-only directory fails" \ - test_read_only_dir || \ + test_read_only_dir ro-tmp || \ + failed=`expr $failed + 1` + +testit "writing into a read-only share fails" \ + test_read_only_dir valid-users-tmp || \ failed=`expr $failed + 1` testit "Reading a owner-only file fails" \ diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index 9b0527c..57c80f2 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -330,6 +330,11 @@ for t in tests: elif t == "smb2.durable-open" or t == "smb2.durable-v2-open": plansmbtorture4testsuite(t, "s3dc", '//$SERVER_IP/durable -U$USERNAME%$PASSWORD') plansmbtorture4testsuite(t, "plugin_s4_dc", '//$SERVER_IP/durable -U$USERNAME%$PASSWORD') + elif t == "base.rw1": + plansmbtorture4testsuite(t, "s3dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD') + plansmbtorture4testsuite(t, "s3dc", '//$SERVER_IP/valid-users-tmp -U$USERNAME%$PASSWORD') + plansmbtorture4testsuite(t, "s3dc", '//$SERVER_IP/write-list-tmp -U$USERNAME%$PASSWORD') + plansmbtorture4testsuite(t, "plugin_s4_dc", '//$SERVER/tmp -U$USERNAME%$PASSWORD') else: plansmbtorture4testsuite(t, "s3dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD') plansmbtorture4testsuite(t, "plugin_s4_dc", '//$SERVER/tmp -U$USERNAME%$PASSWORD') -- 1.7.7.3