Re: Howto log multiple sftpd instances with their chroot shared via NFS

[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

 



Hi Hildegard,

Hildegard Meier wrote:
> I think, the sftpd process should just not write to the /dev/log
> unix socket (because this leads to the problem here), but to the
> local kernel directly, something like what you describe here.

Exactly, but unfortunately the code that sets the socket path is in
the system C library, without any interface to control the setting.


> But how could I do this concrete with Ubuntu Linux? What you write
> is rather abstract and I am not so expert that I understand what
> you mean with LD_PRELOAD wrapper.

Setting the LD_PRELOAD environment variable to a library filename when
starting a program loads that library into memory before the system C
library and the program itself. Symbols (ie. functions) loaded from
the preloaded library are not replaced by later (system) libraries,
making it possible to override and/or wrap libc functionality in this
fairly brutish way, hence a bit unpleasant.

Attached is source code for a simple such wrapper overriding openlog(),
syslog() and closelog(). It might work only on the older system, or on
both. You only need this hack on one server, the other can use /dev/log.

The wrapper directs logging to /dev/log_<hostname> instead of /dev/log.
Since libc has no interface to manipulate the socket path these functions
override the normal functions with a very limited implementation.
Adjust the template on line 49 if you want to change the destinateion.

Although functionality is limited it could work well for sftp-server.

One simplification is that this openlog() ignores all option flags
except LOG_NDELAY and that syslog() always behaves as if openlog() was
called with the LOG_PID option. Since this is exactly what OpenSSH log.c
does all log messages should look the same as with the libc implementation.

Note that log messages are silently lost on any error, e.g. syslog-ng
not running. Also note that if log messages, the openlog() ident
parameter or the username (when ident == NULL) are very long then
messages are silently truncated to 2048 chars. OpenSSH sends max 500
chars.


You didn't mention if your two sshd are configured to use the in-process
sftp-server (Subsystem sftp internal-sftp in sshd_config) - if so then
this is probably not really the best solution, since LD_PRELOAD would
have to be set for the entire sshd process, which I don't recommend
because this code is so simplistic compared to libc.

Anyway, try it if you like.


The comment near the top of the file shows how to compile. sshd can't
be configured to set LD_PRELOAD so to use the compiled .so with
sftp-server you have to create a simple script:

--8<-- /usr/local/libexec/sftp-server-hostlog
#!/bin/sh
export LD_PRELOAD=/usr/local/libexec/hostlog.so
exec /usr/lib/sftp-server "$*"
-->8--

and then configure sshd to call that instead of sftp-server:

--8<-- /etc/ssh/sshd_config
Subsystem sftp /usr/local/libexec/sftp-server-hostlog
-->8--

Adjust paths as needed, also in the compile command.


For anyone else interested please go ahead but note that I haven't
put huge effort into portability; it might work outside Linux but
I haven't tested anywhere else so YMMV.


Kind regards

//Peter
/* Copyright (c) 2021 Peter Stuge */
/* SPDX-License-Identifier: MIT */

/* This very limited syslog() implementation sends messages to
 * /dev/log_<hostname> instead of /dev/log and fails silently on any error.
 *
 * build:  cc -std=c89 -shared -fPIC -s -o hostlog.so hostlog.c
 * usage:  LD_PRELOAD=./hostlog.so program_using_libc_syslog args ...
 */

#define _POSIX_C_SOURCE 200112L /* gethostname() */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <time.h>

#ifndef LOG_NDELAY
#define LOG_NDELAY 0x08
#endif
#ifndef LOG_USER
#define LOG_USER (1<<3)
#endif

static const char *opened_ident = NULL;
static int opened_facility = LOG_USER;
static int sockfd = -1;

static void close_sockfd(void) {
	if (sockfd != -1) {
		close(sockfd);
		sockfd = -1;
	}
}

static int open_sockfd(void) {
	char hostname[HOST_NAME_MAX + 1];
	struct sockaddr_un un;
	int fd;

	if (-1 == gethostname(hostname, sizeof hostname))
		return -1;

	hostname[sizeof hostname - 1] = 0;

	un.sun_family = AF_UNIX;

	if (snprintf(un.sun_path, sizeof un.sun_path, "/dev/log_%s", hostname) >= sizeof un.sun_path)
		return -1;

	fd = socket(un.sun_family, SOCK_DGRAM|SOCK_CLOEXEC, 0);
	if (-1 == fd)
		return -1;

	if (-1 == connect(fd, (const struct sockaddr *)&un, sizeof un)) {
		close(fd);
		return -1;
	}

	close_sockfd();

	sockfd = fd;

	return sockfd;
}

void openlog(const char *ident, int option, int facility) {
	opened_ident = ident;
	opened_facility = facility;

	if (option & LOG_NDELAY)
		open_sockfd();
}

void syslog(int priority, const char *format, ...) {
	time_t now;
	char timestr[64], msg[2049];
	int len;
	va_list ap;

	if (-1 == sockfd && -1 == open_sockfd())
		return;

	now = time(NULL);
	strftime(timestr, sizeof timestr, "%b %d %H:%M:%S", localtime(&now));

	len = snprintf(msg, sizeof msg, "<%u>%s %s[%u]: ",
		opened_facility | priority,
		timestr,
		opened_ident ? opened_ident : getenv("USER"),
		getpid());

	if (len < sizeof msg) {
		va_start(ap, format);
		len += vsnprintf(msg + len, sizeof msg - len, format, ap);
		va_end(ap);
	}

	if (len >= sizeof msg)
		len = sizeof msg - 1;

	sendto(sockfd, msg, len, MSG_NOSIGNAL, NULL, 0);
}

void closelog(void) {
	close_sockfd();
	opened_ident = NULL;
	opened_facility = LOG_USER;
}
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@xxxxxxxxxxx
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev

[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux