diff --git a/source/smbd/service.c b/source/smbd/service.c index 491a67a..68d5b9b 100644 --- a/source/smbd/service.c +++ b/source/smbd/service.c @@ -682,6 +682,8 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, conn->params->service = snum; conn->nt_user_token = NULL; + conn->read_only = lp_readonly(SNUM(conn)); + conn->admin_user = False; if (lp_guest_only(snum)) { const char *guestname = lp_guestaccount(); @@ -761,12 +763,19 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, &conn->uid, &conn->gid, &found_username, &conn->nt_user_token); - TALLOC_FREE(pass); if (!NT_STATUS_IS_OK(status2)) { conn_free(conn); *status = status2; + TALLOC_FREE(pass); return NULL; } + if (!check_user_ok_sharelevel_security(conn, pass->pw_name)) { + conn_free(conn); + *status = NT_STATUS_ACCESS_DENIED; + TALLOC_FREE(pass); + return NULL; + } + TALLOC_FREE(pass); fstrcpy(user, found_username); string_set(&conn->user,user); TALLOC_FREE(found_username); @@ -812,9 +821,6 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, string_set(&conn->dirpath,""); string_set(&conn->user,user); - conn->read_only = lp_readonly(SNUM(conn)); - conn->admin_user = False; - /* * If force user is true, then store the given userid and the gid of * the user we're forcing. diff --git a/source/smbd/share_access.c b/source/smbd/share_access.c index e89934c..ef898b8 100644 --- a/source/smbd/share_access.c +++ b/source/smbd/share_access.c @@ -191,7 +191,7 @@ bool token_contains_name_in_list(const char *username, * The other use is the netgroup check when using @group or &group. */ -bool user_ok_token(const char *username, struct nt_user_token *token, int snum) +bool user_ok_token(const char *username, const struct nt_user_token *token, int snum) { if (lp_invalid_users(snum) != NULL) { if (token_contains_name_in_list(username, lp_servicename(snum), @@ -248,7 +248,7 @@ bool user_ok_token(const char *username, struct nt_user_token *token, int snum) */ bool is_share_read_only_for_token(const char *username, - struct nt_user_token *token, + const struct nt_user_token *token, connection_struct *conn) { int snum = SNUM(conn); diff --git a/source/smbd/uid.c b/source/smbd/uid.c index 631a37f..3b3952b 100644 --- a/source/smbd/uid.c +++ b/source/smbd/uid.c @@ -141,6 +141,48 @@ static bool check_user_ok(connection_struct *conn, user_struct *vuser,int snum) return(True); } +/******************************************************************* + Check if a username is OK in share level security. +********************************************************************/ + +bool check_user_ok_sharelevel_security(connection_struct *conn, + const char *unix_name) +{ + int snum = SNUM(conn); + NT_USER_TOKEN *token = conn->nt_user_token; + + if (!user_ok_token(unix_name, token, snum)) { + return false; + } + + conn->read_only = is_share_read_only_for_token(unix_name, + token, + conn); + + if (!conn->read_only && + !share_access_check(token, lp_servicename(snum), + FILE_WRITE_DATA)) { + /* smb.conf allows r/w, but the security descriptor denies + * write. Fall back to looking at readonly. */ + conn->read_only = true; + DEBUG(5,("falling back to read-only access-evaluation due to " + "security descriptor\n")); + } + + if (!share_access_check(token, lp_servicename(snum), + conn->read_only ? + FILE_READ_DATA : FILE_WRITE_DATA)) { + return false; + } + + conn->admin_user = token_contains_name_in_list( + unix_name, NULL, token, + lp_admin_users(SNUM(conn))); + + return true; +} + + /**************************************************************************** Become the user of a connection number without changing the security context stack, but modify the current_user entries.