summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/proto.h3
-rw-r--r--source3/param/loadparm.c13
-rw-r--r--source3/smbd/connection.c678
-rw-r--r--source3/smbd/posix_acls.c19
-rw-r--r--source3/smbd/sec_ctx.c2
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 <lastlog.h>.
+ 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 <utmpx.h>
#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 <lastlog.h>
+#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 <master@iaas.msu.ru>
+****************************************************************************/
+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;
}