From 1e2f92af555166ea4e042e33ef41957354d233f8 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 12 Jan 2000 03:09:17 +0000 Subject: Added utmp fix from David Lee . Jeremy. (This used to be commit 95d37a1d25d56316c80eec54aea1f358cd621d4c) --- source3/smbd/connection.c | 212 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 212 insertions(+) (limited to 'source3/smbd/connection.c') 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 + +#ifdef HAVE_UTMPX_H +#include +#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 -- cgit