[GLUE] Rsync SAMBA_3_2_0 SVN r25598 in order to create the v3-2-test branch.
[samba.git] / source / smbd / conn.c
index b110e8d0828904a4583f4372b6bb3630895745ea..50a71edf9d304f8337e6c5555c5a4378dd292870 100644 (file)
@@ -1,12 +1,12 @@
 /* 
-   Unix SMB/Netbios implementation.
-   Version 1.9.
+   Unix SMB/CIFS implementation.
    Manage connections_struct structures
    Copyright (C) Andrew Tridgell 1998
+   Copyright (C) Alexander Bokovoy 2002
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 
-extern int DEBUGLEVEL;
-
-/* set these to define the limits of the server. NOTE These are on a
-   per-client basis. Thus any one machine can't connect to more than
-   MAX_CONNECTIONS services, but any number of machines may connect at
-   one time. */
-#define MAX_CONNECTIONS 128
+/* The connections bitmap is expanded in increments of BITMAP_BLOCK_SZ. The
+ * maximum size of the bitmap is the largest positive integer, but you will hit
+ * the "max connections" limit, looong before that.
+ */
+#define BITMAP_BLOCK_SZ 128
 
 static connection_struct *Connections;
 
@@ -40,7 +37,7 @@ init the conn structures
 ****************************************************************************/
 void conn_init(void)
 {
-       bmap = bitmap_allocate(MAX_CONNECTIONS);
+       bmap = bitmap_allocate(BITMAP_BLOCK_SZ);
 }
 
 /****************************************************************************
@@ -59,7 +56,7 @@ BOOL conn_snum_used(int snum)
 {
        connection_struct *conn;
        for (conn=Connections;conn;conn=conn->next) {
-               if (conn->service == snum) {
+               if (conn->params->service == snum) {
                        return(True);
                }
        }
@@ -70,12 +67,18 @@ BOOL conn_snum_used(int snum)
 /****************************************************************************
 find a conn given a cnum
 ****************************************************************************/
-connection_struct *conn_find(int cnum)
+connection_struct *conn_find(unsigned cnum)
 {
+       int count=0;
        connection_struct *conn;
 
-       for (conn=Connections;conn;conn=conn->next) {
-               if (conn->cnum == cnum) return conn;
+       for (conn=Connections;conn;conn=conn->next,count++) {
+               if (conn->cnum == cnum) {
+                       if (count > 10) {
+                               DLIST_PROMOTE(Connections, conn);
+                       }
+                       return conn;
+               }
        }
 
        return NULL;
@@ -89,108 +92,256 @@ thinking the server is still available.
 ****************************************************************************/
 connection_struct *conn_new(void)
 {
+       TALLOC_CTX *mem_ctx;
        connection_struct *conn;
        int i;
+        int find_offset = 1;
 
-       i = bitmap_find(bmap, 1);
+find_again:
+       i = bitmap_find(bmap, find_offset);
        
        if (i == -1) {
-               DEBUG(1,("ERROR! Out of connection structures\n"));            
+                /* Expand the connections bitmap. */
+                int             oldsz = bmap->n;
+                int             newsz = bmap->n + BITMAP_BLOCK_SZ;
+                struct bitmap * nbmap;
+
+                if (newsz <= oldsz) {
+                        /* Integer wrap. */
+                       DEBUG(0,("ERROR! Out of connection structures\n"));
+                        return NULL;
+                }
+
+               DEBUG(4,("resizing connections bitmap from %d to %d\n",
+                        oldsz, newsz));
+
+                nbmap = bitmap_allocate(newsz);
+               if (!nbmap) {
+                       DEBUG(0,("ERROR! malloc fail.\n"));
+                       return NULL;
+               }
+
+                bitmap_copy(nbmap, bmap);
+                bitmap_free(bmap);
+
+                bmap = nbmap;
+                find_offset = oldsz; /* Start next search in the new portion. */
+
+                goto find_again;
+       }
+
+       /* The bitmap position is used below as the connection number
+        * conn->cnum). This ends up as the TID field in the SMB header,
+        * which is limited to 16 bits (we skip 0xffff which is the
+        * NULL TID).
+        */
+       if (i > 65534) {
+               DEBUG(0, ("Maximum connection limit reached\n"));
                return NULL;
        }
 
-       conn = (connection_struct *)malloc(sizeof(*conn));
-       if (!conn) return NULL;
+       if ((mem_ctx=talloc_init("connection_struct"))==NULL) {
+               DEBUG(0,("talloc_init(connection_struct) failed!\n"));
+               return NULL;
+       }
 
-       memset(conn, 0, sizeof(*conn));
+       if (!(conn=TALLOC_ZERO_P(mem_ctx, connection_struct)) ||
+           !(conn->params = TALLOC_P(mem_ctx, struct share_params))) {
+               DEBUG(0,("TALLOC_ZERO() failed!\n"));
+               TALLOC_FREE(mem_ctx);
+               return NULL;
+       }
+       conn->mem_ctx = mem_ctx;
        conn->cnum = i;
 
        bitmap_set(bmap, i);
 
        num_open++;
 
-       string_init(&conn->user,"");
-       string_init(&conn->dirpath,"");
-       string_init(&conn->connectpath,"");
-       string_init(&conn->origpath,"");
+       string_set(&conn->user,"");
+       string_set(&conn->dirpath,"");
+       string_set(&conn->connectpath,"");
+       string_set(&conn->origpath,"");
        
-       /* hook into the front of the list */
-       if (!Connections) {
-               Connections = conn;
-       } else {
-               Connections->prev = conn;
-               conn->next = Connections;
-               Connections = conn;
-       }
+       DLIST_ADD(Connections, conn);
 
        return conn;
 }
 
 /****************************************************************************
-close all conn structures
+ Close all conn structures.
 ****************************************************************************/
+
 void conn_close_all(void)
 {
        connection_struct *conn, *next;
        for (conn=Connections;conn;conn=next) {
                next=conn->next;
-               close_cnum(conn, (uint16)-1);
+               set_current_service(conn, 0, True);
+               close_cnum(conn, conn->vuid);
        }
 }
 
 /****************************************************************************
-idle inactive connections
+ Idle inactive connections.
 ****************************************************************************/
-BOOL conn_idle_all(time_t t, int deadtime)
+
+BOOL conn_idle_all(time_t t)
 {
-       BOOL allidle = True;
-       connection_struct *conn, *next;
+       int deadtime = lp_deadtime()*60;
+       pipes_struct *plist = NULL;
+       connection_struct *conn;
+
+       if (deadtime <= 0)
+               deadtime = DEFAULT_SMBD_TIMEOUT;
+
+       for (conn=Connections;conn;conn=conn->next) {
+
+               time_t age = t - conn->lastused;
+
+               /* Update if connection wasn't idle. */
+               if (conn->lastused != conn->lastused_count) {
+                       conn->lastused = t;
+                       conn->lastused_count = t;
+               }
 
-       for (conn=Connections;conn;conn=next) {
-               next=conn->next;
                /* close dirptrs on connections that are idle */
-               if ((t-conn->lastused) > DPTR_IDLE_TIMEOUT)
+               if (age > DPTR_IDLE_TIMEOUT) {
                        dptr_idlecnum(conn);
+               }
 
-               if (conn->num_files_open > 0 || 
-                   (t-conn->lastused)<deadtime)
-                       allidle = False;
+               if (conn->num_files_open > 0 || age < deadtime) {
+                       return False;
+               }
        }
 
-       return allidle;
+       /*
+        * Check all pipes for any open handles. We cannot
+        * idle with a handle open.
+        */
+
+       for (plist = get_first_internal_pipe(); plist;
+            plist = get_next_internal_pipe(plist)) {
+               if (plist->pipe_handles && plist->pipe_handles->count) {
+                       return False;
+               }
+       }
+       
+       return True;
 }
 
 /****************************************************************************
-free a conn structure
+ Clear a vuid out of the validity cache, and as the 'owner' of a connection.
 ****************************************************************************/
-void conn_free(connection_struct *conn)
+
+void conn_clear_vuid_cache(uint16 vuid)
 {
-       if (conn == Connections) {
-               Connections = conn->next;
-               if (Connections) Connections->prev = NULL;
-       } else {
-               conn->prev->next = conn->next;
-               if (conn->next) conn->next->prev = conn->prev;
+       connection_struct *conn;
+       unsigned int i;
+
+       for (conn=Connections;conn;conn=conn->next) {
+               if (conn->vuid == vuid) {
+                       conn->vuid = UID_FIELD_INVALID;
+               }
+
+               for (i=0;i<conn->vuid_cache.entries && i< VUID_CACHE_SIZE;i++) {
+                       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;
+                       }
+               }
        }
+}
+
+/****************************************************************************
+ Free a conn structure - internal part.
+****************************************************************************/
 
-       if (conn->ngroups && conn->groups) {
-               free(conn->groups);
-               conn->groups = NULL;
-               conn->ngroups = 0;
+void conn_free_internal(connection_struct *conn)
+{
+       vfs_handle_struct *handle = NULL, *thandle = NULL;
+       TALLOC_CTX *mem_ctx = NULL;
+       struct trans_state *state = NULL;
+
+       /* Free vfs_connection_struct */
+       handle = conn->vfs_handles;
+       while(handle) {
+               DLIST_REMOVE(conn->vfs_handles, handle);
+               thandle = handle->next;
+               if (handle->free_data)
+                       handle->free_data(&handle->data);
+               handle = thandle;
+       }
+
+       /* Free any pending transactions stored on this conn. */
+       for (state = conn->pending_trans; state; state = state->next) {
+               /* state->setup is a talloc child of state. */
+               SAFE_FREE(state->param);
+               SAFE_FREE(state->data);
        }
 
        free_namearray(conn->veto_list);
        free_namearray(conn->hide_list);
        free_namearray(conn->veto_oplock_list);
+       free_namearray(conn->aio_write_behind_list);
        
        string_free(&conn->user);
        string_free(&conn->dirpath);
        string_free(&conn->connectpath);
        string_free(&conn->origpath);
 
+       mem_ctx = conn->mem_ctx;
+       ZERO_STRUCTP(conn);
+       talloc_destroy(mem_ctx);
+}
+
+/****************************************************************************
+ Free a conn structure.
+****************************************************************************/
+
+void conn_free(connection_struct *conn)
+{
+       DLIST_REMOVE(Connections, conn);
+
        bitmap_clear(bmap, conn->cnum);
+
+       SMB_ASSERT(num_open > 0);
        num_open--;
 
-       memset(conn, 0, sizeof(*conn));
-       free(conn);
+       conn_free_internal(conn);
+}
+/****************************************************************************
+receive a smbcontrol message to forcibly unmount a share
+the message contains just a share name and all instances of that
+share are unmounted
+the special sharename '*' forces unmount of all shares
+****************************************************************************/
+void msg_force_tdis(struct messaging_context *msg,
+                   void *private_data,
+                   uint32_t msg_type,
+                   struct server_id server_id,
+                   DATA_BLOB *data)
+{
+       connection_struct *conn, *next;
+       fstring sharename;
+
+       fstrcpy(sharename, (const char *)data->data);
+
+       if (strcmp(sharename, "*") == 0) {
+               DEBUG(1,("Forcing close of all shares\n"));
+               conn_close_all();
+               return;
+       }
+
+       for (conn=Connections;conn;conn=next) {
+               next=conn->next;
+               if (strequal(lp_servicename(SNUM(conn)), sharename)) {
+                       DEBUG(1,("Forcing close of share %s cnum=%d\n",
+                                sharename, conn->cnum));
+                       close_cnum(conn, (uint16)-1);
+               }
+       }
 }