summaryrefslogtreecommitdiff
path: root/source3/smbd
diff options
context:
space:
mode:
Diffstat (limited to 'source3/smbd')
-rw-r--r--source3/smbd/connection.c212
1 files changed, 212 insertions, 0 deletions
diff --git a/source3/smbd/connection.c b/source3/smbd/connection.c
index 82f789f7a1..9a678ba88f 100644
--- a/source3/smbd/connection.c
+++ b/source3/smbd/connection.c
@@ -27,6 +27,11 @@ static TDB_CONTEXT *tdb;
extern int DEBUGLEVEL;
+#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
+
/****************************************************************************
delete a connection record
****************************************************************************/
@@ -48,6 +53,12 @@ BOOL yield_connection(connection_struct *conn,char *name,int max_connections)
kbuf.dsize = sizeof(key);
tdb_delete(tdb, kbuf);
+
+#ifdef WITH_UTMP
+ if(conn)
+ utmp_yield(key.pid, conn);
+#endif
+
return(True);
}
@@ -102,5 +113,206 @@ BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOO
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) {
+ ux.ut_syslen = strlen(host);
+ 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 (! 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);
+ }
+}
+
+#endif