make sam_account_ok static.
[ira/wip.git] / source3 / smbd / connection.c
index 972ffa52ddecd12afc90692bbe9c423aa3d17614..c0eaf8187dbedbac391608172b3b124e2e4afb88 100644 (file)
 
 #include "includes.h"
 
-
 extern fstring remote_machine;
 static TDB_CONTEXT *tdb;
 
-extern int DEBUGLEVEL;
+/****************************************************************************
+ Return the connection tdb context (used for message send all).
+****************************************************************************/
 
-#ifdef WITH_UTMP
-static void utmp_yield(pid_t pid, const connection_struct *conn);
-static void utmp_claim(const struct connections_data *crec, const connection_struct *conn);
-#endif
+TDB_CONTEXT *conn_tdb_ctx(void)
+{
+       return tdb;
+}
 
 /****************************************************************************
-delete a connection record
+ Delete a connection record.
 ****************************************************************************/
+
 BOOL yield_connection(connection_struct *conn,char *name,int max_connections)
 {
        struct connections_key key;
@@ -45,47 +47,114 @@ BOOL yield_connection(connection_struct *conn,char *name,int max_connections)
        DEBUG(3,("Yielding connection to %s\n",name));
 
        ZERO_STRUCT(key);
-       key.pid = getpid();
-       if (conn) key.cnum = conn->cnum;
+       key.pid = sys_getpid();
+       key.cnum = conn?conn->cnum:-1;
        fstrcpy(key.name, name);
 
        kbuf.dptr = (char *)&key;
        kbuf.dsize = sizeof(key);
 
-       tdb_delete(tdb, kbuf);
-
-#ifdef WITH_UTMP
-       if(conn)
-               utmp_yield(key.pid, conn);
-#endif
+       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);
+       }
 
        return(True);
 }
 
+struct count_stat {
+       pid_t mypid;
+       int curr_connections;
+       char *name;
+       BOOL Clear;
+};
 
 /****************************************************************************
-claim an entry in the connections database
+ 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)
+{
+       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)
+               return 0;
+
+       /* If the pid was not found delete the entry from connections.tdb */
+
+       if (cs->Clear && !process_exists(crec.pid) && (errno == ESRCH)) {
+               DEBUG(2,("pid %u doesn't exist - deleting connections %d [%s]\n",
+                       (unsigned int)crec.pid, crec.cnum, crec.name));
+               if (tdb_delete(the_tdb, kbuf) != 0)
+                       DEBUG(0,("count_fn: tdb_delete failed with error %s\n", tdb_errorstr(tdb) ));
+               return 0;
+       }
+
+       if (strequal(crec.name, cs->name))
+               cs->curr_connections++;
+
+       return 0;
+}
+
+/****************************************************************************
+ Claim an entry in the connections database.
+****************************************************************************/
+
 BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOOL Clear)
 {
        struct connections_key key;
        struct connections_data crec;
        TDB_DATA kbuf, dbuf;
-       extern int Client;
-
-       if (max_connections <= 0)
-               return(True);
 
        if (!tdb) {
-               tdb = tdb_open(lock_path("connections.tdb"), 0, TDB_CLEAR_IF_FIRST, 
+               tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT, 
                               O_RDWR | O_CREAT, 0644);
        }
-       if (!tdb) return False;
+       if (!tdb)
+               return False;
+
+       /*
+        * Enforce the max connections parameter.
+        */
+
+       if (max_connections > 0) {
+               struct count_stat cs;
+
+               cs.mypid = sys_getpid();
+               cs.curr_connections = 0;
+               cs.name = lp_servicename(SNUM(conn));
+               cs.Clear = Clear;
+
+               /*
+                * This has a race condition, but locking the chain before hand is worse
+                * as it leads to deadlock.
+                */
+
+               if (tdb_traverse(tdb, count_fn, &cs) == -1) {
+                       DEBUG(0,("claim_connection: traverse of connections.tdb failed with error %s.\n",
+                               tdb_errorstr(tdb) ));
+                       return False;
+               }
+
+               if (cs.curr_connections >= max_connections) {
+                       DEBUG(1,("claim_connection: Max connections (%d) exceeded for %s\n",
+                               max_connections, name ));
+                       return False;
+               }
+       }
 
        DEBUG(5,("claiming %s %d\n",name,max_connections));
 
        ZERO_STRUCT(key);
-       key.pid = getpid();
+       key.pid = sys_getpid();
        key.cnum = conn?conn->cnum:-1;
        fstrcpy(key.name, name);
 
@@ -95,7 +164,7 @@ BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOO
        /* fill in the crec */
        ZERO_STRUCT(crec);
        crec.magic = 0x280267;
-       crec.pid = getpid();
+       crec.pid = sys_getpid();
        crec.cnum = conn?conn->cnum:-1;
        if (conn) {
                crec.uid = conn->uid;
@@ -106,215 +175,16 @@ BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOO
        crec.start = time(NULL);
        
        StrnCpy(crec.machine,remote_machine,sizeof(crec.machine)-1);
-       StrnCpy(crec.addr,conn?conn->client_address:client_addr(Client),sizeof(crec.addr)-1);
+       StrnCpy(crec.addr,conn?conn->client_address:client_addr(),sizeof(crec.addr)-1);
 
        dbuf.dptr = (char *)&crec;
        dbuf.dsize = sizeof(crec);
 
-       if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) return False;
-
-#ifdef WITH_UTMP
-       if (conn)
-           utmp_claim(&crec, conn);
-#endif
-
-       return True;
-}
-
-#ifdef WITH_UTMP
-
-/****************************************************************************
-Reflect connection status in utmp/wtmp files.
-       T.D.Lee@durham.ac.uk  September 1999
-
-Hints for porting:
-       o Always attempt to use programmatic interface (pututline() etc.)
-       o The "x" (utmpx/wtmpx; HAVE_UTMPX_H) seems preferable.
-
-OS status:
-       Solaris 2.x:  Tested on 2.6 and 2.7; should be OK on other flavours.
-               T.D.Lee@durham.ac.uk
-       HPUX 9.x:  Not tested.  Appears not to have "x".
-       IRIX 6.5:  Not tested.  Appears to have "x".
-
-Notes:
-       The 4 byte 'ut_id' component is vital to distinguish connections,
-       of which there could be several hundered or even thousand.
-       Entries seem to be printable characters, with optional NULL pads.
-
-       We need to be distinct from other entries in utmp/wtmp.
-
-       Observed things: therefore avoid them.  Add to this list please.
-       From Solaris 2.x (because that's what I have):
-               'sN'    : run-levels; N: [0-9]
-               'co'    : console
-               'CC'    : arbitrary things;  C: [a-z]
-               'rXNN'  : rlogin;  N: [0-9]; X: [0-9a-z]
-               'tXNN'  : rlogin;  N: [0-9]; X: [0-9a-z]
-               '/NNN'  : Solaris CDE
-               'ftpZ'  : ftp (Z is the number 255, aka 0377, aka 0xff)
-       Mostly a record uses the same 'ut_id' in both "utmp" and "wtmp",
-       but differences have been seen.
-
-       Arbitrarily I have chosen to use a distinctive 'SM' for the
-       first two bytes.
-
-       The remaining two encode the connection number used in samba locking
-       functions "claim_connection() and "yield_connection()".  This seems
-       to be a "nicely behaved" number: starting from 0 then working up
-       looking for an available slot.
-
-****************************************************************************/
-
-#include <utmp.h>
-
-#ifdef HAVE_UTMPX_H
-#include <utmpx.h>
-#endif
-
-static const char *ut_id_encstr =
-       "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
-
-static
-int
-ut_id_encode(int i, char *fourbyte)
-{
-       int nbase;
-
-       fourbyte[0] = 'S';
-       fourbyte[1] = 'M';
-
-/*
- * Encode remaining 2 bytes from 'i'.
- * 'ut_id_encstr' is the character set on which modulo arithmetic is done.
- * Example: digits would produce the base-10 numbers from '001'.
- */
-       nbase = strlen(ut_id_encstr);
-
-       fourbyte[3] = ut_id_encstr[i % nbase];
-       i /= nbase;
-       fourbyte[2] = ut_id_encstr[i % nbase];
-       i /= nbase;
-
-       return(i);      /* 0: good; else overflow */
-}
-
-static int utmp_fill(struct utmp *u, const connection_struct *conn, pid_t pid, int i)
-{
-       struct timeval timeval;
-       int rc;
-
-       pstrcpy(u->ut_user, conn->user);
-       rc = ut_id_encode(i, u->ut_id);
-       slprintf(u->ut_line, 12, "smb/%d", i);
-
-       u->ut_pid = pid;
-
-       gettimeofday(&timeval, NULL);
-       u->ut_time = timeval.tv_sec;
-
-       return(rc);
-}
-
-static void utmp_update(const pstring dirname, const struct utmp *u, const char *host)
-{
-       pstring fname;
-
-#ifdef HAVE_UTMPX_H
-       struct utmpx ux, *uxrc;
-
-       getutmpx(u, &ux);
-       if (host) {
-#if defined(HAVE_UX_UT_SYSLEN)
-               ux.ut_syslen = strlen(host);
-#endif /* defined(HAVE_UX_UT_SYSLEN) */
-               pstrcpy(ux.ut_host, host);
-       }
-
-       pstrcpy(fname, dirname);
-       pstrcat(fname, "utmpx");
-       utmpxname(fname);
-       uxrc = pututxline(&ux);
-       if (uxrc == NULL) {
-               DEBUG(2,("utmp_update: pututxline() failed\n"));
-               return;
-       }
-
-       pstrcpy(fname, dirname);
-       pstrcat(fname, "wtmpx");
-       updwtmpx(fname, &ux);
-#else
-       pstrcpy(fname, dirname);
-       pstrcat(fname, "utmp");
-
-       utmpname(fname);
-       pututline(u);
-
-       pstrcpy(fname, dirname);
-       pstrcat(fname, "wtmp");
-
-       /* *** OK.  Appending wtmp (as distinct from overwriting utmp) has
-       me baffled.  How is it to be done? *** */
-#endif
-}
-
-static void utmp_yield(int pid, const connection_struct *conn)
-{
-       struct utmp u;
-       pstring dirname;
-
-       if (! lp_utmp(SNUM(conn))) {
-               DEBUG(2,("utmp_yield: lp_utmp() NULL\n"));
-               return;
-       }
-
-       pstrcpy(dirname,lp_utmpdir());
-       trim_string(dirname,"","/");
-       pstrcat(dirname,"/");
-
-       DEBUG(2,("utmp_yield: dir:%s conn: user:%s cnum:%d i:%d\n",
-         dirname, conn->user, conn->cnum, conn->cnum));
-
-       memset((char *)&u, '\0', sizeof(struct utmp));
-       u.ut_type = DEAD_PROCESS;
-       u.ut_exit.e_termination = 0;
-       u.ut_exit.e_exit = 0;
-       if (utmp_fill(&u, conn, pid, conn->cnum) == 0) {
-               utmp_update(dirname, &u, NULL);
-       }
-}
-
-static void utmp_claim(const struct connections_data *crec, const connection_struct *conn)
-{
-       extern int Client;
-       struct utmp u;
-       pstring dirname;
-
-       if (conn == NULL) {
-               DEBUG(2,("utmp_claim: conn NULL\n"));
-               return;
+       if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) {
+               DEBUG(0,("claim_connection: tdb_store failed with error %s.\n",
+                       tdb_errorstr(tdb) ));
+               return False;
        }
 
-       if (! lp_utmp(SNUM(conn))) {
-               DEBUG(2,("utmp_claim: lp_utmp() NULL\n"));
-               return;
-       }
-
-       pstrcpy(dirname,lp_utmpdir());
-       trim_string(dirname,"","/");
-       pstrcat(dirname,"/");
-
-       DEBUG(2,("utmp_claim: dir:%s conn: user:%s cnum:%d i:%d\n",
-         dirname, conn->user, conn->cnum, conn->cnum));
-       DEBUG(2,("utmp_claim: crec: pid:%d, cnum:%d name:%s addr:%s mach:%s DNS:%s\n",
-         crec->pid, crec->cnum, crec->name, crec->addr, crec->machine, client_name(Client)));
-
-
-       memset((char *)&u, '\0', sizeof(struct utmp));
-       u.ut_type = USER_PROCESS;
-       if (utmp_fill(&u, conn, crec->pid, conn->cnum) == 0) {
-               utmp_update(dirname, &u, crec->machine);
-       }
+       return True;
 }
-
-#endif