From 1cb444057a7894ca97706fb65a756e5fdb635f81 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Sat, 28 Oct 2000 19:38:39 +0000 Subject: David Lee's utmp patch (finally). Thanks David ! Jeremy. (This used to be commit b809a2d0c81c54e917ccc0c99b3e70ea8d7ceab1) --- source3/include/proto.h | 3 + source3/param/loadparm.c | 13 + source3/smbd/connection.c | 678 ++++++++++++++++++++++++++++++++++++++++------ source3/smbd/posix_acls.c | 19 +- source3/smbd/sec_ctx.c | 2 +- 5 files changed, 625 insertions(+), 90 deletions(-) diff --git a/source3/include/proto.h b/source3/include/proto.h index 9b851f901d..81380caa36 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -1339,6 +1339,9 @@ char *lp_addprinter_cmd(void); char *lp_deleteprinter_cmd(void); char *lp_lockdir(void); char *lp_utmpdir(void); +char *lp_wtmpdir(void); +char *lp_utmp_hostname(void); +BOOL lp_utmp_consolidate(void); char *lp_rootdir(void); char *lp_source_environment(void); char *lp_defaultservice(void); diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 3fa3773276..43b0c62f17 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -168,6 +168,9 @@ typedef struct char *szWINSHook; #ifdef WITH_UTMP char *szUtmpDir; + char *szWtmpDir; + char *szUtmpHostname; + BOOL bUtmpConsolidate; #endif /* WITH_UTMP */ char *szSourceEnv; char *szWinbindUID; @@ -939,6 +942,10 @@ static struct parm_struct parm_table[] = { #ifdef WITH_UTMP {"utmp dir", P_STRING, P_GLOBAL, &Globals.szUtmpDir, NULL, NULL, 0}, {"utmp directory", P_STRING, P_GLOBAL, &Globals.szUtmpDir, NULL, NULL, 0}, + {"wtmp dir", P_STRING, P_GLOBAL, &Globals.szWtmpDir, NULL, NULL, 0}, + {"wtmp directory", P_STRING, P_GLOBAL, &Globals.szWtmpDir, NULL, NULL, 0}, + {"utmp hostname", P_STRING, P_GLOBAL, &Globals.szUtmpHostname, NULL, NULL, 0}, + {"utmp consolidate", P_BOOL, P_GLOBAL, &Globals.bUtmpConsolidate, NULL, NULL, 0}, #endif /* WITH_UTMP */ {"default service", P_STRING, P_GLOBAL, @@ -1142,6 +1149,9 @@ static void init_globals(void) string_set(&Globals.szLockDir, LOCKDIR); #ifdef WITH_UTMP string_set(&Globals.szUtmpDir, ""); + string_set(&Globals.szWtmpDir, ""); + string_set(&Globals.szUtmpHostname, "%m"); + Globals.bUtmpConsolidate = False; #endif /* WITH_UTMP */ string_set(&Globals.szSmbrun, SMBRUN); string_set(&Globals.szSocketAddress, "0.0.0.0"); @@ -1370,6 +1380,9 @@ FN_GLOBAL_STRING(lp_deleteprinter_cmd, &Globals.szDeletePrinterCommand) FN_GLOBAL_STRING(lp_lockdir, &Globals.szLockDir) #ifdef WITH_UTMP FN_GLOBAL_STRING(lp_utmpdir, &Globals.szUtmpDir) +FN_GLOBAL_STRING(lp_wtmpdir, &Globals.szWtmpDir) +FN_GLOBAL_STRING(lp_utmp_hostname, &Globals.szUtmpHostname) +FN_GLOBAL_BOOL(lp_utmp_consolidate, &Globals.bUtmpConsolidate) #endif /* WITH_UTMP */ FN_GLOBAL_STRING(lp_rootdir, &Globals.szRootdir) FN_GLOBAL_STRING(lp_source_environment, &Globals.szSourceEnv) diff --git a/source3/smbd/connection.c b/source3/smbd/connection.c index bc014c300d..6e088f9f8f 100644 --- a/source3/smbd/connection.c +++ b/source3/smbd/connection.c @@ -126,17 +126,63 @@ BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOO 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. + With grateful thanks since then to many who have helped port it to + different operating systems. The variety of OS quirks thereby + uncovered is amazing... -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". +Hints for porting: + o Always attempt to use programmatic interface (pututline() etc.) + Indeed, at present only programmatic use is supported. + o The only currently supported programmatic interface to "wtmp{,x}" + is through "updwtmp*()" routines. + o The "x" (utmpx/wtmpx; HAVE_UTMPX_H) seems preferable. + o The HAVE_* items should identify supported features. + o If at all possible, avoid "if defined(MY-OS)" constructions. + +OS observations and status: + Almost every OS seems to have its own quirks. + + Solaris 2.x: + Tested on 2.6 and 2.7; should be OK on other flavours. + AIX: + Apparently has utmpx.h but doesn't implement. + OSF: + Has utmpx.h, but (e.g.) no "getutmpx()". (Is this like AIX ?) + Redhat 6: + utmpx.h seems not to set default filenames. non-x better. + IRIX 6.5: + Not tested. Appears to have "x". + HP-UX 9.x: + Not tested. Appears to lack "x". + HP-UX 10.x: + Not tested. + "updwtmp*()" routines seem absent, so no current wtmp* support. + Has "ut_addr": probably trivial to implement (although remember + that IPv6 is coming...). + + FreeBSD: + No "putut*()" type of interface. + No "ut_type" and associated defines. + Write files directly. Alternatively use its login(3)/logout(3). + SunOS 4: + Not tested. Resembles FreeBSD, but no login()/logout(). + +lastlog: + Should "lastlog" files, if any, be updated? + BSD systems (SunOS 4, FreeBSD): + o Prominent mention on man pages. + System-V (e.g. Solaris 2): + o No mention on man pages, even under "man -k". + o Has a "/var/adm/lastlog" file, but pututxline() etc. seem + not to touch it. + o Despite downplaying (above), nevertheless has . + So perhaps UN*X "lastlog" facility is intended for tty/terminal only? Notes: + Each connection requires a small number (starting at 0, working up) + to represent the line (unum). This must be unique within and across + all smbd processes. + 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. @@ -158,10 +204,11 @@ Notes: 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. + The remaining two encode the "unum" (see above). + + For "utmp consolidate" the suggestion was made to encode the pid into + those remaining two bytes (16 bits). But recent UNIX (e.g Solaris 8) + is migrating to pids > 16 bits, so we ought not to do this. ****************************************************************************/ @@ -171,6 +218,136 @@ Notes: #include #endif +/* BSD systems: some may need lastlog.h (SunOS 4), some may not (FreeBSD) */ +/* Some System-V systems (e.g. Solaris 2) declare this too. */ +#ifdef HAVE_LASTLOG_H +#include +#endif + +/**************************************************************************** +obtain/release a small number (0 upwards) unique within and across smbds +****************************************************************************/ +/* + * Need a "small" number to represent this connection, unique within this + * smbd and across all smbds. + * + * claim: + * Start at 0, hunt up for free, unique number "unum" by attempting to + * store it as a key in a tdb database: + * key: unum data: pid+conn + * Also store its inverse, ready for yield function: + * key: pid+conn data: unum + * + * yield: + * Find key: pid+conn; data is unum; delete record + * Find key: unum ; delete record. + * + * Comment: + * The claim algorithm (a "for" loop attempting to store numbers in a tdb + * database) will be increasingly inefficient with larger numbers of + * connections. Is it possible to write a suitable primitive within tdb? + * + * However, by also storing the inverse key/data pair, we at least make + * the yield algorithm efficient. + */ + +static TDB_CONTEXT *tdb_utmp; + +struct utmp_tdb_data { + pid_t pid; + int cnum; +}; + +static int utmp_claim_tdb(const connection_struct *conn) +{ + struct utmp_tdb_data udata; + int i, slotnum; + TDB_DATA kbuf, dbuf; + + if (!tdb_utmp) { + tdb_utmp = tdb_open(lock_path("utmp.tdb"), 0, + TDB_CLEAR_IF_FIRST, O_RDWR | O_CREAT, 0644); + } + if (!tdb_utmp) return(-1); + + DEBUG(2,("utmp_claim_tdb: entered\n")); + + ZERO_STRUCT(udata); + udata.pid = sys_getpid(); + udata.cnum = conn ? conn->cnum : -1; + + dbuf.dptr = (char *) &udata; + dbuf.dsize = sizeof(udata); + + /* The key is simply a number as close as possible to zero: find it */ + slotnum = -1; + /* stop loop when overflow +ve integers (a huge, busy machine!) */ + for (i = 0; i >= 0 ; i++) { + kbuf.dptr = (char *) &i; + kbuf.dsize = sizeof(i); + + if (tdb_store(tdb_utmp, kbuf, dbuf, TDB_INSERT) == 0) { + /* have successfully grabbed a free slot */ + slotnum = i; + + /* store the inverse for faster utmp_yield_tdb() */ + tdb_store(tdb_utmp, dbuf, kbuf, TDB_INSERT); + + break; /* Got it; escape */ + } + } + if (slotnum < 0) { /* more connections than positive integers! */ + DEBUG(2,("utmp_claim_tdb: failed\n")); + return(-1); + } + + DEBUG(2,("utmp_claim_tdb: leaving with %d\n", slotnum)); + + return(slotnum); +} + +static int utmp_yield_tdb(const connection_struct *conn) +{ + struct utmp_tdb_data revkey; + int i, slotnum; + TDB_DATA kbuf, dbuf; + + if (!tdb_utmp) { + return(-1); + } + + DEBUG(2,("utmp_yield_tdb: entered\n")); + + ZERO_STRUCT(revkey); + revkey.pid = sys_getpid(); + revkey.cnum = conn ? conn->cnum : -1; + + kbuf.dptr = (char *) &revkey; + kbuf.dsize = sizeof(revkey); + + dbuf = tdb_fetch(tdb_utmp, kbuf); + if (dbuf.dptr == NULL) { + DEBUG(2,("utmp_yield_tdb: failed\n")); + return(-1); /* shouldn't happen */ + } + + /* Save our result */ + slotnum = (int) dbuf.dptr; + + /* Tidy up */ + tdb_delete(tdb_utmp, kbuf); + tdb_delete(tdb_utmp, dbuf); + + free(dbuf.dptr); + DEBUG(2,("utmp_yield_tdb: leaving with %d\n", slotnum)); + + return(slotnum); +} + +#if defined(HAVE_UT_UT_ID) +/**************************************************************************** +encode the unique connection number into "ut_id" +****************************************************************************/ static const char *ut_id_encstr = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; @@ -197,61 +374,198 @@ ut_id_encode(int i, char *fourbyte) return(i); /* 0: good; else overflow */ } +#endif /* defined(HAVE_UT_UT_ID) */ -static int utmp_fill(struct utmp *u, const connection_struct *conn, pid_t pid, int i) +/* + * ut_line: + * size small, e.g. Solaris: 12; FreeBSD: 8 + * pattern conventions differ across systems. + * So take care in tweaking the template below. + * Arguably, this could be yet another smb.conf parameter. + */ +static const char *ut_line_template = +#if defined(__FreeBSD__) + "smb%d" ; +#else + "smb/%d" ; +#endif + +/**************************************************************************** +Fill in a utmp (not utmpx) template +****************************************************************************/ +static int utmp_fill(struct utmp *u, const connection_struct *conn, pid_t pid, + int i, pstring host) { +#if defined(HAVE_UT_UT_TIME) struct timeval timeval; - int rc; +#endif /* defined(HAVE_UT_UT_TIME) */ + char line_tmp[1024]; /* plenty big enough for slprintf() */ + int line_len; + int rc = 0; +/* + * ut_name, ut_user: + * Several (all?) systems seems to define one as the other. + * It is easier and clearer simply to let the following take its course, + * rather than to try to detect and optimise. + */ +#if defined(HAVE_UT_UT_USER) pstrcpy(u->ut_user, conn->user); - rc = ut_id_encode(i, u->ut_id); - slprintf(u->ut_line, 12, "smb/%d", i); +#endif /* defined(HAVE_UT_UT_USER) */ +#if defined(HAVE_UT_UT_NAME) + pstrcpy(u->ut_name, conn->user); +#endif /* defined(HAVE_UT_UT_NAME) */ + +/* + * ut_line: + * If size limit proves troublesome, then perhaps use "ut_id_encode()". + * + * Temporary variable "line_tmp" avoids trouble: + * o with unwanted trailing NULL if ut_line full; + * o with overflow if ut_line would be more than full. + */ + memset(line_tmp, '\0', sizeof(line_tmp)); + slprintf(line_tmp, sizeof(line_tmp), (char *) ut_line_template, i); + line_len = strlen(line_tmp); + if (line_len <= sizeof(u->ut_line)) { + memcpy(u->ut_line, line_tmp, sizeof(u->ut_line)); + } + else { + DEBUG(1,("utmp_fill: ut_line exceeds field length(%d > %d)\n", + line_len, sizeof(u->ut_line))); + return(1); + } + +#if defined(HAVE_UT_UT_PID) u->ut_pid = pid; +#endif /* defined(HAVE_UT_UT_PID) */ +/* + * ut_time, ut_tv: + * Some have one, some the other. Many have both, but defined (aliased). + * It is easier and clearer simply to let the following take its course. + * But note that we do the more precise ut_tv as the final assignment. + */ +#if defined(HAVE_UT_UT_TIME) gettimeofday(&timeval, NULL); u->ut_time = timeval.tv_sec; +#endif /* defined(HAVE_UT_UT_TIME) */ + +#if defined(HAVE_UT_UT_TV) + gettimeofday(&timeval, NULL); + u->ut_tv = timeval; +#endif /* defined(HAVE_UT_UT_TV) */ + +#if defined(HAVE_UT_UT_HOST) + if (host) { + pstrcpy(u->ut_host, host); + } +#endif /* defined(HAVE_UT_UT_HOST) */ + +#if defined(HAVE_UT_UT_ADDR) + /* + * "(unsigned long) ut_addr" apparently exists on at least HP-UX 10.20. + * Volunteer to implement, please ... + */ +#endif /* defined(HAVE_UT_UT_ADDR) */ + +#if defined(HAVE_UT_UT_ID) + rc = ut_id_encode(i, u->ut_id); +#endif /* defined(HAVE_UT_UT_ID) */ return(rc); } -/* Default path (if possible) */ +/**************************************************************************** +Default paths to various {u,w}tmp{,x} files +****************************************************************************/ #ifdef HAVE_UTMPX_H -# ifdef UTMPX_FILE -static char *ut_pathname = UTMPX_FILE; +static const char *ux_pathname = +# if defined (UTMPX_FILE) + UTMPX_FILE ; +# elif defined (_UTMPX_FILE) + _UTMPX_FILE ; +# elif defined (_PATH_UTMPX) + _PATH_UTMPX ; # else -static char *ut_pathname = ""; + "" ; # endif -# ifdef WTMPX_FILE -static char *wt_pathname = WTMPX_FILE; + +static const char *wx_pathname = +# if defined (WTMPX_FILE) + WTMPX_FILE ; +# elif defined (_WTMPX_FILE) + _WTMPX_FILE ; +# elif defined (_PATH_WTMPX) + _PATH_WTMPX ; # else -static char *wt_pathname = ""; + "" ; # endif -#else /* HAVE_UTMPX_H */ +#endif /* HAVE_UTMPX_H */ -# ifdef UTMP_FILE -static char *ut_pathname = UTMP_FILE; +static const char *ut_pathname = +# if defined (UTMP_FILE) + UTMP_FILE ; +# elif defined (_UTMP_FILE) + _UTMP_FILE ; +# elif defined (_PATH_UTMP) + _PATH_UTMP ; # else -static char *ut_pathname = ""; + "" ; # endif -# ifdef WTMP_FILE -static char *wt_pathname = WTMP_FILE; + +static const char *wt_pathname = +# if defined (WTMP_FILE) + WTMP_FILE ; +# elif defined (_WTMP_FILE) + _WTMP_FILE ; +# elif defined (_PATH_WTMP) + _PATH_WTMP ; # else -static char *wt_pathname = ""; + "" ; # endif -#endif /* HAVE_UTMPX_H */ +/* BSD-like systems might want "lastlog" support. */ +/* *** Not yet implemented */ +#ifndef HAVE_PUTUTLINE /* see "pututline_my()" */ +static const char *ll_pathname = +# if defined (_PATH_LASTLOG) /* what other names (if any?) */ + _PATH_LASTLOG ; +# else + "" ; +# endif /* _PATH_LASTLOG */ +#endif /* HAVE_PUTUTLINE */ -static void uw_pathname(pstring fname, const char *uw_name) +/* + * Get name of {u,w}tmp{,x} file. + * return: fname contains filename + * Possibly empty if this code not yet ported to this system. + * + * utmp{,x}: try "utmp dir", then default (a define) + * wtmp{,x}: try "wtmp dir", then "utmp dir", then default (a define) + */ +static void uw_pathname(pstring fname, const char *uw_name, const char *uw_default) { pstring dirname; - pstrcpy(dirname,lp_utmpdir()); - trim_string(dirname,"","/"); + pstrcpy(dirname, ""); + + /* For w-files, first look for explicit "wtmp dir" */ + if (uw_name[0] == 'w') { + pstrcpy(dirname,lp_wtmpdir()); + trim_string(dirname,"","/"); + } - /* Given directory: use it */ + /* For u-files and non-explicit w-dir, look for "utmp dir" */ + if (dirname == 0 || strlen(dirname) == 0) { + pstrcpy(dirname,lp_utmpdir()); + trim_string(dirname,"","/"); + } + + /* If explicit directory above, use it */ if (dirname != 0 && strlen(dirname) != 0) { pstrcpy(fname, dirname); pstrcat(fname, "/"); @@ -259,90 +573,256 @@ static void uw_pathname(pstring fname, const char *uw_name) return; } - /* No given directory: attempt to use default paths */ - if (uw_name[0] == 'u') { - pstrcpy(fname, ut_pathname); + /* No explicit directory: attempt to use default paths */ + if (strlen(uw_default) == 0) { + /* No explicit setting, no known default. + * Has it yet been ported to this OS? + */ + DEBUG(2,("uw_pathname: unable to determine pathname\n")); + } + pstrcpy(fname, uw_default); +} + +#ifndef HAVE_PUTUTLINE +/**************************************************************************** +Update utmp file directly. No subroutine interface: probably a BSD system. +****************************************************************************/ +static void pututline_my(pstring uname, struct utmp *u, BOOL claim) +{ + DEBUG(1,("pututline_my: not yet implemented\n")); + /* BSD implementor: may want to consider (or not) adjusting "lastlog" */ +} +#endif /* HAVE_PUTUTLINE */ + +#ifndef HAVE_UPDWTMP +/**************************************************************************** +Update wtmp file directly. No subroutine interface: probably a BSD system. +Credit: Michail Vidiassov +****************************************************************************/ +static void updwtmp_my(pstring wname, struct utmp *u, BOOL claim) +{ + int fd; + struct stat buf; + + if (! claim) { + /* + * BSD-like systems: + * may use empty ut_name to distinguish a logout record. + * + * May need "if defined(SUNOS4)" etc. around some of these, + * but try to avoid if possible. + * + * SunOS 4: + * man page indicates ut_name and ut_host both NULL + * FreeBSD 4.0: + * man page appears not to specify (hints non-NULL) + * A correspondent suggest at least ut_name should be NULL + */ + memset((char *)&(u->ut_name), '\0', sizeof(u->ut_name)); + memset((char *)&(u->ut_host), '\0', sizeof(u->ut_host)); + } + /* Stolen from logwtmp function in libutil. + * May be more locking/blocking is needed? + */ + if ((fd = open(wname, O_WRONLY|O_APPEND, 0)) < 0) return; + if (fstat(fd, &buf) == 0) { + if (write(fd, (char *)u, sizeof(struct utmp)) != sizeof(struct utmp)) + (void) ftruncate(fd, buf.st_size); } + (void) close(fd); +} +#endif /* HAVE_UPDWTMP */ - if (uw_name[0] == 'w') { - pstrcpy(fname, wt_pathname); +/**************************************************************************** +Update via utmp/wtmp (not utmpx/wtmpx) +****************************************************************************/ +static void utmp_nox_update(struct utmp *u, pstring host, BOOL claim) +{ + pstring uname, wname; +#if defined(PUTUTLINE_RETURNS_UTMP) + struct utmp *urc; +#endif /* PUTUTLINE_RETURNS_UTMP */ + + uw_pathname(uname, "utmp", ut_pathname); + DEBUG(2,("utmp_nox_update: uname:%s\n", uname)); + +#ifdef HAVE_PUTUTLINE + if (strlen(uname) != 0) { + utmpname(uname); + } + +# if defined(PUTUTLINE_RETURNS_UTMP) + setutent(); + urc = pututline(u); + endutent(); + if (urc == NULL) { + DEBUG(2,("utmp_nox_update: pututline() failed\n")); return; } +# else /* PUTUTLINE_RETURNS_UTMP */ + setutent(); + pututline(u); + endutent(); +# endif /* PUTUTLINE_RETURNS_UTMP */ - pstrcpy(fname, ""); +#else /* HAVE_PUTUTLINE */ + if (strlen(uname) != 0) { + pututline_my(uname, u, claim); + } +#endif /* HAVE_PUTUTLINE */ + + uw_pathname(wname, "wtmp", wt_pathname); + DEBUG(2,("utmp_nox_update: wname:%s\n", wname)); + if (strlen(wname) != 0) { +#ifdef HAVE_UPDWTMP + updwtmp(wname, u); + /* + * updwtmp() and the newer updwtmpx() may be unsymmetrical. + * At least one OS, Solaris 2.x declares the former in the + * "utmpx" (latter) file and context. + * In the Solaris case this is irrelevant: it has both and + * we always prefer the "x" case, so doesn't come here. + * But are there other systems, with no "x", which lack + * updwtmp() perhaps? + */ +#else + updwtmp_my(wname, u, claim); +#endif /* HAVE_UPDWTMP */ + } } -static void utmp_update(const struct utmp *u, const char *host) +/**************************************************************************** +Update via utmpx/wtmpx (preferred) or via utmp/wtmp +****************************************************************************/ +static void utmp_update(struct utmp *u, pstring host, BOOL claim) { - pstring fname; - -#ifdef HAVE_UTMPX_H +#if !defined(HAVE_UTMPX_H) + /* No utmpx stuff. Drop to non-x stuff */ + utmp_nox_update(u, host, claim); +#elif !defined(HAVE_PUTUTXLINE) + /* Odd. Have utmpx.h but no "pututxline()". Drop to non-x stuff */ + DEBUG(1,("utmp_update: have utmpx.h but no pututxline() function\n")); + utmp_nox_update(u, host, claim); +#elif !defined(HAVE_GETUTMPX) + /* Odd. Have utmpx.h but no "getutmpx()". Drop to non-x stuff */ + DEBUG(1,("utmp_update: have utmpx.h but no getutmpx() function\n")); + utmp_nox_update(u, host, claim); +#else + pstring uname, wname; struct utmpx ux, *uxrc; getutmpx(u, &ux); if (host) { #if defined(HAVE_UX_UT_SYSLEN) - ux.ut_syslen = strlen(host); + ux.ut_syslen = strlen(host) + 1; /* include end NULL */ #endif /* defined(HAVE_UX_UT_SYSLEN) */ pstrcpy(ux.ut_host, host); } - uw_pathname(fname, "utmpx"); - DEBUG(2,("utmp_update: fname:%s\n", fname)); - if (strlen(fname) != 0) { - utmpxname(fname); - } - uxrc = pututxline(&ux); - if (uxrc == NULL) { - DEBUG(2,("utmp_update: pututxline() failed\n")); - return; - } - - uw_pathname(fname, "wtmpx"); - DEBUG(2,("utmp_update: fname:%s\n", fname)); - if (strlen(fname) != 0) { - updwtmpx(fname, &ux); + uw_pathname(uname, "utmpx", ux_pathname); + uw_pathname(wname, "wtmpx", wx_pathname); + DEBUG(2,("utmp_update: uname:%s wname:%s\n", uname, wname)); + /* + * Check for either uname or wname being empty. + * Some systems, such as Redhat 6, have a "utmpx.h" which doesn't + * define default filenames. + * Also, our local installation has not provided an override. + * Drop to non-x method. (E.g. RH6 has good defaults in "utmp.h".) + */ + if ((strlen(uname) == 0) || (strlen(wname) == 0)) { + utmp_nox_update(u, host, claim); } + else { + utmpxname(uname); + setutxent(); + uxrc = pututxline(&ux); + endutxent(); + if (uxrc == NULL) { + DEBUG(2,("utmp_update: pututxline() failed\n")); + return; + } +#ifdef HAVE_UPDWTMPX + updwtmpx(wname, &ux); #else - uw_pathname(fname, "utmp"); - DEBUG(2,("utmp_update: fname:%s\n", fname)); - if (strlen(fname) != 0) { - utmpname(fname); + /* Have utmpx.h but no "updwtmpx()". */ + DEBUG(1,("utmp_update: no updwtmpx() function\n")); +#endif /* HAVE_UPDWTMPX */ } - pututline(u); - - uw_pathname(fname, "wtmp"); - - /* *** Hmmm. Appending wtmp (as distinct from overwriting utmp) has - me baffled. How is it to be done? *** */ -#endif +#endif /* HAVE_UTMPX_H */ } +/* + * "utmp consolidate": some background: + * False (default): + * In "utmp" files note every connection via this process. + * Argument "i" is simply a tty-like number we can use as-is. + * True: + * In "utmp" files, only note first open and final close. Keep: + * o count of open processes; + * o record value of first "i", to use as "i" in final close. + */ +static int utmp_count = 0; +static int utmp_consolidate_conn_num; + +/**************************************************************************** +close a connection +****************************************************************************/ static void utmp_yield(pid_t pid, const connection_struct *conn) { struct utmp u; + int conn_num, i; if (! lp_utmp(SNUM(conn))) { DEBUG(2,("utmp_yield: lp_utmp() NULL\n")); return; } - DEBUG(2,("utmp_yield: conn: user:%s cnum:%d\n", - conn->user, conn->cnum)); + i = utmp_yield_tdb(conn); + if (i < 0) { + DEBUG(2,("utmp_yield: utmp_yield_tdb() failed\n")); + return; + } + conn_num = i; + DEBUG(2,("utmp_yield: conn: user:%s cnum:%d i:%d (utmp_count:%d)\n", + conn->user, conn->cnum, i, utmp_count)); + + utmp_count -= 1; + if (lp_utmp_consolidate()) { + if (utmp_count > 0) { + DEBUG(2,("utmp_yield: utmp consolidate: %d entries still open\n", utmp_count)); + return; + } + else { + /* consolidate; final close: override conn_num */ + conn_num = utmp_consolidate_conn_num; + } + } memset((char *)&u, '\0', sizeof(struct utmp)); - u.ut_type = DEAD_PROCESS; + +#if defined(HAVE_UT_UT_EXIT) u.ut_exit.e_termination = 0; u.ut_exit.e_exit = 0; - if (utmp_fill(&u, conn, pid, conn->cnum) == 0) { - utmp_update(&u, NULL); +#endif /* defined(HAVE_UT_UT_EXIT) */ + +#if defined(HAVE_UT_UT_TYPE) + u.ut_type = DEAD_PROCESS; +#endif /* defined(HAVE_UT_UT_TYPE) */ + + if (utmp_fill(&u, conn, pid, conn_num, NULL) == 0) { + utmp_update(&u, NULL, False); } } +/**************************************************************************** +open a connection +****************************************************************************/ static void utmp_claim(const struct connections_data *crec, const connection_struct *conn) { struct utmp u; + pstring host; + int i; if (conn == NULL) { DEBUG(2,("utmp_claim: conn NULL\n")); @@ -354,17 +834,47 @@ static void utmp_claim(const struct connections_data *crec, const connection_str return; } - DEBUG(2,("utmp_claim: conn: user:%s cnum:%d\n", - conn->user, 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())); + i = utmp_claim_tdb(conn); + if (i < 0) { + DEBUG(2,("utmp_claim: utmp_claim_tdb() failed\n")); + return; + } + pstrcpy(host, lp_utmp_hostname()); + if (host == 0 || strlen(host) == 0) { + pstrcpy(host, crec->machine); + } + else { + /* explicit "utmp host": expand for any "%" variables */ + standard_sub_basic(host); + } + + DEBUG(2,("utmp_claim: conn: user:%s cnum:%d i:%d (utmp_count:%d)\n", + conn->user, conn->cnum, i, utmp_count)); + DEBUG(2,("utmp_claim: crec: pid:%d, cnum:%d name:%s addr:%s mach:%s DNS:%s host:%s\n", + crec->pid, crec->cnum, crec->name, crec->addr, crec->machine, client_name(), host)); + + utmp_count += 1; + if (lp_utmp_consolidate()) { + if (utmp_count > 1) { + DEBUG(2,("utmp_claim: utmp consolidate: %d entries already open\n", (utmp_count-1))); + return; + } + else { + /* consolidate; first open: keep record of "i" */ + utmp_consolidate_conn_num = i; + } + } memset((char *)&u, '\0', sizeof(struct utmp)); + +#if defined(HAVE_UT_UT_TYPE) u.ut_type = USER_PROCESS; - if (utmp_fill(&u, conn, crec->pid, conn->cnum) == 0) { - utmp_update(&u, crec->machine); +#endif /* defined(HAVE_UT_UT_TYPE) */ + + if (utmp_fill(&u, conn, crec->pid, i, host) == 0) { + utmp_update(&u, host, True); } } -#endif +#endif /* WITH_UTMP */ diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c index b463ec2479..54b45529d0 100644 --- a/source3/smbd/posix_acls.c +++ b/source3/smbd/posix_acls.c @@ -327,7 +327,7 @@ static BOOL unpack_nt_permissions(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *p of the mask entry as we scan the acl. ****************************************************************************/ -size_t get_num_posix_entries(acl_t posix_acl, acl_permset_t *posix_mask) +static size_t get_num_posix_entries(acl_t posix_acl, acl_permset_t *posix_mask) { size_t num_entries; acl_entry_t entry; @@ -362,7 +362,7 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc) { extern DOM_SID global_sid_World; SMB_STRUCT_STAT sbuf; - SEC_ACE ace_list[6]; + SEC_ACE *ace_list; DOM_SID owner_sid; DOM_SID group_sid; size_t sd_size; @@ -373,13 +373,15 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc) int grp_acl_type; SEC_ACCESS other_access; int other_acl_type; - int num_acls = 0; - acl_t posix_acl; + size_t num_acls = 0; + size_t num_dir_acls = 0; + acl_t posix_acl = NULL; + acl_t directory_acl = NULL; *ppdesc = NULL; if(fsp->is_directory || fsp->fd == -1) { - if(dos_stat(fsp->fsp_name, &sbuf) != 0) { + if(vfs_stat(fsp,fsp->fsp_name, &sbuf) != 0) { return 0; } /* @@ -389,6 +391,13 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc) if ((posix_acl = acl_get_file( dos_to_unix(fsp->fsp_name, False), ACL_TYPE_ACCESS)) == NULL) return 0; + /* + * If it's a directory get the default POSIX ACL. + */ + + if(fsp->is_directory) { + } + } else { if(fsp->conn->vfs_ops.fstat(fsp->fd,&sbuf) != 0) { return 0; diff --git a/source3/smbd/sec_ctx.c b/source3/smbd/sec_ctx.c index f316156222..ef446ed759 100644 --- a/source3/smbd/sec_ctx.c +++ b/source3/smbd/sec_ctx.c @@ -62,7 +62,7 @@ static BOOL become_uid(uid_t uid) set_effective_uid(uid); current_user.uid = uid; - DO_PROFILE_INC(uid_changes) + DO_PROFILE_INC(uid_changes); return True; } -- cgit