vtdaemon.c revision ea2722793e684f62dd496ede6243eacea967b82e
fa9e4066f08beec538e775443c5be79dd423fcabahrens/*
fa9e4066f08beec538e775443c5be79dd423fcabahrens * CDDL HEADER START
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The contents of this file are subject to the terms of the
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * Common Development and Distribution License (the "License").
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * You may not use this file except in compliance with the License.
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
fa9e4066f08beec538e775443c5be79dd423fcabahrens * or http://www.opensolaris.org/os/licensing.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * See the License for the specific language governing permissions
fa9e4066f08beec538e775443c5be79dd423fcabahrens * and limitations under the License.
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * When distributing Covered Code, include this CDDL HEADER in each
fa9e4066f08beec538e775443c5be79dd423fcabahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * If applicable, add the following below this CDDL HEADER, with the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * fields enclosed by brackets "[]" replaced with your own identifying
fa9e4066f08beec538e775443c5be79dd423fcabahrens * information: Portions Copyright [yyyy] [name of copyright owner]
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * CDDL HEADER END
fa9e4066f08beec538e775443c5be79dd423fcabahrens */
fa9e4066f08beec538e775443c5be79dd423fcabahrens
55434c770c89aa1b84474f2559a106803511aba0ek/*
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Use is subject to license terms.
fa9e4066f08beec538e775443c5be79dd423fcabahrens */
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens/*
55434c770c89aa1b84474f2559a106803511aba0ek * vtdaemon is responsible for the session secure switch via hotkeys.
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * vtdaemon itself, like ttymon(1M), is also running on a virtual
fa9e4066f08beec538e775443c5be79dd423fcabahrens * console device (/dev/vt/1), and provides a text console session
fa9e4066f08beec538e775443c5be79dd423fcabahrens * for password input and authentication. The /dev/vt/1 special text
fa9e4066f08beec538e775443c5be79dd423fcabahrens * console is reserved and end users cannot switch to it via hotkeys.
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks * The hotkey event request can come from either kernel or Xserver,
fa9e4066f08beec538e775443c5be79dd423fcabahrens * and a door server is setup to handle the request:
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * 1) All text console hotkeys (e.g. "Alt + F#") are intercepted by
fa9e4066f08beec538e775443c5be79dd423fcabahrens * the kernel console driver which sends a door upcall to the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * vtdaemon via door_upcall (target_vt).
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * 2) All Xserver hotkeys ("Alt + Ctrl + F#") are intercepted by
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Xserver which sends a door call to the vtdaemon via
fa9e4066f08beec538e775443c5be79dd423fcabahrens * door_call (target_vt).
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * server_for_door receives and handles any door server requests:
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Firstly, check source session:
104e2ed78d9ef0a0f89f320108b8ca29ca3850d5perrin *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * . If it's from kernel for a text console source session,
55434c770c89aa1b84474f2559a106803511aba0ek * then directly go to check the target session.
55434c770c89aa1b84474f2559a106803511aba0ek *
55434c770c89aa1b84474f2559a106803511aba0ek * . If it's from Xserver for a graphical source session and the vt
55434c770c89aa1b84474f2559a106803511aba0ek * associated with the Xserver is currently active:
55434c770c89aa1b84474f2559a106803511aba0ek * check if a user has logged in, if true, issue an internal
55434c770c89aa1b84474f2559a106803511aba0ek * VT_EV_LOCK event to the main thread to request lock for
55434c770c89aa1b84474f2559a106803511aba0ek * the graphical source session; else, directly go to check
fa9e4066f08beec538e775443c5be79dd423fcabahrens * the target session.
55434c770c89aa1b84474f2559a106803511aba0ek *
55434c770c89aa1b84474f2559a106803511aba0ek * . otherwise, discard this request.
55434c770c89aa1b84474f2559a106803511aba0ek *
55434c770c89aa1b84474f2559a106803511aba0ek *
55434c770c89aa1b84474f2559a106803511aba0ek * Secondly, check the target session
55434c770c89aa1b84474f2559a106803511aba0ek *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * . if the target session is a text one that no one has logged in
fa9e4066f08beec538e775443c5be79dd423fcabahrens * or a graphical one, issue an internal VT_EV_ACTIVATE event to
fa9e4066f08beec538e775443c5be79dd423fcabahrens * the main thread to request the actual VT switch.
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * . otherwise, the target session is a text one that someone has
fa9e4066f08beec538e775443c5be79dd423fcabahrens * logged in, issue an internal VT_EV_AUTH event to the main
fa9e4066f08beec538e775443c5be79dd423fcabahrens * thread to request authentication for the target session.
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * The main thread of vtdaemon is a loop waiting for internal events
fa9e4066f08beec538e775443c5be79dd423fcabahrens * which come from door call threads:
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * 1) VT_EV_AUTH to authenticate for target session:
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * firstly switch to the vtdaemon special text console;
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * then prompt for password (target_owner on target_vt),
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * e.g. "User Bob's password on vt/#: ".
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * if the password is correct (authentication succeeds),
fa9e4066f08beec538e775443c5be79dd423fcabahrens * then actually issue the VT switch; otherwise, ignore
fa9e4066f08beec538e775443c5be79dd423fcabahrens * the request.
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * 2) VT_EV_LOCK to lock the graphical source session:
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * activate screenlock for this graphical session.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * vtdaemon just invokes existing front-end command line
fa9e4066f08beec538e775443c5be79dd423fcabahrens * tools (e.g. xscreensaver-command -lock for JDS) to
fa9e4066f08beec538e775443c5be79dd423fcabahrens * lock the display.
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * 3) VT_EV_ACTIVATE to directly switch to the target session
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
104e2ed78d9ef0a0f89f320108b8ca29ca3850d5perrin *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * There is a system/vtdaemon:default SMF service for vtdaemon.
104e2ed78d9ef0a0f89f320108b8ca29ca3850d5perrin *
104e2ed78d9ef0a0f89f320108b8ca29ca3850d5perrin * There's a "hotkeys" property (BOOLEAN) in the
104e2ed78d9ef0a0f89f320108b8ca29ca3850d5perrin * system/vtdaemon:default SMF service, which allows authorized
104e2ed78d9ef0a0f89f320108b8ca29ca3850d5perrin * users to dynamically enable or disable VT switch via hotkeys.
104e2ed78d9ef0a0f89f320108b8ca29ca3850d5perrin * Its default value is TRUE (enabled).
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * There's a "secure" property (BOOLEAN) in the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * system/vtdaemon:default SMF service, which allows authorized
fa9e4066f08beec538e775443c5be79dd423fcabahrens * users to dynamically enable or disable hotkeys are secure.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * If disabled, the user can freely switch to any session without
fa9e4066f08beec538e775443c5be79dd423fcabahrens * authentication. Its default value is TRUE (enabled).
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * By default, there's only 16 virtual console device nodes (from
fa9e4066f08beec538e775443c5be79dd423fcabahrens * /dev/vt/0 to /dev/vt/15). There's a property "nodecount"
fa9e4066f08beec538e775443c5be79dd423fcabahrens * (default value is 16) in the system/vtdaemon:default SMF
fa9e4066f08beec538e775443c5be79dd423fcabahrens * service, so authorized users can configure it to have more
fa9e4066f08beec538e775443c5be79dd423fcabahrens * or less virtual console device nodes.
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
104e2ed78d9ef0a0f89f320108b8ca29ca3850d5perrin * Xserver needs to switch back to previous active vt via VT_EV_X_EXIT
fa9e4066f08beec538e775443c5be79dd423fcabahrens * door event request when it's exiting, so vtdaemon always needs to
104e2ed78d9ef0a0f89f320108b8ca29ca3850d5perrin * be there even if the hotkeys switch is disabled, otherwise the screen
fa9e4066f08beec538e775443c5be79dd423fcabahrens * will be just blank when Xserver exits.
fa9e4066f08beec538e775443c5be79dd423fcabahrens */
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <sys/param.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <sys/mman.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <sys/types.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <sys/wait.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <sys/stat.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <sys/sysmacros.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <syslog.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <deflt.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <bsm/adt.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <bsm/adt_event.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <alloca.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <assert.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <errno.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <door.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <fcntl.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <signal.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <stdarg.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <stdio.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <stdlib.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <string.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <strings.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <synch.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <thread.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <unistd.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <wait.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <limits.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <zone.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <priv.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <pwd.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <utmpx.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <procfs.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <poll.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <termio.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <security/pam_appl.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <time.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <sys/console.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <assert.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <syslog.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <sys/vt.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens#include <sys/vtdaemon.h>
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens/*
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The door file /var/run/vt/vtdaemon_door
fa9e4066f08beec538e775443c5be79dd423fcabahrens */
fa9e4066f08beec538e775443c5be79dd423fcabahrens#define VT_TMPDIR "/var/run/vt"
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens#define VT_DAEMON_ARG 0
fa9e4066f08beec538e775443c5be79dd423fcabahrens#define VT_DAEMON_CONSOLE_FILE "/dev/vt/1"
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens#define VT_IS_SYSTEM_CONSOLE(vtno) ((vtno) == 1)
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens/* Defaults for updating expired passwords */
fa9e4066f08beec538e775443c5be79dd423fcabahrens#define DEF_ATTEMPTS 3
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrensint daemonfd;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic boolean_t vt_hotkeys = B_TRUE; /* '-k' option to disable */
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic boolean_t vt_secure = B_TRUE; /* '-s' option to disable */
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic char vt_door_path[MAXPATHLEN];
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic int vt_door = -1;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens/* protecting vt_hotkeys_pending and vt_auth_doing */
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic mutex_t vt_mutex = DEFAULTMUTEX;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic boolean_t vt_hotkeys_pending = B_FALSE;
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic boolean_t vt_auth_doing = B_FALSE;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic adt_session_data_t **vt_ah_array = NULL;
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic int vtnodecount = 0;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic int vt_audit_start(adt_session_data_t **, pid_t);
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic void vt_audit_event(adt_session_data_t *, au_event_t, int);
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic void vt_check_source_audit(void);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic int
fa9e4066f08beec538e775443c5be79dd423fcabahrensvt_setup_signal(int signo, int mask)
fa9e4066f08beec538e775443c5be79dd423fcabahrens{
fa9e4066f08beec538e775443c5be79dd423fcabahrens sigset_t set;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) sigemptyset(&set);
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) sigaddset(&set, signo);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (mask)
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (sigprocmask(SIG_BLOCK, &set, NULL));
fa9e4066f08beec538e775443c5be79dd423fcabahrens else
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (sigprocmask(SIG_UNBLOCK, &set, NULL));
fa9e4066f08beec538e775443c5be79dd423fcabahrens}
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic void
fa9e4066f08beec538e775443c5be79dd423fcabahrensdo_activate_screenlock(int display_num)
fa9e4066f08beec538e775443c5be79dd423fcabahrens{
fa9e4066f08beec538e775443c5be79dd423fcabahrens char dpy[16];
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) snprintf(dpy, sizeof (dpy), "%d", display_num);
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) execl("/usr/lib/vtxlock", "vtxlock", dpy, NULL);
fa9e4066f08beec538e775443c5be79dd423fcabahrens}
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic void
fa9e4066f08beec538e775443c5be79dd423fcabahrensvt_activate_screenlock(int display)
fa9e4066f08beec538e775443c5be79dd423fcabahrens{
fa9e4066f08beec538e775443c5be79dd423fcabahrens pid_t pid;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens if ((pid = fork()) == -1)
fa9e4066f08beec538e775443c5be79dd423fcabahrens return;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (pid == 0) { /* child */
fa9e4066f08beec538e775443c5be79dd423fcabahrens do_activate_screenlock(display);
fa9e4066f08beec538e775443c5be79dd423fcabahrens exit(0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* parent */
fa9e4066f08beec538e775443c5be79dd423fcabahrens while (waitpid(pid, (int *)0, 0) != pid)
fa9e4066f08beec538e775443c5be79dd423fcabahrens continue;
fa9e4066f08beec538e775443c5be79dd423fcabahrens}
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens/*
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Find the login process and user logged in on the target vt.
fa9e4066f08beec538e775443c5be79dd423fcabahrens */
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic void
eaca9bbd5f5d1e4e554da4c7108e8a03c8c33481eschrockvt_read_utx(int target_vt, pid_t *pid, char name[])
fa9e4066f08beec538e775443c5be79dd423fcabahrens{
fa9e4066f08beec538e775443c5be79dd423fcabahrens struct utmpx *u;
a2eea2e101e6a163a537dcc6d4e3c4da2a0ea5b2ahrens char ttyntail[sizeof (u->ut_line)];
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens *pid = (pid_t)-1;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (VT_IS_SYSTEM_CONSOLE(target_vt)) /* system console */
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) snprintf(ttyntail, sizeof (ttyntail),
fa9e4066f08beec538e775443c5be79dd423fcabahrens "%s", "console");
fa9e4066f08beec538e775443c5be79dd423fcabahrens else
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) snprintf(ttyntail, sizeof (ttyntail),
fa9e4066f08beec538e775443c5be79dd423fcabahrens "%s%d", "vt/", target_vt);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock setutxent();
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock while ((u = getutxent()) != NULL)
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* see if this is the entry we want */
fa9e4066f08beec538e775443c5be79dd423fcabahrens if ((u->ut_type == USER_PROCESS) &&
fa9e4066f08beec538e775443c5be79dd423fcabahrens (!nonuserx(*u)) &&
fa9e4066f08beec538e775443c5be79dd423fcabahrens (u->ut_host[0] == '\0') &&
fa9e4066f08beec538e775443c5be79dd423fcabahrens (strncmp(u->ut_line, ttyntail, sizeof (u->ut_line)) == 0)) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens *pid = u->ut_pid;
eaca9bbd5f5d1e4e554da4c7108e8a03c8c33481eschrock if (name != NULL) {
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock (void) strncpy(name, u->ut_user,
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock sizeof (u->ut_user));
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock name[sizeof (u->ut_user)] = '\0';
eaca9bbd5f5d1e4e554da4c7108e8a03c8c33481eschrock }
fa9e4066f08beec538e775443c5be79dd423fcabahrens break;
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens
eaca9bbd5f5d1e4e554da4c7108e8a03c8c33481eschrock endutxent();
fa9e4066f08beec538e775443c5be79dd423fcabahrens}
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic boolean_t
fa9e4066f08beec538e775443c5be79dd423fcabahrensvt_is_tipline(void)
fa9e4066f08beec538e775443c5be79dd423fcabahrens{
fa9e4066f08beec538e775443c5be79dd423fcabahrens static int is_tipline = 0;
fa9e4066f08beec538e775443c5be79dd423fcabahrens int fd;
fa9e4066f08beec538e775443c5be79dd423fcabahrens static char termbuf[MAX_TERM_TYPE_LEN];
fa9e4066f08beec538e775443c5be79dd423fcabahrens static struct cons_getterm cons_term = { sizeof (termbuf), termbuf};
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (is_tipline != 0)
a2eea2e101e6a163a537dcc6d4e3c4da2a0ea5b2ahrens return (is_tipline == 1);
a2eea2e101e6a163a537dcc6d4e3c4da2a0ea5b2ahrens
a2eea2e101e6a163a537dcc6d4e3c4da2a0ea5b2ahrens if ((fd = open("/dev/console", O_RDONLY)) < 0)
a2eea2e101e6a163a537dcc6d4e3c4da2a0ea5b2ahrens return (B_FALSE);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (ioctl(fd, CONS_GETTERM, &cons_term) != 0 &&
893a6d32980d24be1349478f44169009d4801c25ahrens errno == ENODEV) {
893a6d32980d24be1349478f44169009d4801c25ahrens is_tipline = 1;
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock } else {
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock is_tipline = -1;
893a6d32980d24be1349478f44169009d4801c25ahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) close(fd);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (is_tipline == 1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens}
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic int
fa9e4066f08beec538e775443c5be79dd423fcabahrensvalidate_target_vt(int target_vt)
fa9e4066f08beec538e775443c5be79dd423fcabahrens{
fa9e4066f08beec538e775443c5be79dd423fcabahrens int fd;
fa9e4066f08beec538e775443c5be79dd423fcabahrens struct vt_stat state;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
893a6d32980d24be1349478f44169009d4801c25ahrens if (target_vt < 1)
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
893a6d32980d24be1349478f44169009d4801c25ahrens if ((fd = open(VT_DAEMON_CONSOLE_FILE, O_WRONLY)) < 0)
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
893a6d32980d24be1349478f44169009d4801c25ahrens
893a6d32980d24be1349478f44169009d4801c25ahrens if (ioctl(fd, VT_GETSTATE, &state) != 0) {
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock (void) close(fd);
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) close(fd);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks if (state.v_active == target_vt) {
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks return (1); /* it's current active vt */
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks }
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks if (target_vt == 1) {
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks /*
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks * In tipline case, the system console is always
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks * available, so ignore this request.
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks */
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks if (vt_is_tipline())
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks return (-1);
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks target_vt = 0;
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks }
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks /*
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks * The hotkey request and corresponding target_vt number can come
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks * from either kernel or Xserver (or other user applications).
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks * In kernel we've validated the hotkey request, but Xserver (or
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks * other user applications) cannot do it, so here we still try
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks * to validate it.
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks *
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks * VT_GETSTATE is only valid for first 16 VTs for historical reasons.
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks * Fortunately, in practice, Xserver can only send the hotkey
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks * request of target_vt number from 1 to 12 (Ctrl + Alt + F1 to F2).
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks */
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks if (target_vt < 8 * sizeof (state.v_state)) {
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks if ((state.v_state & (1 << target_vt)) != 0) {
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks return (0);
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks } else {
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks return (-1);
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks }
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks }
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks return (0);
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks}
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarksstatic void
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarksvt_do_activate(int target_vt)
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks{
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks (void) ioctl(daemonfd, VT_ACTIVATE, target_vt);
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks (void) mutex_lock(&vt_mutex);
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks vt_hotkeys_pending = B_FALSE;
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks (void) mutex_unlock(&vt_mutex);
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks}
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks/* events written to fd 0 and read from fd 1 */
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks#define VT_EV_AUTH 1
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks#define VT_EV_LOCK 2
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks#define VT_EV_ACTIVATE 3
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks/* events written to fd 1 and read from fd 0 */
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks#define VT_EV_TERMINATE_AUTH 4
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarkstypedef struct vt_evt {
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks int ve_cmd;
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks int ve_info; /* vtno or display num */
fa9e4066f08beec538e775443c5be79dd423fcabahrens} vt_evt_t;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic int eventstream[2];
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrensboolean_t
fa9e4066f08beec538e775443c5be79dd423fcabahrenseventstream_init(void)
fa9e4066f08beec538e775443c5be79dd423fcabahrens{
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock if (pipe(eventstream) == -1)
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (B_FALSE);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (B_TRUE);
fa9e4066f08beec538e775443c5be79dd423fcabahrens}
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrensvoid
fa9e4066f08beec538e775443c5be79dd423fcabahrenseventstream_write(int channel, vt_evt_t *pevt)
fa9e4066f08beec538e775443c5be79dd423fcabahrens{
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) write(eventstream[channel], pevt, sizeof (vt_evt_t));
fa9e4066f08beec538e775443c5be79dd423fcabahrens}
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic boolean_t
893a6d32980d24be1349478f44169009d4801c25ahrenseventstream_read(int channel, vt_evt_t *pevt)
fa9e4066f08beec538e775443c5be79dd423fcabahrens{
fa9e4066f08beec538e775443c5be79dd423fcabahrens ssize_t rval;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens rval = read(eventstream[channel], pevt, sizeof (vt_evt_t));
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (rval > 0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens}
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic void
67bd71c6cc629bab3aa0d595c624a667f1574254perrinvt_ev_request(int cmd, int info)
fa9e4066f08beec538e775443c5be79dd423fcabahrens{
fa9e4066f08beec538e775443c5be79dd423fcabahrens int channel;
fa9e4066f08beec538e775443c5be79dd423fcabahrens vt_evt_t ve;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens ve.ve_cmd = cmd;
fa9e4066f08beec538e775443c5be79dd423fcabahrens ve.ve_info = info;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens channel = (cmd == VT_EV_TERMINATE_AUTH) ? 1 : 0;
fa9e4066f08beec538e775443c5be79dd423fcabahrens eventstream_write(channel, &ve);
fa9e4066f08beec538e775443c5be79dd423fcabahrens}
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic void
fa9e4066f08beec538e775443c5be79dd423fcabahrensvt_clear_events(void)
fa9e4066f08beec538e775443c5be79dd423fcabahrens{
fa9e4066f08beec538e775443c5be79dd423fcabahrens int rval = 0;
fa9e4066f08beec538e775443c5be79dd423fcabahrens struct stat buf;
fa9e4066f08beec538e775443c5be79dd423fcabahrens vt_evt_t evt;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
7f6e3e7d4ebf3d6d45073854bef004ca26f8e918perrin while (rval == 0) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens rval = fstat(eventstream[0], &buf);
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (rval != -1 && buf.st_size > 0)
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) eventstream_read(0, &evt);
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks else
fa9e4066f08beec538e775443c5be79dd423fcabahrens break;
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens}
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic int vt_conv(int, struct pam_message **,
fa9e4066f08beec538e775443c5be79dd423fcabahrens struct pam_response **, void *);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens/*ARGSUSED*/
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic void
fa9e4066f08beec538e775443c5be79dd423fcabahrenscatch(int x)
fa9e4066f08beec538e775443c5be79dd423fcabahrens{
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) signal(SIGINT, catch);
fa9e4066f08beec538e775443c5be79dd423fcabahrens}
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens/*
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The SIGINT (ctl_c) will restart the authentication, and re-prompt
fa9e4066f08beec538e775443c5be79dd423fcabahrens * the end user to input the password.
fa9e4066f08beec538e775443c5be79dd423fcabahrens */
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic int
fa9e4066f08beec538e775443c5be79dd423fcabahrensvt_poll()
fa9e4066f08beec538e775443c5be79dd423fcabahrens{
fa9e4066f08beec538e775443c5be79dd423fcabahrens struct pollfd pollfds[2];
fa9e4066f08beec538e775443c5be79dd423fcabahrens vt_evt_t ve;
fa9e4066f08beec538e775443c5be79dd423fcabahrens int ret;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens pollfds[0].fd = eventstream[0];
fa9e4066f08beec538e775443c5be79dd423fcabahrens pollfds[1].fd = daemonfd;
fa9e4066f08beec538e775443c5be79dd423fcabahrens pollfds[0].events = pollfds[1].events =
fa9e4066f08beec538e775443c5be79dd423fcabahrens POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens for (;;) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens pollfds[0].revents = pollfds[1].revents = 0;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens ret = poll(pollfds,
fa9e4066f08beec538e775443c5be79dd423fcabahrens sizeof (pollfds) / sizeof (struct pollfd), -1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (ret == -1 && errno != EINTR) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens continue;
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (ret == -1 && errno == EINTR)
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (pollfds[0].revents) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) eventstream_read(0, &ve);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (pollfds[1].revents)
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens}
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic char
fa9e4066f08beec538e775443c5be79dd423fcabahrensvt_getchar(int fd)
fa9e4066f08beec538e775443c5be79dd423fcabahrens{
fa9e4066f08beec538e775443c5be79dd423fcabahrens char c;
fa9e4066f08beec538e775443c5be79dd423fcabahrens int cnt;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens cnt = read(fd, &c, 1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (cnt > 0) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (c);
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (EOF);
fa9e4066f08beec538e775443c5be79dd423fcabahrens}
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic char *
fa9e4066f08beec538e775443c5be79dd423fcabahrensvt_getinput(int noecho)
fa9e4066f08beec538e775443c5be79dd423fcabahrens{
fa9e4066f08beec538e775443c5be79dd423fcabahrens int c;
fa9e4066f08beec538e775443c5be79dd423fcabahrens int i = 0;
fa9e4066f08beec538e775443c5be79dd423fcabahrens struct termio tty;
fa9e4066f08beec538e775443c5be79dd423fcabahrens tcflag_t tty_flags;
fa9e4066f08beec538e775443c5be79dd423fcabahrens char input[PAM_MAX_RESP_SIZE];
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (noecho) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) ioctl(daemonfd, TCGETA, &tty);
fa9e4066f08beec538e775443c5be79dd423fcabahrens tty_flags = tty.c_lflag;
fa9e4066f08beec538e775443c5be79dd423fcabahrens tty.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) ioctl(daemonfd, TCSETAF, &tty);
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens while ((vt_poll()) == 1) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens if ((c = vt_getchar(daemonfd)) != '\n' && c != '\r' &&
fa9e4066f08beec538e775443c5be79dd423fcabahrens c != EOF && (i < PAM_MAX_RESP_SIZE))
fa9e4066f08beec538e775443c5be79dd423fcabahrens input[i++] = (char)c;
fa9e4066f08beec538e775443c5be79dd423fcabahrens else
fa9e4066f08beec538e775443c5be79dd423fcabahrens break;
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens input[i] = '\0';
fa9e4066f08beec538e775443c5be79dd423fcabahrens
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock if (noecho) {
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock tty.c_lflag = tty_flags;
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock (void) ioctl(daemonfd, TCSETAW, &tty);
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock (void) fputc('\n', stdout);
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock }
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (strdup(input));
fa9e4066f08beec538e775443c5be79dd423fcabahrens}
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens/*
fa9e4066f08beec538e775443c5be79dd423fcabahrens * vt_conv: vtdaemon PAM conversation function.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * SIGINT/EINTR is handled in vt_getinput()/vt_poll().
fa9e4066f08beec538e775443c5be79dd423fcabahrens */
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens/*ARGSUSED*/
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic int
fa9e4066f08beec538e775443c5be79dd423fcabahrensvt_conv(int num_msg, struct pam_message **msg,
fa9e4066f08beec538e775443c5be79dd423fcabahrens struct pam_response **response, void *appdata_ptr)
fa9e4066f08beec538e775443c5be79dd423fcabahrens{
fa9e4066f08beec538e775443c5be79dd423fcabahrens struct pam_message *m;
fa9e4066f08beec538e775443c5be79dd423fcabahrens struct pam_response *r;
fa9e4066f08beec538e775443c5be79dd423fcabahrens int i, k;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (num_msg >= PAM_MAX_NUM_MSG) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens syslog(LOG_ERR, "too many messages %d >= %d",
fa9e4066f08beec538e775443c5be79dd423fcabahrens num_msg, PAM_MAX_NUM_MSG);
fa9e4066f08beec538e775443c5be79dd423fcabahrens *response = NULL;
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (PAM_CONV_ERR);
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock
fa9e4066f08beec538e775443c5be79dd423fcabahrens *response = calloc(num_msg, sizeof (struct pam_response));
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (*response == NULL)
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (PAM_BUF_ERR);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens m = *msg;
fa9e4066f08beec538e775443c5be79dd423fcabahrens r = *response;
fa9e4066f08beec538e775443c5be79dd423fcabahrens for (i = 0; i < num_msg; i++) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens int echo_off = 0;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* Bad message */
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (m->msg == NULL) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens syslog(LOG_ERR, "message[%d]: %d/NULL\n",
fa9e4066f08beec538e775443c5be79dd423fcabahrens i, m->msg_style);
fa9e4066f08beec538e775443c5be79dd423fcabahrens goto err;
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens /*
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Fix up final newline:
fa9e4066f08beec538e775443c5be79dd423fcabahrens * remove from prompts, add back for messages.
fa9e4066f08beec538e775443c5be79dd423fcabahrens */
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (m->msg[strlen(m->msg)] == '\n')
fa9e4066f08beec538e775443c5be79dd423fcabahrens m->msg[strlen(m->msg)] = '\0';
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens r->resp = NULL;
fa9e4066f08beec538e775443c5be79dd423fcabahrens r->resp_retcode = 0;
72fc53bc90bd3b199d29d03ee68adb4a5a17d35bmarks
fa9e4066f08beec538e775443c5be79dd423fcabahrens switch (m->msg_style) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens case PAM_PROMPT_ECHO_OFF:
fa9e4066f08beec538e775443c5be79dd423fcabahrens echo_off = 1;
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* FALLTHROUGH */
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens case PAM_PROMPT_ECHO_ON:
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) fputs(m->msg, stdout);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens r->resp = vt_getinput(echo_off);
fa9e4066f08beec538e775443c5be79dd423fcabahrens break;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens case PAM_ERROR_MSG:
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* the user may want to see this */
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) fputs(m->msg, stdout);
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) fputs("\n", stdout);
fa9e4066f08beec538e775443c5be79dd423fcabahrens break;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens case PAM_TEXT_INFO:
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) fputs(m->msg, stdout);
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) fputs("\n", stdout);
fa9e4066f08beec538e775443c5be79dd423fcabahrens break;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens default:
fa9e4066f08beec538e775443c5be79dd423fcabahrens syslog(LOG_ERR, "message[%d]: unknown type"
fa9e4066f08beec538e775443c5be79dd423fcabahrens "%d/val=\"%s\"", i, m->msg_style, m->msg);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* error, service module won't clean up */
fa9e4066f08beec538e775443c5be79dd423fcabahrens goto err;
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* Next message/response */
fa9e4066f08beec538e775443c5be79dd423fcabahrens m++;
fa9e4066f08beec538e775443c5be79dd423fcabahrens r++;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (PAM_SUCCESS);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrockerr:
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock /*
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Service modules don't clean up responses if an error is returned.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Free responses here.
fa9e4066f08beec538e775443c5be79dd423fcabahrens */
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock r = *response;
fa9e4066f08beec538e775443c5be79dd423fcabahrens for (k = 0; k < i; k++, r++) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (r->resp) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* Clear before freeing -- maybe a password */
fa9e4066f08beec538e775443c5be79dd423fcabahrens bzero(r->resp, strlen(r->resp));
fa9e4066f08beec538e775443c5be79dd423fcabahrens free(r->resp);
fa9e4066f08beec538e775443c5be79dd423fcabahrens r->resp = NULL;
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens free(*response);
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock *response = NULL;
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (PAM_CONV_ERR);
fa9e4066f08beec538e775443c5be79dd423fcabahrens}
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens#define DEF_FILE "/etc/default/login"
fa9e4066f08beec538e775443c5be79dd423fcabahrens
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock/* Get PASSREQ from default file */
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrockstatic boolean_t
fa9e4066f08beec538e775443c5be79dd423fcabahrensvt_default(void)
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock{
fa9e4066f08beec538e775443c5be79dd423fcabahrens int flags;
fa9e4066f08beec538e775443c5be79dd423fcabahrens char *ptr;
fa9e4066f08beec538e775443c5be79dd423fcabahrens boolean_t retval = B_FALSE;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens if ((defopen(DEF_FILE)) == 0) {
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock /* ignore case */
fa9e4066f08beec538e775443c5be79dd423fcabahrens flags = defcntl(DC_GETFLAGS, 0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens TURNOFF(flags, DC_CASE);
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) defcntl(DC_SETFLAGS, flags);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens if ((ptr = defread("PASSREQ=")) != NULL &&
fa9e4066f08beec538e775443c5be79dd423fcabahrens strcasecmp("YES", ptr) == 0)
fa9e4066f08beec538e775443c5be79dd423fcabahrens retval = B_TRUE;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) defopen(NULL);
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (retval);
fa9e4066f08beec538e775443c5be79dd423fcabahrens}
fa9e4066f08beec538e775443c5be79dd423fcabahrens
893a6d32980d24be1349478f44169009d4801c25ahrens/*
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * VT_CLEAR_SCREEN_STR is the console terminal escape sequence used to
fa9e4066f08beec538e775443c5be79dd423fcabahrens * clear the current screen. The vt special console (/dev/vt/1) is
fa9e4066f08beec538e775443c5be79dd423fcabahrens * just reserved for vtdaemon, and the TERM/termcap of it is always
fa9e4066f08beec538e775443c5be79dd423fcabahrens * the local sun-color, which is always supported by our kernel terminal
fa9e4066f08beec538e775443c5be79dd423fcabahrens * emulator.
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock */
fa9e4066f08beec538e775443c5be79dd423fcabahrens#define VT_CLEAR_SCREEN_STR "\033[2J\033[1;1H"
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic void
fa9e4066f08beec538e775443c5be79dd423fcabahrensvt_do_auth(int target_vt)
fa9e4066f08beec538e775443c5be79dd423fcabahrens{
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock char user_name[sizeof (((struct utmpx *)0)->ut_line) + 1] = {'\0'};
fa9e4066f08beec538e775443c5be79dd423fcabahrens pam_handle_t *vt_pamh;
fa9e4066f08beec538e775443c5be79dd423fcabahrens int err;
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock int pam_flag = 0;
fa9e4066f08beec538e775443c5be79dd423fcabahrens int chpasswd_tries;
fa9e4066f08beec538e775443c5be79dd423fcabahrens struct pam_conv pam_conv = {vt_conv, NULL};
fa9e4066f08beec538e775443c5be79dd423fcabahrens pid_t pid;
fa9e4066f08beec538e775443c5be79dd423fcabahrens adt_session_data_t *ah;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens vt_read_utx(target_vt, &pid, user_name);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (pid == (pid_t)-1 || user_name[0] == '\0')
fa9e4066f08beec538e775443c5be79dd423fcabahrens return;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock if ((err = pam_start("vtdaemon", user_name, &pam_conv,
fa9e4066f08beec538e775443c5be79dd423fcabahrens &vt_pamh)) != PAM_SUCCESS)
fa9e4066f08beec538e775443c5be79dd423fcabahrens return;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens /*
fa9e4066f08beec538e775443c5be79dd423fcabahrens * firstly switch to the vtdaemon special console
fa9e4066f08beec538e775443c5be79dd423fcabahrens * and clear the current screen
fa9e4066f08beec538e775443c5be79dd423fcabahrens */
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) ioctl(daemonfd, VT_ACTIVATE, VT_DAEMON_ARG);
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) write(daemonfd, VT_CLEAR_SCREEN_STR,
fa9e4066f08beec538e775443c5be79dd423fcabahrens strlen(VT_CLEAR_SCREEN_STR));
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) ioctl(daemonfd, VT_SET_TARGET, target_vt);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) mutex_lock(&vt_mutex);
fa9e4066f08beec538e775443c5be79dd423fcabahrens vt_auth_doing = B_TRUE;
fa9e4066f08beec538e775443c5be79dd423fcabahrens vt_hotkeys_pending = B_FALSE;
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) mutex_unlock(&vt_mutex);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens /*
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Fetch audit handle.
fa9e4066f08beec538e775443c5be79dd423fcabahrens */
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock ah = vt_ah_array[target_vt - 1];
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (vt_default())
fa9e4066f08beec538e775443c5be79dd423fcabahrens pam_flag = PAM_DISALLOW_NULL_AUTHTOK;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens do {
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (VT_IS_SYSTEM_CONSOLE(target_vt))
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) fprintf(stdout,
fa9e4066f08beec538e775443c5be79dd423fcabahrens "\nUnlock user %s on the system console\n",
fa9e4066f08beec538e775443c5be79dd423fcabahrens user_name);
fa9e4066f08beec538e775443c5be79dd423fcabahrens else
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) fprintf(stdout,
fa9e4066f08beec538e775443c5be79dd423fcabahrens "\nUnlock user %s on vt/%d\n", user_name,
fa9e4066f08beec538e775443c5be79dd423fcabahrens target_vt);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens err = pam_authenticate(vt_pamh, pam_flag);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) mutex_lock(&vt_mutex);
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (vt_hotkeys_pending) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) mutex_unlock(&vt_mutex);
fa9e4066f08beec538e775443c5be79dd423fcabahrens break;
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) mutex_unlock(&vt_mutex);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (err == PAM_SUCCESS) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens err = pam_acct_mgmt(vt_pamh, pam_flag);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) mutex_lock(&vt_mutex);
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (vt_hotkeys_pending) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) mutex_unlock(&vt_mutex);
fa9e4066f08beec538e775443c5be79dd423fcabahrens break;
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) mutex_unlock(&vt_mutex);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (err == PAM_NEW_AUTHTOK_REQD) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens chpasswd_tries = 0;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens do {
fa9e4066f08beec538e775443c5be79dd423fcabahrens err = pam_chauthtok(vt_pamh,
fa9e4066f08beec538e775443c5be79dd423fcabahrens PAM_CHANGE_EXPIRED_AUTHTOK);
fa9e4066f08beec538e775443c5be79dd423fcabahrens chpasswd_tries++;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) mutex_lock(&vt_mutex);
893a6d32980d24be1349478f44169009d4801c25ahrens if (vt_hotkeys_pending) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) mutex_unlock(&vt_mutex);
fa9e4066f08beec538e775443c5be79dd423fcabahrens break;
893a6d32980d24be1349478f44169009d4801c25ahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) mutex_unlock(&vt_mutex);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens } while ((err == PAM_AUTHTOK_ERR ||
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock err == PAM_TRY_AGAIN) &&
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock chpasswd_tries < DEF_ATTEMPTS);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock (void) mutex_lock(&vt_mutex);
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (vt_hotkeys_pending) {
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock (void) mutex_unlock(&vt_mutex);
fa9e4066f08beec538e775443c5be79dd423fcabahrens break;
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock }
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) mutex_unlock(&vt_mutex);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens vt_audit_event(ah, ADT_passwd, err);
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens /*
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Only audit failed unlock here, successful unlock
fa9e4066f08beec538e775443c5be79dd423fcabahrens * will be audited after switching to target vt.
fa9e4066f08beec538e775443c5be79dd423fcabahrens */
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (err != PAM_SUCCESS) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) fprintf(stdout, "%s",
fa9e4066f08beec538e775443c5be79dd423fcabahrens pam_strerror(vt_pamh, err));
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens vt_audit_event(ah, ADT_screenunlock, err);
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) mutex_lock(&vt_mutex);
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (vt_hotkeys_pending) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) mutex_unlock(&vt_mutex);
fa9e4066f08beec538e775443c5be79dd423fcabahrens break;
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) mutex_unlock(&vt_mutex);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens } while (err != PAM_SUCCESS);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) mutex_lock(&vt_mutex);
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (!vt_hotkeys_pending) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens /*
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Should be PAM_SUCCESS to reach here.
fa9e4066f08beec538e775443c5be79dd423fcabahrens */
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) ioctl(daemonfd, VT_ACTIVATE, target_vt);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens vt_audit_event(ah, ADT_screenunlock, err);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens /*
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Free audit handle.
fa9e4066f08beec538e775443c5be79dd423fcabahrens */
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) adt_end_session(ah);
fa9e4066f08beec538e775443c5be79dd423fcabahrens vt_ah_array[target_vt - 1] = NULL;
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) mutex_unlock(&vt_mutex);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) pam_end(vt_pamh, err);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (user_name != NULL)
fa9e4066f08beec538e775443c5be79dd423fcabahrens free(user_name);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) mutex_lock(&vt_mutex);
fa9e4066f08beec538e775443c5be79dd423fcabahrens vt_auth_doing = B_FALSE;
fa9e4066f08beec538e775443c5be79dd423fcabahrens vt_clear_events();
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) mutex_unlock(&vt_mutex);
fa9e4066f08beec538e775443c5be79dd423fcabahrens}
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens/* main thread (lock and auth) */
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic void __NORETURN
fa9e4066f08beec538e775443c5be79dd423fcabahrensvt_serve_events(void)
fa9e4066f08beec538e775443c5be79dd423fcabahrens{
fa9e4066f08beec538e775443c5be79dd423fcabahrens struct pollfd pollfds[1];
fa9e4066f08beec538e775443c5be79dd423fcabahrens int ret;
fa9e4066f08beec538e775443c5be79dd423fcabahrens vt_evt_t ve;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
104e2ed78d9ef0a0f89f320108b8ca29ca3850d5perrin pollfds[0].fd = eventstream[1];
fa9e4066f08beec538e775443c5be79dd423fcabahrens pollfds[0].events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens for (;;) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens pollfds[0].revents = 0;
fa9e4066f08beec538e775443c5be79dd423fcabahrens ret = poll(pollfds,
fa9e4066f08beec538e775443c5be79dd423fcabahrens sizeof (pollfds) / sizeof (struct pollfd), -1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (ret == -1 && errno == EINTR) {
104e2ed78d9ef0a0f89f320108b8ca29ca3850d5perrin continue;
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (pollfds[0].revents && eventstream_read(1, &ve)) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* new request */
fa9e4066f08beec538e775443c5be79dd423fcabahrens switch (ve.ve_cmd) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens case VT_EV_AUTH:
104e2ed78d9ef0a0f89f320108b8ca29ca3850d5perrin vt_do_auth(ve.ve_info);
fa9e4066f08beec538e775443c5be79dd423fcabahrens break;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens case VT_EV_LOCK:
fa9e4066f08beec538e775443c5be79dd423fcabahrens vt_activate_screenlock(ve.ve_info);
fa9e4066f08beec538e775443c5be79dd423fcabahrens break;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
104e2ed78d9ef0a0f89f320108b8ca29ca3850d5perrin case VT_EV_ACTIVATE:
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* directly activate target vt */
fa9e4066f08beec538e775443c5be79dd423fcabahrens vt_do_activate(ve.ve_info);
fa9e4066f08beec538e775443c5be79dd423fcabahrens break;
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
104e2ed78d9ef0a0f89f320108b8ca29ca3850d5perrin }
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens}
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic void
fa9e4066f08beec538e775443c5be79dd423fcabahrensvt_check_target_session(uint32_t target_vt)
fa9e4066f08beec538e775443c5be79dd423fcabahrens{
fa9e4066f08beec538e775443c5be79dd423fcabahrens pid_t pid = (pid_t)-1;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (!vt_secure) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens vt_ev_request(VT_EV_ACTIVATE, target_vt);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return;
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* check the target session */
fa9e4066f08beec538e775443c5be79dd423fcabahrens vt_read_utx(target_vt, &pid, NULL);
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (pid == (pid_t)-1) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens vt_ev_request(VT_EV_ACTIVATE, target_vt);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return;
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens vt_ev_request(VT_EV_AUTH, target_vt);
104e2ed78d9ef0a0f89f320108b8ca29ca3850d5perrin}
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic boolean_t
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybeevt_get_active_disp_info(struct vt_dispinfo *vd)
fa9e4066f08beec538e775443c5be79dd423fcabahrens{
fa9e4066f08beec538e775443c5be79dd423fcabahrens int fd;
fa9e4066f08beec538e775443c5be79dd423fcabahrens struct vt_stat state;
fa9e4066f08beec538e775443c5be79dd423fcabahrens char vtname[16];
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens if ((fd = open(VT_DAEMON_CONSOLE_FILE, O_RDONLY)) < 0)
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (B_FALSE);
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (ioctl(fd, VT_GETSTATE, &state) != 0) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) close(fd);
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee return (B_FALSE);
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee }
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee (void) close(fd);
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee (void) snprintf(vtname, sizeof (vtname), "/dev/vt/%d", state.v_active);
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee if ((fd = open(vtname, O_RDONLY)) < 0)
104e2ed78d9ef0a0f89f320108b8ca29ca3850d5perrin return (B_FALSE);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
8ef9dde03e938929ceec1291f40c6a4e644e6783marks if (ioctl(fd, VT_GETDISPINFO, vd) != 0) {
8ef9dde03e938929ceec1291f40c6a4e644e6783marks (void) close(fd);
8ef9dde03e938929ceec1291f40c6a4e644e6783marks return (B_FALSE);
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee }
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee (void) close(fd);
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee return (B_TRUE);
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee}
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee/*
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee * Xserver registers its pid into kernel to associate it with
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee * its vt upon startup for each graphical display. So here we can
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee * check if the pid is of the Xserver for the current active
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee * display when we receive a special VT_EV_X_EXIT request from
c5c6ffa0498b9c8555798756141b4a3061a138c1maybee * a process. If the request does not come from the current
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee * active Xserver, it is discarded.
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee */
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybeestatic boolean_t
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybeevt_check_disp_active(pid_t x_pid)
fa9e4066f08beec538e775443c5be79dd423fcabahrens{
fa9e4066f08beec538e775443c5be79dd423fcabahrens struct vt_dispinfo vd;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee if (vt_get_active_disp_info(&vd) &&
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee vd.v_pid == x_pid)
c5c6ffa0498b9c8555798756141b4a3061a138c1maybee return (B_TRUE);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (B_FALSE);
fa9e4066f08beec538e775443c5be79dd423fcabahrens}
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens/*
fa9e4066f08beec538e775443c5be79dd423fcabahrens * check if the pid is of the Xserver for the current active display,
fa9e4066f08beec538e775443c5be79dd423fcabahrens * return true when it is, and then also return other associated
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee * information with the Xserver.
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee */
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic boolean_t
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybeevt_get_disp_info(pid_t x_pid, int *logged_in, int *display_num)
fa9e4066f08beec538e775443c5be79dd423fcabahrens{
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee struct vt_dispinfo vd;
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee if (!vt_get_active_disp_info(&vd) ||
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee vd.v_pid != x_pid)
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee return (B_FALSE);
c5c6ffa0498b9c8555798756141b4a3061a138c1maybee
fa9e4066f08beec538e775443c5be79dd423fcabahrens *logged_in = vd.v_login;
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee *display_num = vd.v_dispnum;
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (B_TRUE);
fa9e4066f08beec538e775443c5be79dd423fcabahrens}
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybeestatic void
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybeevt_terminate_auth(void)
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee{
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee struct timespec sleeptime;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens sleeptime.tv_sec = 0;
fa9e4066f08beec538e775443c5be79dd423fcabahrens sleeptime.tv_nsec = 1000000; /* 1ms */
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) mutex_lock(&vt_mutex);
fa9e4066f08beec538e775443c5be79dd423fcabahrens while (vt_auth_doing) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens vt_ev_request(VT_EV_TERMINATE_AUTH, 0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (vt_auth_doing) {
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee (void) mutex_unlock(&vt_mutex);
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee (void) nanosleep(&sleeptime, NULL);
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee sleeptime.tv_nsec *= 2;
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee (void) mutex_lock(&vt_mutex);
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee }
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee }
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee (void) mutex_unlock(&vt_mutex);
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee}
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybeestatic void
8a2f1b9190d1dc288470a1fd2776d79ce82cb129ahrensvt_do_hotkeys(pid_t pid, uint32_t target_vt)
8a2f1b9190d1dc288470a1fd2776d79ce82cb129ahrens{
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee int logged_in;
c5c6ffa0498b9c8555798756141b4a3061a138c1maybee int display_num;
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (validate_target_vt(target_vt) != 0)
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee return;
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee /*
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee * Maybe last switch action is being taken and the lock is ongoing,
fa9e4066f08beec538e775443c5be79dd423fcabahrens * here we must reject the newly request.
fa9e4066f08beec538e775443c5be79dd423fcabahrens */
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee (void) mutex_lock(&vt_mutex);
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee if (vt_hotkeys_pending) {
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee (void) mutex_unlock(&vt_mutex);
5dc8af33db998034aea16c6b24b8d6c00fddc1a0maybee return;
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee }
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee
5dc8af33db998034aea16c6b24b8d6c00fddc1a0maybee /* cleared in vt_do_active and vt_do_auth */
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee vt_hotkeys_pending = B_TRUE;
5dc8af33db998034aea16c6b24b8d6c00fddc1a0maybee (void) mutex_unlock(&vt_mutex);
5dc8af33db998034aea16c6b24b8d6c00fddc1a0maybee
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee vt_terminate_auth();
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee /* check source session for this hotkeys request */
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee if (pid == 0) {
b19a79ec1a527828a60c4d325ccd8dcbeb2b2e8bperrin /* ok, it comes from kernel. */
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee if (vt_secure)
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee vt_check_source_audit();
c5c6ffa0498b9c8555798756141b4a3061a138c1maybee
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee /* then only need to check target session */
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee vt_check_target_session(target_vt);
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee return;
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee /*
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee * check if it comes from current active X graphical session,
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee * if not, ignore this request.
fa9e4066f08beec538e775443c5be79dd423fcabahrens */
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (!vt_get_disp_info(pid, &logged_in, &display_num)) {
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee (void) mutex_lock(&vt_mutex);
fa9e4066f08beec538e775443c5be79dd423fcabahrens vt_hotkeys_pending = B_FALSE;
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee (void) mutex_unlock(&vt_mutex);
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee return;
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (logged_in && vt_secure)
fa9e4066f08beec538e775443c5be79dd423fcabahrens vt_ev_request(VT_EV_LOCK, display_num);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee vt_check_target_session(target_vt);
fa9e4066f08beec538e775443c5be79dd423fcabahrens}
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens/*
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The main routine for the door server that deals with secure hotkeys
5730cc9a43c5f11a472d7536ed81facfd10f1e2emaybee */
fa9e4066f08beec538e775443c5be79dd423fcabahrens/* ARGSUSED */
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic void
fa9e4066f08beec538e775443c5be79dd423fcabahrensserver_for_door(void *cookie, char *args, size_t alen, door_desc_t *dp,
fa9e4066f08beec538e775443c5be79dd423fcabahrens uint_t n_desc)
fa9e4066f08beec538e775443c5be79dd423fcabahrens{
fa9e4066f08beec538e775443c5be79dd423fcabahrens ucred_t *uc = NULL;
fa9e4066f08beec538e775443c5be79dd423fcabahrens vt_cmd_arg_t *vtargp;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* LINTED E_BAD_PTR_CAST_ALIGN */
fa9e4066f08beec538e775443c5be79dd423fcabahrens vtargp = (vt_cmd_arg_t *)args;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (vtargp == NULL ||
eaca9bbd5f5d1e4e554da4c7108e8a03c8c33481eschrock alen != sizeof (vt_cmd_arg_t) ||
fa9e4066f08beec538e775443c5be79dd423fcabahrens door_ucred(&uc) != 0) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) door_return(NULL, 0, NULL, 0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return;
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens switch (vtargp->vt_ev) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens case VT_EV_X_EXIT:
fa9e4066f08beec538e775443c5be79dd423fcabahrens /*
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * Xserver will issue this event requesting to switch back
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * to previous active vt when it's exiting and the associated
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * vt is currently active.
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock */
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (vt_check_disp_active(ucred_getpid(uc)))
fa9e4066f08beec538e775443c5be79dd423fcabahrens vt_do_hotkeys(0, vtargp->vt_num);
fa9e4066f08beec538e775443c5be79dd423fcabahrens break;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens case VT_EV_HOTKEYS:
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (!vt_hotkeys) /* hotkeys are disabled? */
fa9e4066f08beec538e775443c5be79dd423fcabahrens break;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens vt_do_hotkeys(ucred_getpid(uc), vtargp->vt_num);
eaca9bbd5f5d1e4e554da4c7108e8a03c8c33481eschrock break;
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens default:
fa9e4066f08beec538e775443c5be79dd423fcabahrens break;
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens
893a6d32980d24be1349478f44169009d4801c25ahrens ucred_free(uc);
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) door_return(NULL, 0, NULL, 0);
893a6d32980d24be1349478f44169009d4801c25ahrens}
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic boolean_t
fa9e4066f08beec538e775443c5be79dd423fcabahrenssetup_door(void)
fa9e4066f08beec538e775443c5be79dd423fcabahrens{
fa9e4066f08beec538e775443c5be79dd423fcabahrens if ((vt_door = door_create(server_for_door, NULL,
fa9e4066f08beec538e775443c5be79dd423fcabahrens DOOR_UNREF | DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) < 0) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens syslog(LOG_ERR, "door_create failed: %s", strerror(errno));
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (B_FALSE);
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) fdetach(vt_door_path);
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (fattach(vt_door, vt_door_path) != 0) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens syslog(LOG_ERR, "fattach to %s failed: %s",
893a6d32980d24be1349478f44169009d4801c25ahrens vt_door_path, strerror(errno));
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) door_revoke(vt_door);
fa9e4066f08beec538e775443c5be79dd423fcabahrens (void) fdetach(vt_door_path);
fa9e4066f08beec538e775443c5be79dd423fcabahrens vt_door = -1;
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (B_FALSE);
fa9e4066f08beec538e775443c5be79dd423fcabahrens }
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (B_TRUE);
fa9e4066f08beec538e775443c5be79dd423fcabahrens}
fa9e4066f08beec538e775443c5be79dd423fcabahrens
fa9e4066f08beec538e775443c5be79dd423fcabahrens/*
fa9e4066f08beec538e775443c5be79dd423fcabahrens * check to see if vtdaemon is already running.
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The idea here is that we want to open the path to which we will
fa9e4066f08beec538e775443c5be79dd423fcabahrens * attach our door, lock it, and then make sure that no-one has beat us
fa9e4066f08beec538e775443c5be79dd423fcabahrens * to fattach(3c)ing onto it.
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * fattach(3c) is really a mount, so there are actually two possible
fa9e4066f08beec538e775443c5be79dd423fcabahrens * vnodes we could be dealing with. Our strategy is as follows:
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
fa9e4066f08beec538e775443c5be79dd423fcabahrens * - If the file we opened is a regular file (common case):
fa9e4066f08beec538e775443c5be79dd423fcabahrens * There is no fattach(3c)ed door, so we have a chance of becoming
fa9e4066f08beec538e775443c5be79dd423fcabahrens * the running vtdaemon. We attempt to lock the file: if it is
fa9e4066f08beec538e775443c5be79dd423fcabahrens * already locked, that means someone else raced us here, so we
fa9e4066f08beec538e775443c5be79dd423fcabahrens * lose and give up.
fa9e4066f08beec538e775443c5be79dd423fcabahrens *
55434c770c89aa1b84474f2559a106803511aba0ek * - If the file we opened is a namefs file:
55434c770c89aa1b84474f2559a106803511aba0ek * This means there is already an established door fattach(3c)'ed
55434c770c89aa1b84474f2559a106803511aba0ek * to the rendezvous path. We've lost the race, so we give up.
55434c770c89aa1b84474f2559a106803511aba0ek * Note that in this case we also try to grab the file lock, and
55434c770c89aa1b84474f2559a106803511aba0ek * will succeed in acquiring it since the vnode locked by the
55434c770c89aa1b84474f2559a106803511aba0ek * "winning" vtdaemon was a regular one, and the one we locked was
55434c770c89aa1b84474f2559a106803511aba0ek * the fattach(3c)'ed door node. At any rate, no harm is done.
55434c770c89aa1b84474f2559a106803511aba0ek */
55434c770c89aa1b84474f2559a106803511aba0ekstatic boolean_t
55434c770c89aa1b84474f2559a106803511aba0ekmake_daemon_exclusive(void)
55434c770c89aa1b84474f2559a106803511aba0ek{
55434c770c89aa1b84474f2559a106803511aba0ek int doorfd = -1;
55434c770c89aa1b84474f2559a106803511aba0ek boolean_t ret = B_FALSE;
55434c770c89aa1b84474f2559a106803511aba0ek struct stat st;
55434c770c89aa1b84474f2559a106803511aba0ek struct flock flock;
55434c770c89aa1b84474f2559a106803511aba0ek
55434c770c89aa1b84474f2559a106803511aba0ektop:
55434c770c89aa1b84474f2559a106803511aba0ek if ((doorfd = open(vt_door_path, O_CREAT|O_RDWR,
55434c770c89aa1b84474f2559a106803511aba0ek S_IREAD|S_IWRITE|S_IRGRP|S_IROTH)) < 0) {
55434c770c89aa1b84474f2559a106803511aba0ek syslog(LOG_ERR, "failed to open %s", vt_door_path);
55434c770c89aa1b84474f2559a106803511aba0ek goto out;
55434c770c89aa1b84474f2559a106803511aba0ek }
55434c770c89aa1b84474f2559a106803511aba0ek if (fstat(doorfd, &st) < 0) {
55434c770c89aa1b84474f2559a106803511aba0ek syslog(LOG_ERR, "failed to stat %s", vt_door_path);
55434c770c89aa1b84474f2559a106803511aba0ek goto out;
55434c770c89aa1b84474f2559a106803511aba0ek }
55434c770c89aa1b84474f2559a106803511aba0ek /*
55434c770c89aa1b84474f2559a106803511aba0ek * Lock the file to synchronize
55434c770c89aa1b84474f2559a106803511aba0ek */
55434c770c89aa1b84474f2559a106803511aba0ek flock.l_type = F_WRLCK;
55434c770c89aa1b84474f2559a106803511aba0ek flock.l_whence = SEEK_SET;
55434c770c89aa1b84474f2559a106803511aba0ek flock.l_start = (off_t)0;
55434c770c89aa1b84474f2559a106803511aba0ek flock.l_len = (off_t)0;
55434c770c89aa1b84474f2559a106803511aba0ek if (fcntl(doorfd, F_SETLK, &flock) < 0) {
55434c770c89aa1b84474f2559a106803511aba0ek /*
55434c770c89aa1b84474f2559a106803511aba0ek * Someone else raced us here and grabbed the lock file
55434c770c89aa1b84474f2559a106803511aba0ek * first. A warning here and exit.
55434c770c89aa1b84474f2559a106803511aba0ek */
55434c770c89aa1b84474f2559a106803511aba0ek syslog(LOG_ERR, "vtdaemon is already running!");
55434c770c89aa1b84474f2559a106803511aba0ek goto out;
55434c770c89aa1b84474f2559a106803511aba0ek }
55434c770c89aa1b84474f2559a106803511aba0ek
55434c770c89aa1b84474f2559a106803511aba0ek if (strcmp(st.st_fstype, "namefs") == 0) {
55434c770c89aa1b84474f2559a106803511aba0ek struct door_info info;
55434c770c89aa1b84474f2559a106803511aba0ek
55434c770c89aa1b84474f2559a106803511aba0ek /*
55434c770c89aa1b84474f2559a106803511aba0ek * There is already something fattach()'ed to this file.
55434c770c89aa1b84474f2559a106803511aba0ek * Lets see what the door is up to.
55434c770c89aa1b84474f2559a106803511aba0ek */
55434c770c89aa1b84474f2559a106803511aba0ek if (door_info(doorfd, &info) == 0 && info.di_target != -1) {
55434c770c89aa1b84474f2559a106803511aba0ek syslog(LOG_ERR, "vtdaemon is already running!");
55434c770c89aa1b84474f2559a106803511aba0ek goto out;
55434c770c89aa1b84474f2559a106803511aba0ek }
55434c770c89aa1b84474f2559a106803511aba0ek
55434c770c89aa1b84474f2559a106803511aba0ek (void) fdetach(vt_door_path);
55434c770c89aa1b84474f2559a106803511aba0ek (void) close(doorfd);
55434c770c89aa1b84474f2559a106803511aba0ek goto top;
55434c770c89aa1b84474f2559a106803511aba0ek }
55434c770c89aa1b84474f2559a106803511aba0ek
55434c770c89aa1b84474f2559a106803511aba0ek ret = setup_door();
55434c770c89aa1b84474f2559a106803511aba0ek
55434c770c89aa1b84474f2559a106803511aba0ekout:
55434c770c89aa1b84474f2559a106803511aba0ek (void) close(doorfd);
55434c770c89aa1b84474f2559a106803511aba0ek return (ret);
55434c770c89aa1b84474f2559a106803511aba0ek}
55434c770c89aa1b84474f2559a106803511aba0ek
55434c770c89aa1b84474f2559a106803511aba0ekstatic boolean_t
55434c770c89aa1b84474f2559a106803511aba0ekmkvtdir(void)
55434c770c89aa1b84474f2559a106803511aba0ek{
55434c770c89aa1b84474f2559a106803511aba0ek struct stat st;
55434c770c89aa1b84474f2559a106803511aba0ek /*
55434c770c89aa1b84474f2559a106803511aba0ek * We must create and lock everyone but root out of VT_TMPDIR
55434c770c89aa1b84474f2559a106803511aba0ek * since anyone can open any UNIX domain socket, regardless of
55434c770c89aa1b84474f2559a106803511aba0ek * its file system permissions.
55434c770c89aa1b84474f2559a106803511aba0ek */
55434c770c89aa1b84474f2559a106803511aba0ek if (mkdir(VT_TMPDIR, S_IRWXU|S_IROTH|S_IXOTH|S_IRGRP|S_IXGRP) < 0 &&
55434c770c89aa1b84474f2559a106803511aba0ek errno != EEXIST) {
syslog(LOG_ERR, "could not mkdir '%s'", VT_TMPDIR);
return (B_FALSE);
}
/* paranoia */
if ((stat(VT_TMPDIR, &st) < 0) || !S_ISDIR(st.st_mode)) {
syslog(LOG_ERR, "'%s' is not a directory", VT_TMPDIR);
return (B_FALSE);
}
(void) chmod(VT_TMPDIR, S_IRWXU|S_IROTH|S_IXOTH|S_IRGRP|S_IXGRP);
return (B_TRUE);
}
int
main(int argc, char *argv[])
{
int i;
int opt;
priv_set_t *privset;
int active;
openlog("vtdaemon", LOG_PID | LOG_CONS, 0);
/*
* Check that we have all privileges. It would be nice to pare
* this down, but this is at least a first cut.
*/
if ((privset = priv_allocset()) == NULL) {
syslog(LOG_ERR, "priv_allocset failed");
return (1);
}
if (getppriv(PRIV_EFFECTIVE, privset) != 0) {
syslog(LOG_ERR, "getppriv failed", "getppriv");
priv_freeset(privset);
return (1);
}
if (priv_isfullset(privset) == B_FALSE) {
syslog(LOG_ERR, "You lack sufficient privilege "
"to run this command (all privs required)");
priv_freeset(privset);
return (1);
}
priv_freeset(privset);
while ((opt = getopt(argc, argv, "ksrc:")) != EOF) {
switch (opt) {
case 'k':
vt_hotkeys = B_FALSE;
break;
case 's':
vt_secure = B_FALSE;
break;
case 'c':
vtnodecount = atoi(optarg);
break;
default:
break;
}
}
(void) vt_setup_signal(SIGINT, 1);
if (!mkvtdir())
return (1);
if (!eventstream_init())
return (1);
(void) snprintf(vt_door_path, sizeof (vt_door_path),
VT_TMPDIR "/vtdaemon_door");
if (!make_daemon_exclusive())
return (1);
/* only the main thread accepts SIGINT */
(void) vt_setup_signal(SIGINT, 0);
(void) sigset(SIGPIPE, SIG_IGN);
(void) signal(SIGQUIT, SIG_IGN);
(void) signal(SIGINT, catch);
for (i = 0; i < 3; i++)
(void) close(i);
(void) setsid();
if ((daemonfd = open(VT_DAEMON_CONSOLE_FILE, O_RDWR)) < 0) {
return (1);
}
if (daemonfd != 0)
(void) dup2(daemonfd, STDIN_FILENO);
if (daemonfd != 1)
(void) dup2(daemonfd, STDOUT_FILENO);
if (vtnodecount >= 2)
(void) ioctl(daemonfd, VT_CONFIG, vtnodecount);
if ((vt_ah_array = calloc(vtnodecount - 1,
sizeof (adt_session_data_t *))) == NULL)
return (1);
(void) ioctl(daemonfd, VT_GETACTIVE, &active);
if (active == 1) {
/*
* This is for someone who restarts vtdaemon while vtdaemon
* is doing authentication on /dev/vt/1.
* A better way is to continue the authentication, but there
* are chances that the status of the target VT has changed.
* So we just clear the screen here.
*/
(void) write(daemonfd, VT_CLEAR_SCREEN_STR,
strlen(VT_CLEAR_SCREEN_STR));
}
vt_serve_events();
/*NOTREACHED*/
}
static int
vt_audit_start(adt_session_data_t **ah, pid_t pid)
{
ucred_t *uc;
if (adt_start_session(ah, NULL, 0))
return (-1);
if ((uc = ucred_get(pid)) == NULL) {
(void) adt_end_session(*ah);
return (-1);
}
if (adt_set_from_ucred(*ah, uc, ADT_NEW)) {
ucred_free(uc);
(void) adt_end_session(*ah);
return (-1);
}
ucred_free(uc);
return (0);
}
/*
* Write audit event
*/
static void
vt_audit_event(adt_session_data_t *ah, au_event_t event_id, int status)
{
adt_event_data_t *event;
if ((event = adt_alloc_event(ah, event_id)) == NULL) {
return;
}
(void) adt_put_event(event,
status == PAM_SUCCESS ? ADT_SUCCESS : ADT_FAILURE,
status == PAM_SUCCESS ? ADT_SUCCESS : ADT_FAIL_PAM + status);
adt_free_event(event);
}
static void
vt_check_source_audit(void)
{
int fd;
int source_vt;
int real_vt;
struct vt_stat state;
pid_t pid;
adt_session_data_t *ah;
if ((fd = open(VT_DAEMON_CONSOLE_FILE, O_WRONLY)) < 0)
return;
if (ioctl(fd, VT_GETSTATE, &state) != 0 ||
ioctl(fd, VT_GETACTIVE, &real_vt) != 0) {
(void) close(fd);
return;
}
source_vt = state.v_active; /* 1..n */
(void) close(fd);
/* check if it's already locked */
if (real_vt == 1) /* vtdaemon is taking over the screen */
return;
vt_read_utx(source_vt, &pid, NULL);
if (pid == (pid_t)-1)
return;
if (vt_audit_start(&ah, pid) != 0) {
syslog(LOG_ERR, "audit start failed ");
return;
}
/*
* In case the previous session terminated abnormally.
*/
if (vt_ah_array[source_vt - 1] != NULL)
(void) adt_end_session(vt_ah_array[source_vt - 1]);
vt_ah_array[source_vt - 1] = ah;
vt_audit_event(ah, ADT_screenlock, PAM_SUCCESS);
}