summaryrefslogtreecommitdiffstats
path: root/lib/libulog/ulog_pututxline.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libulog/ulog_pututxline.c')
-rw-r--r--lib/libulog/ulog_pututxline.c208
1 files changed, 208 insertions, 0 deletions
diff --git a/lib/libulog/ulog_pututxline.c b/lib/libulog/ulog_pututxline.c
new file mode 100644
index 0000000..d02dda5
--- /dev/null
+++ b/lib/libulog/ulog_pututxline.c
@@ -0,0 +1,208 @@
+/*-
+ * Copyright (c) 2009 Ed Schouten <ed@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <string.h>
+#include <timeconv.h>
+#include <unistd.h>
+
+#include "ulog_internal.h"
+
+static void
+ulog_utmpx_to_futmp(const struct ulog_utmpx *utx, struct futmp *ut)
+{
+
+ memset(ut, 0, sizeof *ut);
+#define COPY_STRING(field) do { \
+ strncpy(ut->ut_ ## field, utx->ut_ ## field, \
+ MIN(sizeof ut->ut_ ## field, sizeof utx->ut_ ## field)); \
+} while (0)
+ switch (utx->ut_type) {
+ case BOOT_TIME:
+ strcpy(ut->ut_user, "reboot");
+ ut->ut_line[0] = '~';
+ break;
+ case OLD_TIME:
+ strcpy(ut->ut_user, "date");
+ ut->ut_line[0] = '|';
+ break;
+ case NEW_TIME:
+ strcpy(ut->ut_user, "date");
+ ut->ut_line[0] = '{';
+ break;
+ case USER_PROCESS:
+ COPY_STRING(user);
+ COPY_STRING(line);
+ COPY_STRING(host);
+ break;
+ case DEAD_PROCESS:
+ COPY_STRING(line);
+ break;
+ case SHUTDOWN_TIME:
+ strcpy(ut->ut_user, "shutdown");
+ ut->ut_line[0] = '~';
+ break;
+ }
+#undef COPY_STRING
+ ut->ut_time = _time_to_time32(utx->ut_tv.tv_sec);
+}
+
+static void
+ulog_utmpx_to_flastlog(const struct ulog_utmpx *utx, struct flastlog *ll)
+{
+
+ memset(ll, 0, sizeof *ll);
+#define COPY_STRING(field) do { \
+ strncpy(ll->ll_ ## field, utx->ut_ ## field, \
+ MIN(sizeof ll->ll_ ## field, sizeof utx->ut_ ## field)); \
+} while (0)
+ switch (utx->ut_type) {
+ case USER_PROCESS:
+ COPY_STRING(line);
+ COPY_STRING(host);
+ break;
+ }
+#undef COPY_STRING
+ ll->ll_time = _time_to_time32(utx->ut_tv.tv_sec);
+}
+
+static void
+ulog_write_utmp_fast(const struct futmp *ut)
+{
+ unsigned int idx;
+ char line[sizeof ut->ut_line + 1];
+ int fd;
+
+ if ((fd = open(_PATH_UTMP, O_WRONLY|O_CREAT, 0644)) < 0)
+ return;
+ strlcpy(line, ut->ut_line, sizeof line);
+ idx = ulog_ttyslot(line);
+ if (idx > 0) {
+ lseek(fd, (off_t)(idx * sizeof *ut), SEEK_SET);
+ write(fd, ut, sizeof *ut);
+ }
+ close(fd);
+}
+
+static int
+ulog_write_utmp_slow(const struct futmp *ut)
+{
+ struct futmp utf;
+ int fd, found;
+
+ if ((fd = open(_PATH_UTMP, O_RDWR, 0)) < 0)
+ return (0);
+ found = 0;
+ while (read(fd, &utf, sizeof utf) == sizeof utf) {
+ if (utf.ut_user[0] == '\0' ||
+ strncmp(utf.ut_line, ut->ut_line, sizeof utf.ut_line) != 0)
+ continue;
+ lseek(fd, -(off_t)sizeof utf, SEEK_CUR);
+ write(fd, &ut, sizeof ut);
+ found = 1;
+ }
+ close(fd);
+ return (found);
+}
+
+static void
+ulog_write_wtmp(const struct futmp *ut)
+{
+ int fd;
+
+ if ((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) < 0)
+ return;
+ write(fd, ut, sizeof *ut);
+ close(fd);
+}
+
+static void
+ulog_write_lastlog(const struct flastlog *ll, const char *user)
+{
+ struct passwd *pw;
+ int fd;
+
+ if ((fd = open(_PATH_LASTLOG, O_WRONLY, 0)) < 0)
+ return;
+ pw = getpwnam(user);
+ if (pw != NULL) {
+ lseek(fd, (off_t)(pw->pw_uid * sizeof *ll), SEEK_SET);
+ write(fd, ll, sizeof *ll);
+ }
+ close(fd);
+}
+
+struct ulog_utmpx *
+ulog_pututxline(const struct ulog_utmpx *utmpx)
+{
+ static struct ulog_utmpx utx;
+ struct futmp ut;
+ struct flastlog ll;
+ char user[sizeof utmpx->ut_user + 1];
+
+ switch (utmpx->ut_type) {
+ case BOOT_TIME:
+ case OLD_TIME:
+ case NEW_TIME:
+ case SHUTDOWN_TIME:
+ ulog_utmpx_to_futmp(utmpx, &ut);
+
+ /* Only log to wtmp. */
+ ulog_write_wtmp(&ut);
+ break;
+ case USER_PROCESS:
+ ulog_utmpx_to_futmp(utmpx, &ut);
+ ulog_utmpx_to_flastlog(utmpx, &ll);
+
+ /* Log to utmp, wtmp and lastlog. */
+ ulog_write_utmp_fast(&ut);
+ ulog_write_wtmp(&ut);
+ strlcpy(user, utmpx->ut_user, sizeof user);
+ ulog_write_lastlog(&ll, user);
+ break;
+ case DEAD_PROCESS:
+ ulog_utmpx_to_futmp(utmpx, &ut);
+
+ /* Only log to wtmp if logged in utmp. */
+ if (ulog_write_utmp_slow(&ut))
+ ulog_write_wtmp(&ut);
+ break;
+ default:
+ return (NULL);
+ }
+
+ /* XXX: Can't we just return utmpx itself? */
+ memcpy(&utx, utmpx, sizeof utx);
+ utx.ut_user[sizeof utx.ut_user - 1] = '\0';
+ utx.ut_line[sizeof utx.ut_line - 1] = '\0';
+ utx.ut_host[sizeof utx.ut_host - 1] = '\0';
+ return (&utx);
+}
OpenPOWER on IntegriCloud