s3:count_current_connections: do not clear orphaned entries from connections.tdb
[mat/samba.git] / source3 / smbd / connection.c
index 9653723e13fac3e0b9c72ef5b0620a46eb61323b..ac2ab955d2bcce9670bd434d63ea8a3a277f91c3 100644 (file)
 */
 
 #include "includes.h"
+#include "smbd/smbd.h"
 #include "smbd/globals.h"
-#include "dbwrap.h"
+#include "dbwrap/dbwrap.h"
+#include "auth.h"
+#include "../lib/tsocket/tsocket.h"
+#include "messages.h"
+#include "lib/conn_tdb.h"
 
 /****************************************************************************
  Delete a connection record.
@@ -38,7 +43,7 @@ bool yield_connection(connection_struct *conn, const char *name)
                return False;
        }
 
-       status = rec->delete_rec(rec);
+       status = dbwrap_record_delete(rec);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG( NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND) ? 3 : 0,
                       ("deleting connection record returned %s\n",
@@ -52,42 +57,30 @@ bool yield_connection(connection_struct *conn, const char *name)
 struct count_stat {
        int curr_connections;
        const char *name;
-       bool Clear;
+       bool verify;
 };
 
 /****************************************************************************
  Count the entries belonging to a service in the connection db.
 ****************************************************************************/
 
-static int count_fn(struct db_record *rec,
-                   const struct connections_key *ckey,
+static int count_fn(const struct connections_key *ckey,
                    const struct connections_data *crec,
                    void *udp)
 {
        struct count_stat *cs = (struct count_stat *)udp;
 
-       if (crec->cnum == -1) {
+       if (crec->cnum == TID_FIELD_INVALID) {
                return 0;
        }
 
-       /* If the pid was not found delete the entry from connections.tdb */
-
-       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));
-
-               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)));
-               }
+       if (cs->verify && !process_exists(crec->pid)) {
                return 0;
        }
 
-       if (strequal(crec->servicename, cs->name))
+       if (strequal(crec->servicename, cs->name)) {
                cs->curr_connections++;
+       }
 
        return 0;
 }
@@ -96,28 +89,50 @@ static int count_fn(struct db_record *rec,
  Claim an entry in the connections database.
 ****************************************************************************/
 
-int count_current_connections( const char *sharename, bool clear  )
+int count_current_connections(const char *sharename, bool verify)
 {
        struct count_stat cs;
+       int ret;
 
        cs.curr_connections = 0;
        cs.name = sharename;
-       cs.Clear = clear;
+       cs.verify = verify;
 
        /*
         * This has a race condition, but locking the chain before hand is worse
         * as it leads to deadlock.
         */
 
-       if (connections_forall(count_fn, &cs) == -1) {
+       /*
+        * become_root() because we might have to open connections.tdb
+        * via ctdb, which is not possible without root.
+        */
+       become_root();
+       ret = connections_forall_read(count_fn, &cs);
+       unbecome_root();
+
+       if (ret < 0) {
                DEBUG(0,("count_current_connections: traverse of "
                         "connections.tdb failed\n"));
-               return False;
+               return 0;
        }
 
        return cs.curr_connections;
 }
 
+bool connections_snum_used(struct smbd_server_connection *unused, int snum)
+{
+       int active;
+
+       active = count_current_connections(lp_servicename(talloc_tos(), snum),
+                                          true);
+       if (active > 0) {
+               return true;
+       }
+
+       return false;
+}
+
 /****************************************************************************
  Claim an entry in the connections database.
 ****************************************************************************/
@@ -126,6 +141,7 @@ bool claim_connection(connection_struct *conn, const char *name)
 {
        struct db_record *rec;
        struct connections_data crec;
+       char *raddr;
        TDB_DATA dbuf;
        NTSTATUS status;
 
@@ -136,24 +152,33 @@ bool claim_connection(connection_struct *conn, const char *name)
                return False;
        }
 
+       /* Make clear that we require the optional unix_token in the source3 code */
+       SMB_ASSERT(conn->session_info->unix_token);
+
        /* fill in the crec */
        ZERO_STRUCT(crec);
        crec.magic = 0x280267;
-       crec.pid = sconn_server_id(conn->sconn);
+       crec.pid = messaging_server_id(conn->sconn->msg_ctx);
        crec.cnum = conn->cnum;
-       crec.uid = conn->server_info->utok.uid;
-       crec.gid = conn->server_info->utok.gid;
-       strlcpy(crec.servicename, lp_servicename(SNUM(conn)),
+       crec.uid = conn->session_info->unix_token->uid;
+       crec.gid = conn->session_info->unix_token->gid;
+       strlcpy(crec.servicename, lp_servicename(rec, SNUM(conn)),
                sizeof(crec.servicename));
        crec.start = time(NULL);
 
+       raddr = tsocket_address_inet_addr_string(conn->sconn->remote_address,
+                                                rec);
+       if (raddr == NULL) {
+               return false;
+       }
+
        strlcpy(crec.machine,get_remote_machine_name(),sizeof(crec.machine));
-       strlcpy(crec.addr, conn->sconn->client_id.addr, sizeof(crec.addr));
+       strlcpy(crec.addr, raddr, sizeof(crec.addr));
 
        dbuf.dptr = (uint8 *)&crec;
        dbuf.dsize = sizeof(crec);
 
-       status = rec->store(rec, dbuf, TDB_REPLACE);
+       status = dbwrap_record_store(rec, dbuf, TDB_REPLACE);
 
        TALLOC_FREE(rec);