1200062Sed/*-
2200062Sed * Copyright (c) 2009 Ed Schouten <ed@FreeBSD.org>
3200062Sed * All rights reserved.
4200062Sed *
5200062Sed * Redistribution and use in source and binary forms, with or without
6200062Sed * modification, are permitted provided that the following conditions
7200062Sed * are met:
8200062Sed * 1. Redistributions of source code must retain the above copyright
9200062Sed *    notice, this list of conditions and the following disclaimer.
10200062Sed * 2. Redistributions in binary form must reproduce the above copyright
11200062Sed *    notice, this list of conditions and the following disclaimer in the
12200062Sed *    documentation and/or other materials provided with the distribution.
13200062Sed *
14200062Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15200062Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16200062Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17200062Sed * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18200062Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19200062Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20200062Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21200062Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22200062Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23200062Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24200062Sed * SUCH DAMAGE.
25200062Sed */
26200062Sed
27200062Sed#include <sys/cdefs.h>
28200062Sed__FBSDID("$FreeBSD$");
29200062Sed
30200062Sed#include <pwd.h>
31200062Sed#include <unistd.h>
32200062Sed#include <stdlib.h>
33200062Sed#include <string.h>
34200062Sed#include <sysexits.h>
35200062Sed#include <ulog.h>
36200062Sed
37200062Sed/*
38200062Sed * This setuid helper utility writes user login records to disk.
39223367Sed * Unprivileged processes are not capable of writing records to utmpx,
40223367Sed * but we do want to allow this for pseudo-terminals.  Because a file
41223367Sed * descriptor to a pseudo-terminal master device can only be obtained by
42223367Sed * processes using the pseudo-terminal, we expect such a descriptor on
43223367Sed * stdin.
44200062Sed *
45200062Sed * It uses the real user ID of the calling process to determine the
46200062Sed * username.  It does allow users to log arbitrary hostnames.
47200062Sed */
48200062Sed
49234469Sedstatic const char *
50234469Sedget_username(void)
51234469Sed{
52234469Sed	const struct passwd *pw;
53234469Sed	const char *login;
54234469Sed	uid_t uid;
55234469Sed
56234469Sed	/*
57234469Sed	 * Attempt to determine the username corresponding to this login
58234469Sed	 * session.  First, validate the results of getlogin() against
59234469Sed	 * the password database.  If getlogin() returns invalid data,
60234469Sed	 * return an arbitrary username corresponding to this uid.
61234469Sed	 */
62234469Sed	uid = getuid();
63234469Sed	if ((login = getlogin()) != NULL && (pw = getpwnam(login)) != NULL &&
64234469Sed	    pw->pw_uid == uid)
65234469Sed		return (login);
66234469Sed	if ((pw = getpwuid(uid)) != NULL)
67234469Sed		return (pw->pw_name);
68234469Sed	return (NULL);
69234469Sed}
70234469Sed
71200062Sedint
72200062Sedmain(int argc, char *argv[])
73200062Sed{
74223367Sed	const char *line, *user, *host;
75200062Sed
76200062Sed	/* Device line name. */
77200062Sed	if ((line = ptsname(STDIN_FILENO)) == NULL)
78200062Sed		return (EX_USAGE);
79200062Sed
80200062Sed	if ((argc == 2 || argc == 3) && strcmp(argv[1], "login") == 0) {
81200062Sed		/* Username. */
82234469Sed		user = get_username();
83223367Sed		if (user == NULL)
84200062Sed			return (EX_OSERR);
85200062Sed
86200062Sed		/* Hostname. */
87223367Sed		host = argc == 3 ? argv[2] : NULL;
88200062Sed
89223367Sed		ulog_login(line, user, host);
90200062Sed		return (EX_OK);
91200062Sed	} else if (argc == 2 && strcmp(argv[1], "logout") == 0) {
92200085Sed		ulog_logout(line);
93200062Sed		return (EX_OK);
94200062Sed	}
95200062Sed
96200062Sed	return (EX_USAGE);
97200062Sed}
98