Fixup the 'multiple-vuids' bugs.
authorJeremy Allison <jra@samba.org>
Fri, 13 Feb 2004 19:05:25 +0000 (19:05 +0000)
committerJeremy Allison <jra@samba.org>
Fri, 13 Feb 2004 19:05:25 +0000 (19:05 +0000)
Jeremy.

source/include/smb.h
source/smbd/conn.c
source/smbd/service.c
source/smbd/uid.c

index 24cdde30d1ff634872c252ba403e9c0b2375bf13..37a2833d97554402d350c2eb37db82f573d52237 100644 (file)
@@ -421,7 +421,8 @@ typedef struct files_struct
 #include "sysquotas.h"
 
 /* used to hold an arbitrary blob of data */
-typedef struct data_blob {
+typedef struct data_blob
+{
        uint8 *data;
        size_t length;
        void (*free)(struct data_blob *data_blob);
@@ -434,19 +435,27 @@ typedef struct data_blob {
 
 typedef struct
 {
-  time_t modify_time;
-  time_t status_time;
+       time_t modify_time;
+       time_t status_time;
 } dir_status_struct;
 
-struct vuid_cache {
-  unsigned int entries;
-  uint16 list[VUID_CACHE_SIZE];
+struct vuid_cache_entry
+{
+       uint16 vuid;
+       BOOL read_only;
+       BOOL admin_user;
+};
+
+struct vuid_cache
+{
+       unsigned int entries;
+       struct vuid_cache_entry array[VUID_CACHE_SIZE];
 };
 
 typedef struct
 {
-  char *name;
-  BOOL is_wild;
+       char *name;
+       BOOL is_wild;
 } name_compare_entry;
 
 /* Include VFS stuff */
@@ -466,8 +475,8 @@ typedef struct connection_struct
        void *dirptr;
        BOOL printer;
        BOOL ipc;
-       BOOL read_only;
-       BOOL admin_user;
+       BOOL read_only; /* Attributes for the current user of the share. */
+       BOOL admin_user; /* Attributes for the current user of the share. */
        char *dirpath;
        char *connectpath;
        char *origpath;
index 289b7d611d6b927c7a340927507a2a155d8f3fe4..9bac0acdb9fd3b6e622e26a6f2211bffade5e896 100644 (file)
@@ -199,8 +199,9 @@ BOOL conn_idle_all(time_t t, int deadtime)
 }
 
 /****************************************************************************
-clear a vuid out of the validity cache, and as the 'owner' of a connection.
+ Clear a vuid out of the validity cache, and as the 'owner' of a connection.
 ****************************************************************************/
+
 void conn_clear_vuid_cache(uint16 vuid)
 {
        connection_struct *conn;
@@ -212,8 +213,11 @@ void conn_clear_vuid_cache(uint16 vuid)
                }
 
                for (i=0;i<conn->vuid_cache.entries && i< VUID_CACHE_SIZE;i++) {
-                       if (conn->vuid_cache.list[i] == vuid) {
-                               conn->vuid_cache.list[i] = UID_FIELD_INVALID;
+                       if (conn->vuid_cache.array[i].vuid == vuid) {
+                               struct vuid_cache_entry *ent = &conn->vuid_cache.array[i];
+                               ent->vuid = UID_FIELD_INVALID;
+                               ent->read_only = False;
+                               ent->admin_user = False;
                        }
                }
        }
index e5655bd9f4c23498016ee6191e637b5c2b2ff31a..78b610ae37c7c2a1bcd7f7c4f1efcb44e6965217 100644 (file)
@@ -259,78 +259,6 @@ static NTSTATUS share_sanity_checks(int snum, fstring dev)
        return NT_STATUS_OK;
 }
 
-/****************************************************************************
- readonly share?
-****************************************************************************/
-
-static void set_read_only(connection_struct *conn, gid_t *groups, size_t n_groups)
-{
-       char **list;
-       const char *service = lp_servicename(conn->service);
-       conn->read_only = lp_readonly(conn->service);
-
-       if (!service)
-               return;
-
-       str_list_copy(&list, lp_readlist(conn->service));
-       if (list) {
-               if (!str_list_sub_basic(list, current_user_info.smb_name) ) {
-                       DEBUG(0, ("ERROR: read list substitution failed\n"));
-               }
-               if (!str_list_substitute(list, "%S", service)) {
-                       DEBUG(0, ("ERROR: read list service substitution failed\n"));
-               }
-               if (user_in_list(conn->user, (const char **)list, groups, n_groups))
-                       conn->read_only = True;
-               str_list_free(&list);
-       }
-       
-       str_list_copy(&list, lp_writelist(conn->service));
-       if (list) {
-               if (!str_list_sub_basic(list, current_user_info.smb_name) ) {
-                       DEBUG(0, ("ERROR: write list substitution failed\n"));
-               }
-               if (!str_list_substitute(list, "%S", service)) {
-                       DEBUG(0, ("ERROR: write list service substitution failed\n"));
-               }
-               if (user_in_list(conn->user, (const char **)list, groups, n_groups))
-                       conn->read_only = False;
-               str_list_free(&list);
-       }
-}
-
-/****************************************************************************
-  admin user check
-****************************************************************************/
-
-static void set_admin_user(connection_struct *conn, gid_t *groups, size_t n_groups)
-{
-       /* admin user check */
-       
-       /* JRA - original code denied admin user if the share was
-          marked read_only. Changed as I don't think this is needed,
-          but old code left in case there is a problem here.
-       */
-       if (user_in_list(conn->user,lp_admin_users(conn->service), groups, n_groups) 
-#if 0
-           && !conn->read_only
-#endif
-           ) {
-               conn->admin_user = True;
-               conn->force_user = True;  /* Admin users are effectivly 'forced' */
-               DEBUG(0,("%s logged in as admin user (root privileges)\n",conn->user));
-       } else {
-               conn->admin_user = False;
-       }
-
-#if 0 /* This done later, for now */    
-       /* admin users always run as uid=0 */
-       if (conn->admin_user) {
-               conn->uid = 0;
-       }
-#endif
-}
-
 /****************************************************************************
   Make a connection, given the snum to connect to, and the vuser of the
   connecting user if appropriate.
@@ -443,10 +371,9 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
        string_set(&conn->dirpath,"");
        string_set(&conn->user,user);
        conn->nt_user_token = NULL;
-       
-       set_read_only(conn, vuser ? vuser->groups : NULL, vuser ? vuser->n_groups : 0);
-       
-       set_admin_user(conn, vuser ? vuser->groups : NULL, vuser ? vuser->n_groups : 0);
+
+       conn->read_only = lp_readonly(conn->service);
+       conn->admin_user = False;
 
        /*
         * If force user is true, then store the
@@ -478,11 +405,6 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
                }
        }
 
-       /* admin users always run as uid=0 */
-       if (conn->admin_user) {
-               conn->uid = 0;
-       }
-
 #ifdef HAVE_GETGRNAM 
        /*
         * If force group is true, then override
index f3d9004dd9f8fae2c30d0da663f09708c408eb89..3859298055bf82fdd49bdcf157fdec0b78bcb373 100644 (file)
@@ -54,33 +54,97 @@ BOOL change_to_guest(void)
        return True;
 }
 
+/****************************************************************************
+ Readonly share for this user ?
+****************************************************************************/
+
+static BOOL is_share_read_only_for_user(connection_struct *conn, user_struct *vuser)
+{
+       char **list;
+       const char *service = lp_servicename(conn->service);
+       BOOL read_only_ret = lp_readonly(conn->service);
+
+       if (!service)
+               return read_only_ret;
+
+       str_list_copy(&list, lp_readlist(conn->service));
+       if (list) {
+               if (!str_list_sub_basic(list, vuser->user.smb_name) ) {
+                       DEBUG(0, ("is_share_read_only_for_user: ERROR: read list substitution failed\n"));
+               }
+               if (!str_list_substitute(list, "%S", service)) {
+                       DEBUG(0, ("is_share_read_only_for_user: ERROR: read list service substitution failed\n"));
+               }
+               if (user_in_list(vuser->user.unix_name, (const char **)list, vuser->groups, vuser->n_groups)) {
+                       read_only_ret = True;
+               }
+               str_list_free(&list);
+       }
+
+       str_list_copy(&list, lp_writelist(conn->service));
+       if (list) {
+               if (!str_list_sub_basic(list, vuser->user.smb_name) ) {
+                       DEBUG(0, ("is_share_read_only_for_user: ERROR: write list substitution failed\n"));
+               }
+               if (!str_list_substitute(list, "%S", service)) {
+                       DEBUG(0, ("is_share_read_only_for_user: ERROR: write list service substitution failed\n"));
+               }
+               if (user_in_list(vuser->user.unix_name, (const char **)list, vuser->groups, vuser->n_groups)) {
+                       read_only_ret = False;
+               }
+               str_list_free(&list);
+       }
+
+       DEBUG(10,("is_share_read_only_for_user: share %s is %s for unix user %s\n",
+               service, read_only_ret ? "read-only" : "read-write", vuser->user.unix_name ));
+
+       return read_only_ret;
+}
+
 /*******************************************************************
  Check if a username is OK.
 ********************************************************************/
 
 static BOOL check_user_ok(connection_struct *conn, user_struct *vuser,int snum)
 {
-       unsigned i;
-       for (i=0;i<conn->vuid_cache.entries && i< VUID_CACHE_SIZE;i++)
-               if (conn->vuid_cache.list[i] == vuser->vuid)
+       unsigned int i;
+       struct vuid_cache_entry *ent = NULL;
+       BOOL readonly_share;
+
+       for (i=0;i<conn->vuid_cache.entries && i< VUID_CACHE_SIZE;i++) {
+               if (conn->vuid_cache.array[i].vuid == vuser->vuid) {
+                       ent = &conn->vuid_cache.array[i];
+                       conn->read_only = ent->read_only;
+                       conn->admin_user = ent->admin_user;
                        return(True);
-
-       if ((conn->force_user || conn->force_group) 
-           && (conn->vuid != vuser->vuid)) {
-               return False;
+               }
        }
-       
+
        if (!user_ok(vuser->user.unix_name,snum, vuser->groups, vuser->n_groups))
                return(False);
 
-       if (!share_access_check(conn, snum, vuser, conn->read_only ? FILE_READ_DATA : FILE_WRITE_DATA)) {
+       readonly_share = is_share_read_only_for_user(conn, vuser);
+
+       if (!share_access_check(conn, snum, vuser, readonly_share ? FILE_READ_DATA : FILE_WRITE_DATA)) {
                return False;
        }
 
        i = conn->vuid_cache.entries % VUID_CACHE_SIZE;
-       conn->vuid_cache.list[i] = vuser->vuid;
+       if (conn->vuid_cache.entries < VUID_CACHE_SIZE)
+               conn->vuid_cache.entries++;
+
+       ent = &conn->vuid_cache.array[i];
+       ent->vuid = vuser->vuid;
+       ent->read_only = readonly_share;
+
+       if (user_in_list(vuser->user.unix_name ,lp_admin_users(conn->service), vuser->groups, vuser->n_groups)) {
+               ent->admin_user = True;
+       } else {
+               ent->admin_user = False;
+       }
 
-       conn->vuid_cache.entries++;
+       conn->read_only = ent->read_only;
+       conn->admin_user = ent->admin_user;
 
        return(True);
 }
@@ -132,7 +196,7 @@ BOOL change_to_user(connection_struct *conn, uint16 vuid)
                current_user.ngroups = conn->ngroups;
                token = conn->nt_user_token;
        } else if ((vuser) && check_user_ok(conn, vuser, snum)) {
-               uid = vuser->uid;
+               uid = conn->admin_user ? 0 : vuser->uid;
                gid = vuser->gid;
                current_user.ngroups = vuser->n_groups;
                current_user.groups  = vuser->groups;