smbd: some write time fixes
[tprouty/samba.git] / source / smbd / connection.c
index 1069f95ed83ea7da81079201d2d970f3b586c7eb..d7063c99894bcfd948d5c48d3162feea5b0c35a5 100644 (file)
@@ -5,7 +5,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"
 
-static void make_conn_key(connection_struct *conn, const char *name, TDB_DATA *pkbuf, struct connections_key *pkey)
-{
-       ZERO_STRUCTP(pkey);
-       pkey->pid = procid_self();
-       pkey->cnum = conn?conn->cnum:-1;
-       fstrcpy(pkey->name, name);
-#ifdef DEVELOPER
-       /* valgrind fixer... */
-       {
-               size_t sl = strlen(pkey->name);
-               if (sizeof(fstring)-sl)
-                       memset(&pkey->name[sl], '\0', sizeof(fstring)-sl);
-       }
-#endif
-
-       pkbuf->dptr = (uint8 *)pkey;
-       pkbuf->dsize = sizeof(*pkey);
-}
-
 /****************************************************************************
  Delete a connection record.
 ****************************************************************************/
 
-BOOL yield_connection(connection_struct *conn, const char *name)
+bool yield_connection(connection_struct *conn, const char *name)
 {
-       struct connections_key key;
-       TDB_DATA kbuf;
-       TDB_CONTEXT *tdb = conn_tdb_ctx(True);
-
-       if (!tdb)
-               return False;
+       struct db_record *rec;
+       NTSTATUS status;
 
        DEBUG(3,("Yielding connection to %s\n",name));
 
-       make_conn_key(conn, name, &kbuf, &key);
+       if (!(rec = connections_fetch_entry(NULL, conn, name))) {
+               DEBUG(0, ("connections_fetch_entry failed\n"));
+               return False;
+       }
 
-       if (tdb_delete(tdb, kbuf) != 0) {
-               int dbg_lvl = (!conn && (tdb_error(tdb) == TDB_ERR_NOEXIST)) ? 3 : 0;
-               DEBUG(dbg_lvl,("yield_connection: tdb_delete for name %s failed with error %s.\n",
-                       name, tdb_errorstr(tdb) ));
-               return (False);
+       status = rec->delete_rec(rec);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG( NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND) ? 3 : 0,
+                      ("deleting connection record returned %s\n",
+                       nt_errstr(status)));
        }
 
-       return(True);
+       TALLOC_FREE(rec);
+       return NT_STATUS_IS_OK(status);
 }
 
 struct count_stat {
        pid_t mypid;
        int curr_connections;
        const char *name;
-       BOOL Clear;
+       bool Clear;
 };
 
 /****************************************************************************
  Count the entries belonging to a service in the connection db.
 ****************************************************************************/
 
-static int count_fn( TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *udp)
+static int count_fn(struct db_record *rec,
+                   const struct connections_key *ckey,
+                   const struct connections_data *crec,
+                   void *udp)
 {
-       struct connections_data crec;
        struct count_stat *cs = (struct count_stat *)udp;
  
-       if (dbuf.dsize != sizeof(crec)) {
-               return 0;
-       }
-
-       memcpy(&crec, dbuf.dptr, sizeof(crec));
-       if (crec.cnum == -1) {
+       if (crec->cnum == -1) {
                return 0;
        }
 
        /* If the pid was not found delete the entry from connections.tdb */
 
-       if (cs->Clear && !process_exists(crec.pid) && (errno == ESRCH)) {
+       if (cs->Clear && !process_exists(crec->pid) && (errno == ESRCH)) {
+               NTSTATUS status;
                DEBUG(2,("pid %s doesn't exist - deleting connections %d [%s]\n",
-                       procid_str_static(&crec.pid), crec.cnum, crec.servicename));
-               if (tdb_delete(the_tdb, kbuf) != 0)
-                       DEBUG(0,("count_fn: tdb_delete failed with error %s\n", tdb_errorstr(the_tdb) ));
+                        procid_str_static(&crec->pid), crec->cnum,
+                        crec->servicename));
+
+               status = rec->delete_rec(rec);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0,("count_fn: tdb_delete failed with error %s\n",
+                                nt_errstr(status)));
+               }
                return 0;
        }
-       if (cs->name) {
-               /* We are counting all the connections to a given share. */
-               if (strequal(crec.servicename, cs->name)) {
-                       cs->curr_connections++;
-               }
-       } else {
-               /* We are counting all the connections. Static registrations
-                * like the lpq backgroud process and the smbd daemon process
-                * have a cnum of -1, so won't be counted here.
-                */
+
+       if (strequal(crec->servicename, cs->name))
                cs->curr_connections++;
-       }
 
        return 0;
 }
@@ -122,10 +94,9 @@ static int count_fn( TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *u
  Claim an entry in the connections database.
 ****************************************************************************/
 
-int count_current_connections( const char *sharename, BOOL clear  )
+int count_current_connections( const char *sharename, bool clear  )
 {
        struct count_stat cs;
-       TDB_CONTEXT *tdb = conn_tdb_ctx(True);
 
        cs.mypid = sys_getpid();
        cs.curr_connections = 0;
@@ -137,19 +108,12 @@ int count_current_connections( const char *sharename, BOOL clear  )
         * as it leads to deadlock.
         */
 
-       if (tdb_traverse(tdb, count_fn, &cs) == -1) {
-               DEBUG(0,("count_current_connections: traverse of connections.tdb failed with error %s\n",
-                       tdb_errorstr(tdb) ));
-               DEBUGADD(0, ("count_current_connections: connection count of %d might not be accurate",
-                           cs.curr_connections));
+       if (connections_forall(count_fn, &cs) == -1) {
+               DEBUG(0,("count_current_connections: traverse of "
+                        "connections.tdb failed\n"));
+               return False;
        }
 
-       /* If the traverse failed part-way through, we at least return
-        * as many connections as we had already counted. If it failed
-        * right at the start, we will return 0, which is about all we
-        * can do anywway.
-        */
-
        return cs.curr_connections;
 }
 
@@ -159,45 +123,29 @@ int count_current_connections( const char *sharename, BOOL clear  )
 
 int count_all_current_connections(void)
 {
-       return count_current_connections(NULL, True /* clear stale entries */);
+        return count_current_connections(NULL, True /* clear stale entries */);
 }
 
 /****************************************************************************
  Claim an entry in the connections database.
 ****************************************************************************/
 
-BOOL claim_connection(connection_struct *conn, const char *name,
-                     int max_connections, uint32 msg_flags)
+bool claim_connection(connection_struct *conn, const char *name,
+                     uint32 msg_flags)
 {
-       struct connections_key key;
+       struct db_record *rec;
        struct connections_data crec;
-       TDB_DATA kbuf, dbuf;
-       TDB_CONTEXT *tdb = conn_tdb_ctx(True);
+       TDB_DATA dbuf;
+       NTSTATUS status;
+       char addr[INET6_ADDRSTRLEN];
 
-       if (!tdb) {
-               return False;
-       }
-       
-       /*
-        * Enforce the max connections parameter.
-        */
-
-       if (max_connections > 0) {
-               int curr_connections;
-               
-               curr_connections = count_current_connections( lp_servicename(SNUM(conn)), True );
+       DEBUG(5,("claiming [%s]\n", name));
 
-               if (curr_connections >= max_connections) {
-                       DEBUG(1,("claim_connection: Max connections (%d) exceeded for %s\n",
-                               max_connections, name ));
-                       return False;
-               }
+       if (!(rec = connections_fetch_entry(talloc_tos(), conn, name))) {
+               DEBUG(0, ("connections_fetch_entry failed\n"));
+               return False;
        }
 
-       DEBUG(5,("claiming %s %d\n",name,max_connections));
-
-       make_conn_key(conn, name, &kbuf, &key);
-
        /* fill in the crec */
        ZERO_STRUCT(crec);
        crec.magic = 0x280267;
@@ -206,67 +154,74 @@ BOOL claim_connection(connection_struct *conn, const char *name,
        if (conn) {
                crec.uid = conn->uid;
                crec.gid = conn->gid;
-               safe_strcpy(crec.servicename,
-                           lp_servicename(SNUM(conn)),sizeof(crec.servicename)-1);
+               strlcpy(crec.servicename, lp_servicename(SNUM(conn)),
+                       sizeof(crec.servicename));
        }
        crec.start = time(NULL);
        crec.bcast_msg_flags = msg_flags;
        
-       safe_strcpy(crec.machine,get_remote_machine_name(),sizeof(crec.machine)-1);
-       safe_strcpy(crec.addr,conn?conn->client_address:client_addr(),sizeof(crec.addr)-1);
+       strlcpy(crec.machine,get_remote_machine_name(),sizeof(crec.machine));
+       strlcpy(crec.addr,conn?conn->client_address:
+                       client_addr(get_client_fd(),addr,sizeof(addr)),
+               sizeof(crec.addr));
 
        dbuf.dptr = (uint8 *)&crec;
        dbuf.dsize = sizeof(crec);
 
-       if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) {
+       status = rec->store(rec, dbuf, TDB_REPLACE);
+
+       TALLOC_FREE(rec);
+
+       if (!NT_STATUS_IS_OK(status)) {
                DEBUG(0,("claim_connection: tdb_store failed with error %s.\n",
-                       tdb_errorstr(tdb) ));
+                        nt_errstr(status)));
                return False;
        }
 
        return True;
 }
 
-BOOL register_message_flags(BOOL doreg, uint32 msg_flags)
+bool register_message_flags(bool doreg, uint32 msg_flags)
 {
-       struct connections_key key;
+       struct db_record *rec;
        struct connections_data *pcrec;
-       TDB_DATA kbuf, dbuf;
-       TDB_CONTEXT *tdb = conn_tdb_ctx(True);
-
-       if (!tdb)
-               return False;
+       NTSTATUS status;
 
        DEBUG(10,("register_message_flags: %s flags 0x%x\n",
                doreg ? "adding" : "removing",
                (unsigned int)msg_flags ));
 
-       make_conn_key(NULL, "", &kbuf, &key);
+       if (!(rec = connections_fetch_entry(NULL, NULL, ""))) {
+               DEBUG(0, ("connections_fetch_entry failed\n"));
+               return False;
+       }
 
-        dbuf = tdb_fetch(tdb, kbuf);
-        if (!dbuf.dptr) {
-               DEBUG(0,("register_message_flags: tdb_fetch failed: %s\n",
-                       tdb_errorstr(tdb)));
+       if (rec->value.dsize != sizeof(struct connections_data)) {
+               DEBUG(0,("register_message_flags: Got wrong record size\n"));
+               TALLOC_FREE(rec);
                return False;
        }
 
-       pcrec = (struct connections_data *)dbuf.dptr;
+       pcrec = (struct connections_data *)rec->value.dptr;
        if (doreg)
                pcrec->bcast_msg_flags |= msg_flags;
        else
                pcrec->bcast_msg_flags &= ~msg_flags;
 
-       if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) {
+       status = rec->store(rec, rec->value, TDB_REPLACE);
+
+       if (!NT_STATUS_IS_OK(status)) {
                DEBUG(0,("register_message_flags: tdb_store failed: %s.\n",
-                       tdb_errorstr(tdb) ));
-               SAFE_FREE(dbuf.dptr);
+                        nt_errstr(status)));
+               TALLOC_FREE(rec);
                return False;
        }
 
        DEBUG(10,("register_message_flags: new flags 0x%x\n",
                (unsigned int)pcrec->bcast_msg_flags ));
 
-       SAFE_FREE(dbuf.dptr);
+       TALLOC_FREE(rec);
+
        return True;
 }
 
@@ -311,13 +266,13 @@ static void fill_pipe_open_rec( struct pipe_open_rec *prec, smb_np_struct *p )
 /*********************************************************************
 *********************************************************************/
 
-BOOL store_pipe_opendb( smb_np_struct *p )
+bool store_pipe_opendb( smb_np_struct *p )
 {
+       struct db_record *dbrec;
        struct pipe_open_rec *prec;
        TDB_DATA *key;
        TDB_DATA data;
-       TDB_CONTEXT *pipe_tdb;
-       BOOL ret = False;
+       bool ret = False;
        
        if ( (prec = TALLOC_P( NULL, struct pipe_open_rec)) == NULL ) {
                DEBUG(0,("store_pipe_opendb: talloc failed!\n"));
@@ -331,12 +286,13 @@ BOOL store_pipe_opendb( smb_np_struct *p )
        
        data.dptr = (uint8 *)prec;
        data.dsize = sizeof(struct pipe_open_rec);
-       
-       if ( (pipe_tdb = conn_tdb_ctx(True) ) == NULL ) {
+
+       if (!(dbrec = connections_fetch_record(prec, *key))) {
+               DEBUG(0, ("connections_fetch_record failed\n"));
                goto done;
        }
-       
-       ret = (tdb_store( pipe_tdb, *key, data, TDB_REPLACE ) != -1);
+
+       ret = NT_STATUS_IS_OK(dbrec->store(dbrec, data, TDB_REPLACE));
        
 done:
        TALLOC_FREE( prec );    
@@ -346,12 +302,12 @@ done:
 /*********************************************************************
 *********************************************************************/
 
-BOOL delete_pipe_opendb( smb_np_struct *p )
+bool delete_pipe_opendb( smb_np_struct *p )
 {
+       struct db_record *dbrec;
        struct pipe_open_rec *prec;
        TDB_DATA *key;
-       TDB_CONTEXT *pipe_tdb;
-       BOOL ret = False;
+       bool ret = False;
        
        if ( (prec = TALLOC_P( NULL, struct pipe_open_rec)) == NULL ) {
                DEBUG(0,("store_pipe_opendb: talloc failed!\n"));
@@ -363,11 +319,12 @@ BOOL delete_pipe_opendb( smb_np_struct *p )
                goto done;
        }
        
-       if ( (pipe_tdb = conn_tdb_ctx(True) ) == NULL ) {
+       if (!(dbrec = connections_fetch_record(prec, *key))) {
+               DEBUG(0, ("connections_fetch_record failed\n"));
                goto done;
        }
 
-       ret = (tdb_delete( pipe_tdb, *key ) != -1 );
+       ret = NT_STATUS_IS_OK(dbrec->delete_rec(dbrec));
        
 done:
        TALLOC_FREE( prec );