Fix bug #1254 - write list not working under share-level security
authorJeremy Allison <jra@samba.org>
Thu, 4 Dec 2008 19:07:53 +0000 (11:07 -0800)
committerJeremy Allison <jra@samba.org>
Thu, 4 Dec 2008 19:07:53 +0000 (11:07 -0800)
(mtab.c, fix build).
Jeremy.

source/client/mtab.c
source/smbd/share_access.c
source/smbd/uid.c

index 93fbd11359b6b89344e416e9583b72f6ea2b2b4b..70789bcb9d87829319c7293bc28c08134f539b92 100644 (file)
@@ -32,6 +32,7 @@
 #include <errno.h>
 #include <stdio.h>
 #include <sys/time.h>
+#include <sys/stat.h>
 #include <time.h>
 #include <fcntl.h>
 #include <mntent.h>
index adb9d169642d96b93ca889da277c9418710dc4dc..c9716941818a9c264719ac3cef45ab00cbe65370 100644 (file)
@@ -192,7 +192,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),
@@ -249,7 +249,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, int snum)
+                                 const struct nt_user_token *token, int snum)
 {
        BOOL result = lp_readonly(snum);
 
index c6d4e3329c8b9ff8513c20c8eed2dd257dc51e7c..07a42fa7fee9407ab1a68a835358fa2f2abbc5eb 100644 (file)
@@ -142,6 +142,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.
+********************************************************************/
+
+static bool check_user_ok_sharelevel_security(connection_struct *conn,
+                                       const char *unix_name,
+                                       int snum)
+{
+       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,
+                                                     snum);
+
+       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.
@@ -149,6 +191,7 @@ static BOOL check_user_ok(connection_struct *conn, user_struct *vuser,int snum)
 
 BOOL change_to_user(connection_struct *conn, uint16 vuid)
 {
+       enum security_types sec = (enum security_types)lp_security();
        user_struct *vuser = get_valid_user_struct(vuid);
        int snum;
        gid_t gid;
@@ -171,7 +214,7 @@ BOOL change_to_user(connection_struct *conn, uint16 vuid)
         * SMB's - this hurts performance - Badly.
         */
 
-       if((lp_security() == SEC_SHARE) && (current_user.conn == conn) &&
+       if((sec == SEC_SHARE) && (current_user.conn == conn) &&
           (current_user.ut.uid == conn->uid)) {
                DEBUG(4,("change_to_user: Skipping user change - already "
                         "user\n"));
@@ -192,6 +235,13 @@ BOOL change_to_user(connection_struct *conn, uint16 vuid)
                         vuser->user.smb_name, vuser->user.unix_name, vuid,
                         lp_servicename(snum)));
                return False;
+       } else if ((sec == SEC_SHARE) && !check_user_ok_sharelevel_security(conn,
+                       conn->user, snum)) {
+               DEBUG(2,("change_to_user: unix user %s "
+                        "not permitted access to share %s.\n",
+                        conn->user,
+                        lp_servicename(snum)));
+               return false;
        }
 
        if (conn->force_user) /* security = share sets this too */ {