tomoyotitle.png

Recording command-line for SSH sessions

About this page

This page explains you how to record commandline for SSH login sessions.

Step 1: Compiling the program

Compile the below program. In this page, we assume the location of compiled program as /bin/record_cmdline . We assume the location of SSH server program as /usr/sbin/sshd . We assume the location of login shell program as /bin/bash .

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <fcntl.h>

static void encode(char *buffer, const char *string)
{
	while (1) {
		const unsigned char c = *(const unsigned char *) string++;
		if (!c)
			break;
		else if (c == '\\') {
			*buffer++ = '\\';
			*buffer++ = '\\';
		} else if (c > 32 && c < 127)
			*buffer++ = c;
		else {
			*buffer++ = '\\';
			*buffer++ = '0' + (c >> 6);
			*buffer++ = '0' + ((c >> 3) & 7);
			*buffer++ = '0' + (c & 7);
		}
	}
}

int main(int raw_argc, char *raw_argv[])
{
	int i;
	int argc;
	int envc;
	char *filename;
	char **argv;
	char **envp;
	{ /* Check that I'm an execute handler process.  */
		int fd = open("/proc/ccs/.execute_handler", O_RDONLY);
		close(fd);
		if (fd == EOF) {
			fprintf(stderr, "FATAL: I'm not execute_handler.\n");
			return 1;
		}
	}
	if (raw_argc < 7)
		return 1;
	filename = raw_argv[4];
	argc = atoi(raw_argv[5]);
	envc = atoi(raw_argv[6]);
	if (raw_argc != argc + envc + 7)
		return 1;
	for (i = 5; i < argc + 5; i++)
		raw_argv[i] = raw_argv[i + 2];
	raw_argv[argc + 5] = NULL;
	for (i = argc + 6; i < argc + envc + 6; i++)
		raw_argv[i] = raw_argv[i + 1];
	raw_argv[argc + envc + 6] = NULL;
	argv = raw_argv + 5;
	envp = raw_argv + argc + 6;

	{ /* Record parameters including argv[] and envp[]. */
		/* Get exlusive lock for serializing syslog(). */
		const int fd = open("/proc/self/exe", O_RDONLY);
		if (fd == EOF || flock(fd, LOCK_EX) == EOF)
			return 1;
		openlog(raw_argv[0], LOG_NDELAY, LOG_USER);
                syslog(LOG_INFO, "Domain = %s\n", raw_argv[1]);
                syslog(LOG_INFO, "Caller Program = %s\n", raw_argv[2]);
                syslog(LOG_INFO, "Process Status = %s\n", raw_argv[3]);
                syslog(LOG_INFO, "Requested Program = %s\n", filename);
                syslog(LOG_INFO, "argc=%d\n", argc);
                syslog(LOG_INFO, "envc=%d\n", envc);
		for (i = 0; i < argc; i++) {
			int max_len = strlen(argv[i]) * 4 + 128;
			int len;
			char *buffer = calloc(max_len, 1);
			if (!buffer)
				return 1;
			len = snprintf(buffer, 100, "argv[%d] = \"", i);
			encode(buffer + len, argv[i]);
			len = strlen(buffer);
			snprintf(buffer + len, max_len - len - 1, "\"");
			syslog(LOG_INFO, "%s\n", buffer);
			free(buffer);
		}
		for (i = 0; i < envc; i++) {
			int max_len = strlen(envp[i]) * 4 + 128;
			int len;
			char *buffer = calloc(max_len, 1);
			if (!buffer)
				return 1;
			len = snprintf(buffer, 100, "envp[%d] = \"", i);
			encode(buffer + len, envp[i]);
			len = strlen(buffer);
			snprintf(buffer + len, max_len - len - 1, "\"");
			syslog(LOG_INFO, "%s\n", buffer);
			free(buffer);
		}
		closelog();
		/* Release exclusive lock. */
		close(fd);
	}

	/* Execute requested program. */
	execve(filename, argv, envp);
	fprintf(stderr, "ERROR: Can't execute %s .\n", filename);
	return 1;
}

Step 2: Install and initialize TOMOYO Linux

Install TOMOYO Linux and run below commandline in order to initialize TOMOYO Linux.

# /usr/lib/ccs/init_policy

Then, please do below operations before you reboot using TOMOYO Linux kernel.

Append below line to /etc/ccs/exception_policy.conf in order to initialize domain transition when /usr/sbin/sshd is executed.

initialize_domain /usr/sbin/sshd from any

Append below line to /etc/ccs/exception_policy.conf in order to suppress domain transition after login shell which is executed by SSH server.

keep_domain any from <kernel> /usr/sbin/sshd /bin/bash

Append below lines to /etc/ccs/domain_policy.conf so that program execution requests from login shell which is executed by SSH server are passed to /bin/record_cmdline .

<kernel> /usr/sbin/sshd /bin/bash
task auto_execute_handler /bin/record_cmdline

Step 3: Operation

Now, you are ready to start operation. Please reboot using TOMOYO Linux kernel.

Login via SSH and do some operations. You can confirm that commandline parameters are recorded by doing below commandline.

# grep record_cmdline /var/log/messages

Explanation

TOMOYO Linux's execute_handler functionality intercepts program execution requests from login shell which in executed by SSH server and passes the program execution requests to /bin/record_cmdline . Then, /bin/record_cmdline records parameters passed to program execution requests and actually executes the requested programs.

Application idea

You can customize /bin/record_cmdline to accept or deny program execution requests based on commandline arguments because parameters passed to execution requests are passed to /bin/record_cmdline .