💾 Archived View for thrig.me › tech › openbsd › myfingerd.c captured on 2023-11-14 at 09:35:26.

View Raw

More Information

-=-=-=-=-=-=-

// myfingerd - a small finger server (to be called by inetd(8))
//
// this program reads from a ~/.lawn file if there is one for a valid
// user, or otherwise returns a generic message or otherwise exits with
// a non-zero exit status word should something go awry

#include <sys/time.h>

#include <ctype.h>
#include <fcntl.h>
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define MAXLEN 32 + 2 // max length of username + CRNL

void
handle_alarm(int sig)
{
	exit(1);
}

int
main(void)
{
	if (pledge("stdio rpath unveil", NULL) == -1) goto NOPE;

	// fail if the request takes too long, e.g. when the remote end
	// does a `telnet example.org 79` and then walks away
	struct itimerval timeout = {0};
	timeout.it_value.tv_sec  = 5;
	if (signal(SIGALRM, handle_alarm) == SIG_ERR) goto NOPE;
	if (setitimer(ITIMER_REAL, &timeout, NULL) == -1) goto NOPE;

	char user[MAXLEN + 1];
	if (fgets(user, MAXLEN + 1, stdin) == NULL) goto NOPE;

	size_t len = strnlen(user, MAXLEN);
	if (len < 2) goto NOPE;
	if (!(user[len - 1] == '\n' && user[len - 2] == '\r')) {
		if (len == MAXLEN)
			goto ALLUSERS; // the input filled our buffer
		else
			goto NOPE; // did not terminate with CRNL
	}
	len -= 2;
	if (len == 0) goto ALLUSERS;

	user[len] = '\0';
	char *ch  = user;
	// maybe you have _ or other such in your usernames? I don't
	while (*ch != '\0') {
		if (!isalnum(*ch)) goto ALLUSERS;
		ch++;
	}

	struct passwd *pw = getpwnam(user);
	if (!pw) goto ALLUSERS;
	char *home = pw->pw_dir;
	if (!home) goto ALLUSERS;
	if (chdir(home) == -1) goto ALLUSERS;

	// traditional would be ".plan" and ".project" but those
	// might be better reserved for internal use
	if (unveil(".lawn", "r") == -1) goto NOPE;
	if (unveil(NULL, NULL) == -1) goto NOPE;
	int fd = open(".lawn", O_RDONLY | O_NOFOLLOW);
	if (fd < 0) goto ALLUSERS;
	if (pledge("stdio", NULL) == -1) goto NOPE;
	char buf[4096];
	while (1) {
		ssize_t amount = read(fd, buf, sizeof(buf));
		if (amount <= 0) break;
		write(STDOUT_FILENO, buf, (size_t) amount);
	}
	//close(fd);
	exit(0);

ALLUSERS:
	if (pledge("stdio", NULL) == -1) goto NOPE;
	write(STDOUT_FILENO, "get off our lawns\n", 18);
	exit(0);

NOPE:
	exit(1);
}