Move tcons.num_open from smb1 to sconn->num_tcons_open as this is needed for SMB2...
[abartlet/samba.git/.git] / source3 / smbd / conn.c
index 44888b777f2e536b6d3014f7434a261f76d7d4df..b18231f44cb4e4f5cf773a58bdc5c7059bf8feb1 100644 (file)
@@ -6,7 +6,7 @@
    
    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"
+#include "smbd/globals.h"
 
 /* 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
  */
 #define BITMAP_BLOCK_SZ 128
 
-static connection_struct *Connections;
-
-/* number of open connections */
-static struct bitmap *bmap;
-static int num_open;
-
 /****************************************************************************
 init the conn structures
 ****************************************************************************/
-void conn_init(void)
+void conn_init(struct smbd_server_connection *sconn)
 {
-       bmap = bitmap_allocate(BITMAP_BLOCK_SZ);
+       sconn->smb1.tcons.Connections = NULL;
+       sconn->smb1.tcons.bmap = bitmap_talloc(sconn, BITMAP_BLOCK_SZ);
 }
 
 /****************************************************************************
 return the number of open connections
 ****************************************************************************/
-int conn_num_open(void)
+int conn_num_open(struct smbd_server_connection *sconn)
 {
-       return num_open;
+       return sconn->num_tcons_open;
 }
 
 
 /****************************************************************************
 check if a snum is in use
 ****************************************************************************/
-BOOL conn_snum_used(int snum)
+bool conn_snum_used(int snum)
 {
+       struct smbd_server_connection *sconn = smbd_server_conn;
        connection_struct *conn;
-       for (conn=Connections;conn;conn=conn->next) {
+       for (conn=sconn->smb1.tcons.Connections;conn;conn=conn->next) {
                if (conn->params->service == snum) {
                        return(True);
                }
@@ -64,19 +60,20 @@ BOOL conn_snum_used(int snum)
        return(False);
 }
 
-
 /****************************************************************************
-find a conn given a cnum
+ Find a conn given a cnum.
 ****************************************************************************/
-connection_struct *conn_find(unsigned cnum)
+
+connection_struct *conn_find(struct smbd_server_connection *sconn,unsigned cnum)
 {
        int count=0;
        connection_struct *conn;
 
-       for (conn=Connections;conn;conn=conn->next,count++) {
+       for (conn=sconn->smb1.tcons.Connections;conn;conn=conn->next,count++) {
                if (conn->cnum == cnum) {
                        if (count > 10) {
-                               DLIST_PROMOTE(Connections, conn);
+                               DLIST_PROMOTE(sconn->smb1.tcons.Connections,
+                                             conn);
                        }
                        return conn;
                }
@@ -85,26 +82,36 @@ connection_struct *conn_find(unsigned cnum)
        return NULL;
 }
 
-
 /****************************************************************************
   find first available connection slot, starting from a random position.
 The randomisation stops problems with the server dieing and clients
 thinking the server is still available.
 ****************************************************************************/
-connection_struct *conn_new(void)
+connection_struct *conn_new(struct smbd_server_connection *sconn)
 {
-       TALLOC_CTX *mem_ctx;
        connection_struct *conn;
        int i;
         int find_offset = 1;
 
+       if (sconn->using_smb2) {
+               if (!(conn=TALLOC_ZERO_P(NULL, connection_struct)) ||
+                   !(conn->params = TALLOC_P(conn, struct share_params))) {
+                       DEBUG(0,("TALLOC_ZERO() failed!\n"));
+                       TALLOC_FREE(conn);
+                       return NULL;
+               }
+               conn->sconn = sconn;
+               return conn;
+       }
+
 find_again:
-       i = bitmap_find(bmap, find_offset);
+       i = bitmap_find(sconn->smb1.tcons.bmap, find_offset);
        
        if (i == -1) {
                 /* Expand the connections bitmap. */
-                int             oldsz = bmap->n;
-                int             newsz = bmap->n + BITMAP_BLOCK_SZ;
+                int             oldsz = sconn->smb1.tcons.bmap->n;
+                int             newsz = sconn->smb1.tcons.bmap->n +
+                                       BITMAP_BLOCK_SZ;
                 struct bitmap * nbmap;
 
                 if (newsz <= oldsz) {
@@ -116,16 +123,16 @@ find_again:
                DEBUG(4,("resizing connections bitmap from %d to %d\n",
                         oldsz, newsz));
 
-                nbmap = bitmap_allocate(newsz);
+                nbmap = bitmap_talloc(sconn, newsz);
                if (!nbmap) {
                        DEBUG(0,("ERROR! malloc fail.\n"));
                        return NULL;
                }
 
-                bitmap_copy(nbmap, bmap);
-                bitmap_free(bmap);
+                bitmap_copy(nbmap, sconn->smb1.tcons.bmap);
+               TALLOC_FREE(sconn->smb1.tcons.bmap);
 
-                bmap = nbmap;
+                sconn->smb1.tcons.bmap = nbmap;
                 find_offset = oldsz; /* Start next search in the new portion. */
 
                 goto find_again;
@@ -141,45 +148,60 @@ find_again:
                return NULL;
        }
 
-       if ((mem_ctx=talloc_init("connection_struct"))==NULL) {
-               DEBUG(0,("talloc_init(connection_struct) failed!\n"));
+       if (!(conn=TALLOC_ZERO_P(NULL, connection_struct)) ||
+           !(conn->params = TALLOC_P(conn, struct share_params))) {
+               DEBUG(0,("TALLOC_ZERO() failed!\n"));
+               TALLOC_FREE(conn);
                return NULL;
        }
-
-       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->sconn = sconn;
        conn->cnum = i;
+       conn->force_group_gid = (gid_t)-1;
 
-       bitmap_set(bmap, i);
+       bitmap_set(sconn->smb1.tcons.bmap, i);
 
-       num_open++;
+       sconn->num_tcons_open++;
 
-       string_set(&conn->user,"");
-       string_set(&conn->dirpath,"");
        string_set(&conn->connectpath,"");
        string_set(&conn->origpath,"");
        
-       DLIST_ADD(Connections, conn);
+       DLIST_ADD(sconn->smb1.tcons.Connections, conn);
 
        return conn;
 }
 
 /****************************************************************************
  Close all conn structures.
+return true if any were closed
 ****************************************************************************/
-
-void conn_close_all(void)
+bool conn_close_all(struct smbd_server_connection *sconn)
 {
-       connection_struct *conn, *next;
-       for (conn=Connections;conn;conn=next) {
-               next=conn->next;
-               set_current_service(conn, 0, True);
-               close_cnum(conn, conn->vuid);
+       if (sconn->using_smb2) {
+               /* SMB2 */
+               if (sconn->smb2.sessions.list &&
+                               sconn->smb2.sessions.list->tcons.list) {
+                       struct smbd_smb2_tcon *tcon, *tc_next;
+
+                       for (tcon = sconn->smb2.sessions.list->tcons.list;
+                                       tcon; tcon = tc_next) {
+                               tc_next = tcon->next;
+                               TALLOC_FREE(tcon);
+                       }
+                       return true;
+               }
+               return false;
+       } else {
+               /* SMB1 */
+               connection_struct *conn, *next;
+               bool ret = false;
+
+               for (conn=sconn->smb1.tcons.Connections;conn;conn=next) {
+                       next=conn->next;
+                       set_current_service(conn, 0, True);
+                       close_cnum(conn, conn->vuid);
+                       ret = true;
+               }
+               return ret;
        }
 }
 
@@ -187,14 +209,17 @@ void conn_close_all(void)
  Idle inactive connections.
 ****************************************************************************/
 
-BOOL conn_idle_all(time_t t, int deadtime)
+bool conn_idle_all(struct smbd_server_connection *sconn,time_t t)
 {
-       pipes_struct *plist = NULL;
-       BOOL allidle = True;
-       connection_struct *conn, *next;
+       int deadtime = lp_deadtime()*60;
+       connection_struct *conn;
 
-       for (conn=Connections;conn;conn=next) {
-               next=conn->next;
+       if (deadtime <= 0)
+               deadtime = DEFAULT_SMBD_TIMEOUT;
+
+       for (conn=sconn->smb1.tcons.Connections;conn;conn=conn->next) {
+
+               time_t age = t - conn->lastused;
 
                /* Update if connection wasn't idle. */
                if (conn->lastused != conn->lastused_count) {
@@ -203,12 +228,12 @@ BOOL conn_idle_all(time_t t, int deadtime)
                }
 
                /* 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;
                }
        }
 
@@ -216,36 +241,26 @@ BOOL conn_idle_all(time_t t, int deadtime)
         * Check all pipes for any open handles. We cannot
         * idle with a handle open.
         */
+       if (check_open_pipes()) {
+               return False;
+       }
 
-       for (plist = get_first_internal_pipe(); plist; plist = get_next_internal_pipe(plist))
-               if (plist->pipe_handles && plist->pipe_handles->count)
-                       allidle = False;
-       
-       return allidle;
+       return True;
 }
 
 /****************************************************************************
  Clear a vuid out of the validity cache, and as the 'owner' of a connection.
 ****************************************************************************/
 
-void conn_clear_vuid_cache(uint16 vuid)
+void conn_clear_vuid_caches(struct smbd_server_connection *sconn,uint16_t vuid)
 {
        connection_struct *conn;
-       unsigned int i;
 
-       for (conn=Connections;conn;conn=conn->next) {
+       for (conn=sconn->smb1.tcons.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;
-                       }
-               }
+               conn_clear_vuid_cache(conn, vuid);
        }
 }
 
@@ -253,17 +268,16 @@ void conn_clear_vuid_cache(uint16 vuid)
  Free a conn structure - internal part.
 ****************************************************************************/
 
-void conn_free_internal(connection_struct *conn)
+static void conn_free_internal(connection_struct *conn)
 {
-       vfs_handle_struct *handle = NULL, *thandle = NULL;
-       TALLOC_CTX *mem_ctx = NULL;
+       vfs_handle_struct *handle = NULL, *thandle = 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;
+               DLIST_REMOVE(conn->vfs_handles, handle);
                if (handle->free_data)
                        handle->free_data(&handle->data);
                handle = thandle;
@@ -281,14 +295,11 @@ void conn_free_internal(connection_struct *conn)
        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);
+       talloc_destroy(conn);
 }
 
 /****************************************************************************
@@ -297,10 +308,28 @@ void conn_free_internal(connection_struct *conn)
 
 void conn_free(connection_struct *conn)
 {
-       DLIST_REMOVE(Connections, conn);
+       if (conn->sconn == NULL) {
+               conn_free_internal(conn);
+               return;
+       }
+
+       if (conn->sconn->using_smb2) {
+               conn_free_internal(conn);
+               return;
+       }
+
+       DLIST_REMOVE(conn->sconn->smb1.tcons.Connections, conn);
 
-       bitmap_clear(bmap, conn->cnum);
-       num_open--;
+       if (conn->sconn->smb1.tcons.bmap != NULL) {
+               /*
+                * Can be NULL for fake connections created by
+                * create_conn_struct()
+                */
+               bitmap_clear(conn->sconn->smb1.tcons.bmap, conn->cnum);
+       }
+
+       SMB_ASSERT(conn->sconn->num_tcons_open > 0);
+       conn->sconn->num_tcons_open--;
 
        conn_free_internal(conn);
 }
@@ -311,21 +340,31 @@ 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(int msg_type, struct process_id pid, void *buf, size_t len,
-                   void *private_data)
+void msg_force_tdis(struct messaging_context *msg,
+                   void *private_data,
+                   uint32_t msg_type,
+                   struct server_id server_id,
+                   DATA_BLOB *data)
 {
+       struct smbd_server_connection *sconn;
        connection_struct *conn, *next;
        fstring sharename;
 
-       fstrcpy(sharename, (const char *)buf);
+       sconn = msg_ctx_to_sconn(msg);
+       if (sconn == NULL) {
+               DEBUG(1, ("could not find sconn\n"));
+               return;
+       }
+
+       fstrcpy(sharename, (const char *)data->data);
 
        if (strcmp(sharename, "*") == 0) {
                DEBUG(1,("Forcing close of all shares\n"));
-               conn_close_all();
+               conn_close_all(sconn);
                return;
        }
 
-       for (conn=Connections;conn;conn=next) {
+       for (conn=sconn->smb1.tcons.Connections;conn;conn=next) {
                next=conn->next;
                if (strequal(lp_servicename(SNUM(conn)), sharename)) {
                        DEBUG(1,("Forcing close of share %s cnum=%d\n",