Fix error code when smbclient puts a file over an existing directory
[kai/samba.git] / source3 / smbd / conn.c
index bb000bac30ec86ee39045e3b3410911f51c48f66..7f34d2b8e2b3e9d1971c2bd9cb9a9e5057b1c32c 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
    
    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,
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
@@ -15,8 +15,7 @@
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    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 "includes.h"
@@ -53,21 +52,21 @@ int conn_num_open(void)
 /****************************************************************************
 check if a snum is in use
 ****************************************************************************/
 /****************************************************************************
 check if a snum is in use
 ****************************************************************************/
-BOOL conn_snum_used(int snum)
+bool conn_snum_used(int snum)
 {
        connection_struct *conn;
        for (conn=Connections;conn;conn=conn->next) {
 {
        connection_struct *conn;
        for (conn=Connections;conn;conn=conn->next) {
-               if (conn->service == snum) {
+               if (conn->params->service == snum) {
                        return(True);
                }
        }
        return(False);
 }
 
                        return(True);
                }
        }
        return(False);
 }
 
-
 /****************************************************************************
 /****************************************************************************
-find a conn given a cnum
+ Find a conn given a cnum.
 ****************************************************************************/
 ****************************************************************************/
+
 connection_struct *conn_find(unsigned cnum)
 {
        int count=0;
 connection_struct *conn_find(unsigned cnum)
 {
        int count=0;
@@ -85,7 +84,6 @@ connection_struct *conn_find(unsigned cnum)
        return NULL;
 }
 
        return NULL;
 }
 
-
 /****************************************************************************
   find first available connection slot, starting from a random position.
 The randomisation stops problems with the server dieing and clients
 /****************************************************************************
   find first available connection slot, starting from a random position.
 The randomisation stops problems with the server dieing and clients
@@ -93,7 +91,6 @@ thinking the server is still available.
 ****************************************************************************/
 connection_struct *conn_new(void)
 {
 ****************************************************************************/
 connection_struct *conn_new(void)
 {
-       TALLOC_CTX *mem_ctx;
        connection_struct *conn;
        int i;
         int find_offset = 1;
        connection_struct *conn;
        int i;
         int find_offset = 1;
@@ -107,7 +104,7 @@ find_again:
                 int             newsz = bmap->n + BITMAP_BLOCK_SZ;
                 struct bitmap * nbmap;
 
                 int             newsz = bmap->n + BITMAP_BLOCK_SZ;
                 struct bitmap * nbmap;
 
-                if (newsz <= 0) {
+                if (newsz <= oldsz) {
                         /* Integer wrap. */
                        DEBUG(0,("ERROR! Out of connection structures\n"));
                         return NULL;
                         /* Integer wrap. */
                        DEBUG(0,("ERROR! Out of connection structures\n"));
                         return NULL;
@@ -117,6 +114,10 @@ find_again:
                         oldsz, newsz));
 
                 nbmap = bitmap_allocate(newsz);
                         oldsz, newsz));
 
                 nbmap = bitmap_allocate(newsz);
+               if (!nbmap) {
+                       DEBUG(0,("ERROR! malloc fail.\n"));
+                       return NULL;
+               }
 
                 bitmap_copy(nbmap, bmap);
                 bitmap_free(bmap);
 
                 bitmap_copy(nbmap, bmap);
                 bitmap_free(bmap);
@@ -127,23 +128,28 @@ find_again:
                 goto find_again;
        }
 
                 goto find_again;
        }
 
-       if ((mem_ctx=talloc_init("connection_struct"))==NULL) {
-               DEBUG(0,("talloc_init(connection_struct) failed!\n"));
+       /* 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;
        }
 
                return NULL;
        }
 
-       if ((conn=TALLOC_ZERO_P(mem_ctx, connection_struct))==NULL) {
-               DEBUG(0,("talloc_zero() 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;
        }
                return NULL;
        }
-       conn->mem_ctx = mem_ctx;
        conn->cnum = i;
 
        bitmap_set(bmap, i);
 
        num_open++;
 
        conn->cnum = i;
 
        bitmap_set(bmap, i);
 
        num_open++;
 
-       string_set(&conn->user,"");
        string_set(&conn->dirpath,"");
        string_set(&conn->connectpath,"");
        string_set(&conn->origpath,"");
        string_set(&conn->dirpath,"");
        string_set(&conn->connectpath,"");
        string_set(&conn->origpath,"");
@@ -154,37 +160,53 @@ find_again:
 }
 
 /****************************************************************************
 }
 
 /****************************************************************************
-close all conn structures
+ Close all conn structures.
+return true if any were closed
 ****************************************************************************/
 ****************************************************************************/
-void conn_close_all(void)
+bool conn_close_all(void)
 {
        connection_struct *conn, *next;
 {
        connection_struct *conn, *next;
+       bool ret = false;
        for (conn=Connections;conn;conn=next) {
                next=conn->next;
                set_current_service(conn, 0, True);
                close_cnum(conn, conn->vuid);
        for (conn=Connections;conn;conn=next) {
                next=conn->next;
                set_current_service(conn, 0, True);
                close_cnum(conn, conn->vuid);
+               ret = true;
        }
        }
+       return ret;
 }
 
 /****************************************************************************
  Idle inactive connections.
 ****************************************************************************/
 
 }
 
 /****************************************************************************
  Idle inactive connections.
 ****************************************************************************/
 
-BOOL conn_idle_all(time_t t, int deadtime)
+bool conn_idle_all(time_t t)
 {
 {
+       int deadtime = lp_deadtime()*60;
        pipes_struct *plist = NULL;
        pipes_struct *plist = NULL;
-       BOOL allidle = True;
-       connection_struct *conn, *next;
+       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 */
                /* close dirptrs on connections that are idle */
-               if ((t-conn->lastused) > DPTR_IDLE_TIMEOUT)
+               if (age > DPTR_IDLE_TIMEOUT) {
                        dptr_idlecnum(conn);
                        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;
+               }
        }
 
        /*
        }
 
        /*
@@ -192,35 +214,29 @@ BOOL conn_idle_all(time_t t, int deadtime)
         * idle with a handle open.
         */
 
         * 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)
-                       allidle = False;
+       for (plist = get_first_internal_pipe(); plist;
+            plist = get_next_internal_pipe(plist)) {
+               if (plist->pipe_handles && plist->pipe_handles->count) {
+                       return False;
+               }
+       }
        
        
-       return allidle;
+       return True;
 }
 
 /****************************************************************************
  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)
+void conn_clear_vuid_caches(uint16_t vuid)
 {
        connection_struct *conn;
 {
        connection_struct *conn;
-       unsigned int i;
 
        for (conn=Connections;conn;conn=conn->next) {
                if (conn->vuid == vuid) {
                        conn->vuid = UID_FIELD_INVALID;
                }
 
        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;
-                       }
-               }
+               conn_clear_vuid_cache(conn, vuid);
        }
 }
 
        }
 }
 
@@ -231,25 +247,23 @@ void conn_clear_vuid_cache(uint16 vuid)
 void conn_free_internal(connection_struct *conn)
 {
        vfs_handle_struct *handle = NULL, *thandle = NULL;
 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) {
 
        /* Free vfs_connection_struct */
        handle = conn->vfs_handles;
        while(handle) {
-               DLIST_REMOVE(conn->vfs_handles, handle);
                thandle = handle->next;
                thandle = handle->next;
+               DLIST_REMOVE(conn->vfs_handles, handle);
                if (handle->free_data)
                        handle->free_data(&handle->data);
                handle = thandle;
        }
 
                if (handle->free_data)
                        handle->free_data(&handle->data);
                handle = thandle;
        }
 
-       if (conn->ngroups && conn->groups) {
-               SAFE_FREE(conn->groups);
-               conn->ngroups = 0;
-       }
-
-       if (conn->nt_user_token) {
-               delete_nt_token(&(conn->nt_user_token));
+       /* 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->veto_list);
@@ -257,14 +271,12 @@ void conn_free_internal(connection_struct *conn)
        free_namearray(conn->veto_oplock_list);
        free_namearray(conn->aio_write_behind_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);
 
        string_free(&conn->dirpath);
        string_free(&conn->connectpath);
        string_free(&conn->origpath);
 
-       mem_ctx = conn->mem_ctx;
        ZERO_STRUCTP(conn);
        ZERO_STRUCTP(conn);
-       talloc_destroy(mem_ctx);
+       talloc_destroy(conn);
 }
 
 /****************************************************************************
 }
 
 /****************************************************************************
@@ -276,6 +288,8 @@ void conn_free(connection_struct *conn)
        DLIST_REMOVE(Connections, conn);
 
        bitmap_clear(bmap, conn->cnum);
        DLIST_REMOVE(Connections, conn);
 
        bitmap_clear(bmap, conn->cnum);
+
+       SMB_ASSERT(num_open > 0);
        num_open--;
 
        conn_free_internal(conn);
        num_open--;
 
        conn_free_internal(conn);
@@ -287,12 +301,16 @@ the message contains just a share name and all instances of that
 share are unmounted
 the special sharename '*' forces unmount of all shares
 ****************************************************************************/
 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 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;
 
 {
        connection_struct *conn, *next;
        fstring sharename;
 
-       fstrcpy(sharename, (const char *)buf);
+       fstrcpy(sharename, (const char *)data->data);
 
        if (strcmp(sharename, "*") == 0) {
                DEBUG(1,("Forcing close of all shares\n"));
 
        if (strcmp(sharename, "*") == 0) {
                DEBUG(1,("Forcing close of all shares\n"));
@@ -302,7 +320,7 @@ void msg_force_tdis(int msg_type, struct process_id pid, void *buf, size_t len)
 
        for (conn=Connections;conn;conn=next) {
                next=conn->next;
 
        for (conn=Connections;conn;conn=next) {
                next=conn->next;
-               if (strequal(lp_servicename(conn->service), sharename)) {
+               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);
                        DEBUG(1,("Forcing close of share %s cnum=%d\n",
                                 sharename, conn->cnum));
                        close_cnum(conn, (uint16)-1);