Merge commit '00f1a4f432b3d8aad1aa270e91c44c57f03ef407'
[unleashed.git] / usr / src / cmd / vt / vtdaemon.c
bloba64b5d00e71760be609ff8092276ed909c740e72
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
27 * vtdaemon is responsible for the session secure switch via hotkeys.
29 * vtdaemon itself, like ttymon(8), is also running on a virtual
30 * console device (/dev/vt/1), and provides a text console session
31 * for password input and authentication. The /dev/vt/1 special text
32 * console is reserved and end users cannot switch to it via hotkeys.
35 * The hotkey event request can come from either kernel or Xserver,
36 * and a door server is setup to handle the request:
38 * 1) All text console hotkeys (e.g. "Alt + F#") are intercepted by
39 * the kernel console driver which sends a door upcall to the
40 * vtdaemon via door_upcall (target_vt).
42 * 2) All Xserver hotkeys ("Alt + Ctrl + F#") are intercepted by
43 * Xserver which sends a door call to the vtdaemon via
44 * door_call (target_vt).
47 * server_for_door receives and handles any door server requests:
49 * Firstly, check source session:
51 * . If it's from kernel for a text console source session,
52 * then directly go to check the target session.
54 * . If it's from Xserver for a graphical source session and the vt
55 * associated with the Xserver is currently active:
56 * check if a user has logged in, if true, issue an internal
57 * VT_EV_LOCK event to the main thread to request lock for
58 * the graphical source session; else, directly go to check
59 * the target session.
61 * . otherwise, discard this request.
64 * Secondly, check the target session
66 * . if the target session is a text one that no one has logged in
67 * or a graphical one, issue an internal VT_EV_ACTIVATE event to
68 * the main thread to request the actual VT switch.
70 * . otherwise, the target session is a text one that someone has
71 * logged in, issue an internal VT_EV_AUTH event to the main
72 * thread to request authentication for the target session.
75 * The main thread of vtdaemon is a loop waiting for internal events
76 * which come from door call threads:
78 * 1) VT_EV_AUTH to authenticate for target session:
80 * firstly switch to the vtdaemon special text console;
81 * then prompt for password (target_owner on target_vt),
82 * e.g. "User Bob's password on vt/#: ".
84 * if the password is correct (authentication succeeds),
85 * then actually issue the VT switch; otherwise, ignore
86 * the request.
88 * 2) VT_EV_LOCK to lock the graphical source session:
90 * activate screenlock for this graphical session.
91 * vtdaemon just invokes existing front-end command line
92 * tools (e.g. xscreensaver-command -lock for JDS) to
93 * lock the display.
95 * 3) VT_EV_ACTIVATE to directly switch to the target session
98 * There is a system/vtdaemon:default SMF service for vtdaemon.
100 * There's a "hotkeys" property (BOOLEAN) in the
101 * system/vtdaemon:default SMF service, which allows authorized
102 * users to dynamically enable or disable VT switch via hotkeys.
103 * Its default value is TRUE (enabled).
105 * There's a "secure" property (BOOLEAN) in the
106 * system/vtdaemon:default SMF service, which allows authorized
107 * users to dynamically enable or disable hotkeys are secure.
108 * If disabled, the user can freely switch to any session without
109 * authentication. Its default value is TRUE (enabled).
112 * By default, there's only 16 virtual console device nodes (from
113 * /dev/vt/0 to /dev/vt/15). There's a property "nodecount"
114 * (default value is 16) in the system/vtdaemon:default SMF
115 * service, so authorized users can configure it to have more
116 * or less virtual console device nodes.
118 * Xserver needs to switch back to previous active vt via VT_EV_X_EXIT
119 * door event request when it's exiting, so vtdaemon always needs to
120 * be there even if the hotkeys switch is disabled, otherwise the screen
121 * will be just blank when Xserver exits.
124 #include <sys/param.h>
125 #include <sys/mman.h>
126 #include <sys/types.h>
127 #include <sys/wait.h>
128 #include <sys/stat.h>
129 #include <sys/sysmacros.h>
130 #include <syslog.h>
131 #include <deflt.h>
133 #include <bsm/adt.h>
134 #include <bsm/adt_event.h>
136 #include <alloca.h>
137 #include <assert.h>
138 #include <errno.h>
139 #include <door.h>
140 #include <fcntl.h>
141 #include <signal.h>
142 #include <stdarg.h>
143 #include <stdio.h>
144 #include <stdlib.h>
145 #include <string.h>
146 #include <strings.h>
147 #include <synch.h>
148 #include <thread.h>
149 #include <unistd.h>
150 #include <wait.h>
151 #include <limits.h>
152 #include <zone.h>
153 #include <priv.h>
154 #include <pwd.h>
155 #include <utmpx.h>
156 #include <procfs.h>
157 #include <poll.h>
158 #include <termio.h>
159 #include <security/pam_appl.h>
160 #include <time.h>
161 #include <sys/console.h>
162 #include <assert.h>
163 #include <syslog.h>
165 #include <sys/vt.h>
166 #include <sys/vtdaemon.h>
169 * The door file /var/run/vt/vtdaemon_door
171 #define VT_TMPDIR "/var/run/vt"
173 #define VT_DAEMON_ARG 0
174 #define VT_DAEMON_CONSOLE_FILE "/dev/vt/1"
176 #define VT_IS_SYSTEM_CONSOLE(vtno) ((vtno) == 1)
178 /* Defaults for updating expired passwords */
179 #define DEF_ATTEMPTS 3
181 int daemonfd;
183 static boolean_t vt_hotkeys = B_TRUE; /* '-k' option to disable */
184 static boolean_t vt_secure = B_TRUE; /* '-s' option to disable */
186 static char vt_door_path[MAXPATHLEN];
187 static int vt_door = -1;
189 /* protecting vt_hotkeys_pending and vt_auth_doing */
190 static mutex_t vt_mutex = DEFAULTMUTEX;
192 static boolean_t vt_hotkeys_pending = B_FALSE;
193 static boolean_t vt_auth_doing = B_FALSE;
195 static adt_session_data_t **vt_ah_array = NULL;
196 static int vtnodecount = 0;
198 static int vt_audit_start(adt_session_data_t **, pid_t);
199 static void vt_audit_event(adt_session_data_t *, au_event_t, int);
200 static void vt_check_source_audit(void);
202 static int
203 vt_setup_signal(int signo, int mask)
205 sigset_t set;
207 (void) sigemptyset(&set);
208 (void) sigaddset(&set, signo);
210 if (mask)
211 return (sigprocmask(SIG_BLOCK, &set, NULL));
212 else
213 return (sigprocmask(SIG_UNBLOCK, &set, NULL));
216 static void
217 do_activate_screenlock(int display_num)
219 char dpy[16];
221 (void) snprintf(dpy, sizeof (dpy), "%d", display_num);
222 (void) execl("/usr/lib/vtxlock", "vtxlock", dpy, NULL);
225 static void
226 vt_activate_screenlock(int display)
228 pid_t pid;
230 if ((pid = fork()) == -1)
231 return;
233 if (pid == 0) { /* child */
234 do_activate_screenlock(display);
235 exit(0);
238 /* parent */
239 while (waitpid(pid, (int *)0, 0) != pid)
240 continue;
244 * Find the login process and user logged in on the target vt.
246 static void
247 vt_read_utx(int target_vt, pid_t *pid, char name[])
249 struct utmpx *u;
250 char ttyntail[sizeof (u->ut_line)];
252 *pid = (pid_t)-1;
254 if (VT_IS_SYSTEM_CONSOLE(target_vt)) /* system console */
255 (void) snprintf(ttyntail, sizeof (ttyntail),
256 "%s", "console");
257 else
258 (void) snprintf(ttyntail, sizeof (ttyntail),
259 "%s%d", "vt/", target_vt);
261 setutxent();
262 while ((u = getutxent()) != NULL)
263 /* see if this is the entry we want */
264 if ((u->ut_type == USER_PROCESS) &&
265 (!nonuserx(*u)) &&
266 (u->ut_host[0] == '\0') &&
267 (strncmp(u->ut_line, ttyntail, sizeof (u->ut_line)) == 0)) {
269 *pid = u->ut_pid;
270 if (name != NULL) {
271 (void) strncpy(name, u->ut_user,
272 sizeof (u->ut_user));
273 name[sizeof (u->ut_user)] = '\0';
275 break;
278 endutxent();
281 static boolean_t
282 vt_is_tipline(void)
284 static int is_tipline = 0;
285 int fd;
286 static char termbuf[MAX_TERM_TYPE_LEN];
287 static struct cons_getterm cons_term = { sizeof (termbuf), termbuf};
289 if (is_tipline != 0)
290 return (is_tipline == 1);
292 if ((fd = open("/dev/console", O_RDONLY)) < 0)
293 return (B_FALSE);
295 if (ioctl(fd, CONS_GETTERM, &cons_term) != 0 &&
296 errno == ENODEV) {
297 is_tipline = 1;
298 } else {
299 is_tipline = -1;
302 (void) close(fd);
303 return (is_tipline == 1);
306 static int
307 validate_target_vt(int target_vt)
309 int fd;
310 struct vt_stat state;
312 if (target_vt < 1)
313 return (-1);
315 if ((fd = open(VT_DAEMON_CONSOLE_FILE, O_WRONLY)) < 0)
316 return (-1);
318 if (ioctl(fd, VT_GETSTATE, &state) != 0) {
319 (void) close(fd);
320 return (-1);
323 (void) close(fd);
325 if (state.v_active == target_vt) {
326 return (1); /* it's current active vt */
329 if (target_vt == 1) {
331 * In tipline case, the system console is always
332 * available, so ignore this request.
334 if (vt_is_tipline())
335 return (-1);
337 target_vt = 0;
341 * The hotkey request and corresponding target_vt number can come
342 * from either kernel or Xserver (or other user applications).
343 * In kernel we've validated the hotkey request, but Xserver (or
344 * other user applications) cannot do it, so here we still try
345 * to validate it.
347 * VT_GETSTATE is only valid for first 16 VTs for historical reasons.
348 * Fortunately, in practice, Xserver can only send the hotkey
349 * request of target_vt number from 1 to 12 (Ctrl + Alt + F1 to F2).
351 if (target_vt < 8 * sizeof (state.v_state)) {
352 if ((state.v_state & (1 << target_vt)) != 0) {
353 return (0);
354 } else {
355 return (-1);
359 return (0);
362 static void
363 vt_do_activate(int target_vt)
365 (void) ioctl(daemonfd, VT_ACTIVATE, target_vt);
366 (void) mutex_lock(&vt_mutex);
367 vt_hotkeys_pending = B_FALSE;
368 (void) mutex_unlock(&vt_mutex);
371 /* events written to fd 0 and read from fd 1 */
372 #define VT_EV_AUTH 1
373 #define VT_EV_LOCK 2
374 #define VT_EV_ACTIVATE 3
376 /* events written to fd 1 and read from fd 0 */
377 #define VT_EV_TERMINATE_AUTH 4
379 typedef struct vt_evt {
380 int ve_cmd;
381 int ve_info; /* vtno or display num */
382 } vt_evt_t;
384 static int eventstream[2];
386 boolean_t
387 eventstream_init(void)
389 if (pipe(eventstream) == -1)
390 return (B_FALSE);
391 return (B_TRUE);
394 void
395 eventstream_write(int channel, vt_evt_t *pevt)
397 (void) write(eventstream[channel], pevt, sizeof (vt_evt_t));
400 static boolean_t
401 eventstream_read(int channel, vt_evt_t *pevt)
403 ssize_t rval;
405 rval = read(eventstream[channel], pevt, sizeof (vt_evt_t));
406 return (rval > 0);
409 static void
410 vt_ev_request(int cmd, int info)
412 int channel;
413 vt_evt_t ve;
415 ve.ve_cmd = cmd;
416 ve.ve_info = info;
418 channel = (cmd == VT_EV_TERMINATE_AUTH) ? 1 : 0;
419 eventstream_write(channel, &ve);
422 static void
423 vt_clear_events(void)
425 int rval = 0;
426 struct stat buf;
427 vt_evt_t evt;
429 while (rval == 0) {
430 rval = fstat(eventstream[0], &buf);
431 if (rval != -1 && buf.st_size > 0)
432 (void) eventstream_read(0, &evt);
433 else
434 break;
438 static int vt_conv(int, struct pam_message **,
439 struct pam_response **, void *);
441 /*ARGSUSED*/
442 static void
443 catch(int x)
445 (void) signal(SIGINT, catch);
449 * The SIGINT (ctl_c) will restart the authentication, and re-prompt
450 * the end user to input the password.
452 static int
453 vt_poll()
455 struct pollfd pollfds[2];
456 vt_evt_t ve;
457 int ret;
459 pollfds[0].fd = eventstream[0];
460 pollfds[1].fd = daemonfd;
461 pollfds[0].events = pollfds[1].events =
462 POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI;
464 for (;;) {
465 pollfds[0].revents = pollfds[1].revents = 0;
467 ret = poll(pollfds,
468 sizeof (pollfds) / sizeof (struct pollfd), -1);
469 if (ret == -1 && errno != EINTR) {
470 continue;
473 if (ret == -1 && errno == EINTR)
474 return (-1);
476 if (pollfds[0].revents) {
477 (void) eventstream_read(0, &ve);
478 return (0);
481 if (pollfds[1].revents)
482 return (1);
484 return (0);
489 static char
490 vt_getchar(int fd)
492 char c;
493 int cnt;
495 cnt = read(fd, &c, 1);
496 if (cnt > 0) {
497 return (c);
500 return (EOF);
503 static char *
504 vt_getinput(int noecho)
506 int c;
507 int i = 0;
508 struct termio tty;
509 tcflag_t tty_flags;
510 char input[PAM_MAX_RESP_SIZE];
512 if (noecho) {
513 (void) ioctl(daemonfd, TCGETA, &tty);
514 tty_flags = tty.c_lflag;
515 tty.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
516 (void) ioctl(daemonfd, TCSETAF, &tty);
519 while ((vt_poll()) == 1) {
520 if ((c = vt_getchar(daemonfd)) != '\n' && c != '\r' &&
521 c != EOF && (i < PAM_MAX_RESP_SIZE - 1))
522 input[i++] = (char)c;
523 else
524 break;
527 input[i] = '\0';
529 if (noecho) {
530 tty.c_lflag = tty_flags;
531 (void) ioctl(daemonfd, TCSETAW, &tty);
532 (void) fputc('\n', stdout);
535 return (strdup(input));
539 * vt_conv: vtdaemon PAM conversation function.
540 * SIGINT/EINTR is handled in vt_getinput()/vt_poll().
543 /*ARGSUSED*/
544 static int
545 vt_conv(int num_msg, struct pam_message **msg,
546 struct pam_response **response, void *appdata_ptr)
548 struct pam_message *m;
549 struct pam_response *r;
550 int i, k;
552 if (num_msg >= PAM_MAX_NUM_MSG) {
553 syslog(LOG_ERR, "too many messages %d >= %d",
554 num_msg, PAM_MAX_NUM_MSG);
555 *response = NULL;
556 return (PAM_CONV_ERR);
559 *response = calloc(num_msg, sizeof (struct pam_response));
560 if (*response == NULL)
561 return (PAM_BUF_ERR);
563 m = *msg;
564 r = *response;
565 for (i = 0; i < num_msg; i++) {
566 int echo_off = 0;
568 /* Bad message */
569 if (m->msg == NULL) {
570 syslog(LOG_ERR, "message[%d]: %d/NULL\n",
571 i, m->msg_style);
572 goto err;
576 * Fix up final newline:
577 * remove from prompts, add back for messages.
579 if (m->msg[strlen(m->msg)] == '\n')
580 m->msg[strlen(m->msg)] = '\0';
582 r->resp = NULL;
583 r->resp_retcode = 0;
585 switch (m->msg_style) {
587 case PAM_PROMPT_ECHO_OFF:
588 echo_off = 1;
589 /* FALLTHROUGH */
591 case PAM_PROMPT_ECHO_ON:
592 (void) fputs(m->msg, stdout);
594 r->resp = vt_getinput(echo_off);
595 break;
597 case PAM_ERROR_MSG:
598 /* the user may want to see this */
599 (void) fputs(m->msg, stdout);
600 (void) fputs("\n", stdout);
601 break;
603 case PAM_TEXT_INFO:
604 (void) fputs(m->msg, stdout);
605 (void) fputs("\n", stdout);
606 break;
608 default:
609 syslog(LOG_ERR, "message[%d]: unknown type"
610 "%d/val=\"%s\"", i, m->msg_style, m->msg);
612 /* error, service module won't clean up */
613 goto err;
616 /* Next message/response */
617 m++;
618 r++;
621 return (PAM_SUCCESS);
623 err:
625 * Service modules don't clean up responses if an error is returned.
626 * Free responses here.
628 r = *response;
629 for (k = 0; k < i; k++, r++) {
630 if (r->resp) {
631 /* Clear before freeing -- maybe a password */
632 bzero(r->resp, strlen(r->resp));
633 free(r->resp);
634 r->resp = NULL;
638 free(*response);
639 *response = NULL;
640 return (PAM_CONV_ERR);
643 #define DEF_FILE "/etc/default/login"
645 /* Get PASSREQ from default file */
646 static boolean_t
647 vt_default(void)
649 int flags;
650 char *ptr;
651 boolean_t retval = B_FALSE;
653 if ((defopen(DEF_FILE)) == 0) {
654 /* ignore case */
655 flags = defcntl(DC_GETFLAGS, 0);
656 TURNOFF(flags, DC_CASE);
657 (void) defcntl(DC_SETFLAGS, flags);
659 if ((ptr = defread("PASSREQ=")) != NULL &&
660 strcasecmp("YES", ptr) == 0)
661 retval = B_TRUE;
663 (void) defopen(NULL);
666 return (retval);
670 * VT_CLEAR_SCREEN_STR is the console terminal escape sequence used to
671 * clear the current screen. The vt special console (/dev/vt/1) is
672 * just reserved for vtdaemon, and the TERM/termcap of it is always
673 * the local sun-color, which is always supported by our kernel terminal
674 * emulator.
676 #define VT_CLEAR_SCREEN_STR "\033[2J\033[1;1H"
678 static void
679 vt_do_auth(int target_vt)
681 char user_name[sizeof (((struct utmpx *)0)->ut_line) + 1] = {'\0'};
682 pam_handle_t *vt_pamh;
683 int err;
684 int pam_flag = 0;
685 int chpasswd_tries;
686 struct pam_conv pam_conv = {vt_conv, NULL};
687 pid_t pid;
688 adt_session_data_t *ah;
690 vt_read_utx(target_vt, &pid, user_name);
692 if (pid == (pid_t)-1 || user_name[0] == '\0')
693 return;
695 if ((err = pam_start("vtdaemon", user_name, &pam_conv,
696 &vt_pamh)) != PAM_SUCCESS)
697 return;
700 * firstly switch to the vtdaemon special console
701 * and clear the current screen
703 (void) ioctl(daemonfd, VT_ACTIVATE, VT_DAEMON_ARG);
704 (void) write(daemonfd, VT_CLEAR_SCREEN_STR,
705 strlen(VT_CLEAR_SCREEN_STR));
706 (void) ioctl(daemonfd, VT_SET_TARGET, target_vt);
708 (void) mutex_lock(&vt_mutex);
709 vt_auth_doing = B_TRUE;
710 vt_hotkeys_pending = B_FALSE;
711 (void) mutex_unlock(&vt_mutex);
714 * Fetch audit handle.
716 ah = vt_ah_array[target_vt - 1];
718 if (vt_default())
719 pam_flag = PAM_DISALLOW_NULL_AUTHTOK;
721 do {
722 if (VT_IS_SYSTEM_CONSOLE(target_vt))
723 (void) fprintf(stdout,
724 "\nUnlock user %s on the system console\n",
725 user_name);
726 else
727 (void) fprintf(stdout,
728 "\nUnlock user %s on vt/%d\n", user_name,
729 target_vt);
731 err = pam_authenticate(vt_pamh, pam_flag);
733 (void) mutex_lock(&vt_mutex);
734 if (vt_hotkeys_pending) {
735 (void) mutex_unlock(&vt_mutex);
736 break;
738 (void) mutex_unlock(&vt_mutex);
740 if (err == PAM_SUCCESS) {
741 err = pam_acct_mgmt(vt_pamh, pam_flag);
743 (void) mutex_lock(&vt_mutex);
744 if (vt_hotkeys_pending) {
745 (void) mutex_unlock(&vt_mutex);
746 break;
748 (void) mutex_unlock(&vt_mutex);
750 if (err == PAM_NEW_AUTHTOK_REQD) {
751 chpasswd_tries = 0;
753 do {
754 err = pam_chauthtok(vt_pamh,
755 PAM_CHANGE_EXPIRED_AUTHTOK);
756 chpasswd_tries++;
758 (void) mutex_lock(&vt_mutex);
759 if (vt_hotkeys_pending) {
760 (void) mutex_unlock(&vt_mutex);
761 break;
763 (void) mutex_unlock(&vt_mutex);
765 } while ((err == PAM_AUTHTOK_ERR ||
766 err == PAM_TRY_AGAIN) &&
767 chpasswd_tries < DEF_ATTEMPTS);
769 (void) mutex_lock(&vt_mutex);
770 if (vt_hotkeys_pending) {
771 (void) mutex_unlock(&vt_mutex);
772 break;
774 (void) mutex_unlock(&vt_mutex);
776 vt_audit_event(ah, ADT_passwd, err);
781 * Only audit failed unlock here, successful unlock
782 * will be audited after switching to target vt.
784 if (err != PAM_SUCCESS) {
785 (void) fprintf(stdout, "%s",
786 pam_strerror(vt_pamh, err));
788 vt_audit_event(ah, ADT_screenunlock, err);
791 (void) mutex_lock(&vt_mutex);
792 if (vt_hotkeys_pending) {
793 (void) mutex_unlock(&vt_mutex);
794 break;
796 (void) mutex_unlock(&vt_mutex);
798 } while (err != PAM_SUCCESS);
800 (void) mutex_lock(&vt_mutex);
801 if (!vt_hotkeys_pending) {
803 * Should be PAM_SUCCESS to reach here.
805 (void) ioctl(daemonfd, VT_ACTIVATE, target_vt);
807 vt_audit_event(ah, ADT_screenunlock, err);
810 * Free audit handle.
812 (void) adt_end_session(ah);
813 vt_ah_array[target_vt - 1] = NULL;
815 (void) mutex_unlock(&vt_mutex);
817 (void) pam_end(vt_pamh, err);
819 (void) mutex_lock(&vt_mutex);
820 vt_auth_doing = B_FALSE;
821 vt_clear_events();
822 (void) mutex_unlock(&vt_mutex);
825 /* main thread (lock and auth) */
826 static void __NORETURN
827 vt_serve_events(void)
829 struct pollfd pollfds[1];
830 int ret;
831 vt_evt_t ve;
833 pollfds[0].fd = eventstream[1];
834 pollfds[0].events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI;
836 for (;;) {
837 pollfds[0].revents = 0;
838 ret = poll(pollfds,
839 sizeof (pollfds) / sizeof (struct pollfd), -1);
840 if (ret == -1 && errno == EINTR) {
841 continue;
844 if (pollfds[0].revents && eventstream_read(1, &ve)) {
845 /* new request */
846 switch (ve.ve_cmd) {
847 case VT_EV_AUTH:
848 vt_do_auth(ve.ve_info);
849 break;
851 case VT_EV_LOCK:
852 vt_activate_screenlock(ve.ve_info);
853 break;
855 case VT_EV_ACTIVATE:
856 /* directly activate target vt */
857 vt_do_activate(ve.ve_info);
858 break;
864 static void
865 vt_check_target_session(uint32_t target_vt)
867 pid_t pid = (pid_t)-1;
869 if (!vt_secure) {
870 vt_ev_request(VT_EV_ACTIVATE, target_vt);
871 return;
874 /* check the target session */
875 vt_read_utx(target_vt, &pid, NULL);
876 if (pid == (pid_t)-1) {
877 vt_ev_request(VT_EV_ACTIVATE, target_vt);
878 return;
881 vt_ev_request(VT_EV_AUTH, target_vt);
884 static boolean_t
885 vt_get_active_disp_info(struct vt_dispinfo *vd)
887 int fd;
888 struct vt_stat state;
889 char vtname[16];
891 if ((fd = open(VT_DAEMON_CONSOLE_FILE, O_RDONLY)) < 0)
892 return (B_FALSE);
894 if (ioctl(fd, VT_GETSTATE, &state) != 0) {
895 (void) close(fd);
896 return (B_FALSE);
898 (void) close(fd);
900 (void) snprintf(vtname, sizeof (vtname), "/dev/vt/%d", state.v_active);
901 if ((fd = open(vtname, O_RDONLY)) < 0)
902 return (B_FALSE);
904 if (ioctl(fd, VT_GETDISPINFO, vd) != 0) {
905 (void) close(fd);
906 return (B_FALSE);
909 (void) close(fd);
910 return (B_TRUE);
914 * Xserver registers its pid into kernel to associate it with
915 * its vt upon startup for each graphical display. So here we can
916 * check if the pid is of the Xserver for the current active
917 * display when we receive a special VT_EV_X_EXIT request from
918 * a process. If the request does not come from the current
919 * active Xserver, it is discarded.
921 static boolean_t
922 vt_check_disp_active(pid_t x_pid)
924 struct vt_dispinfo vd;
926 if (vt_get_active_disp_info(&vd) &&
927 vd.v_pid == x_pid)
928 return (B_TRUE);
930 return (B_FALSE);
934 * check if the pid is of the Xserver for the current active display,
935 * return true when it is, and then also return other associated
936 * information with the Xserver.
938 static boolean_t
939 vt_get_disp_info(pid_t x_pid, int *logged_in, int *display_num)
941 struct vt_dispinfo vd;
943 if (!vt_get_active_disp_info(&vd) ||
944 vd.v_pid != x_pid)
945 return (B_FALSE);
947 *logged_in = vd.v_login;
948 *display_num = vd.v_dispnum;
949 return (B_TRUE);
952 static void
953 vt_terminate_auth(void)
955 struct timespec sleeptime;
957 sleeptime.tv_sec = 0;
958 sleeptime.tv_nsec = 1000000; /* 1ms */
960 (void) mutex_lock(&vt_mutex);
961 while (vt_auth_doing) {
962 vt_ev_request(VT_EV_TERMINATE_AUTH, 0);
964 if (vt_auth_doing) {
965 (void) mutex_unlock(&vt_mutex);
966 (void) nanosleep(&sleeptime, NULL);
967 sleeptime.tv_nsec *= 2;
968 (void) mutex_lock(&vt_mutex);
971 (void) mutex_unlock(&vt_mutex);
974 static void
975 vt_do_hotkeys(pid_t pid, uint32_t target_vt)
977 int logged_in;
978 int display_num;
980 if (validate_target_vt(target_vt) != 0)
981 return;
984 * Maybe last switch action is being taken and the lock is ongoing,
985 * here we must reject the newly request.
987 (void) mutex_lock(&vt_mutex);
988 if (vt_hotkeys_pending) {
989 (void) mutex_unlock(&vt_mutex);
990 return;
993 /* cleared in vt_do_active and vt_do_auth */
994 vt_hotkeys_pending = B_TRUE;
995 (void) mutex_unlock(&vt_mutex);
997 vt_terminate_auth();
999 /* check source session for this hotkeys request */
1000 if (pid == 0) {
1001 /* ok, it comes from kernel. */
1002 if (vt_secure)
1003 vt_check_source_audit();
1005 /* then only need to check target session */
1006 vt_check_target_session(target_vt);
1007 return;
1011 * check if it comes from current active X graphical session,
1012 * if not, ignore this request.
1014 if (!vt_get_disp_info(pid, &logged_in, &display_num)) {
1015 (void) mutex_lock(&vt_mutex);
1016 vt_hotkeys_pending = B_FALSE;
1017 (void) mutex_unlock(&vt_mutex);
1018 return;
1021 if (logged_in && vt_secure)
1022 vt_ev_request(VT_EV_LOCK, display_num);
1024 vt_check_target_session(target_vt);
1028 * The main routine for the door server that deals with secure hotkeys
1030 /* ARGSUSED */
1031 static void
1032 server_for_door(void *cookie, char *args, size_t alen, door_desc_t *dp,
1033 uint_t n_desc)
1035 ucred_t *uc = NULL;
1036 vt_cmd_arg_t *vtargp;
1038 /* LINTED E_BAD_PTR_CAST_ALIGN */
1039 vtargp = (vt_cmd_arg_t *)args;
1041 if (vtargp == NULL ||
1042 alen != sizeof (vt_cmd_arg_t) ||
1043 door_ucred(&uc) != 0) {
1044 (void) door_return(NULL, 0, NULL, 0);
1045 return;
1048 switch (vtargp->vt_ev) {
1049 case VT_EV_X_EXIT:
1051 * Xserver will issue this event requesting to switch back
1052 * to previous active vt when it's exiting and the associated
1053 * vt is currently active.
1055 if (vt_check_disp_active(ucred_getpid(uc)))
1056 vt_do_hotkeys(0, vtargp->vt_num);
1057 break;
1059 case VT_EV_HOTKEYS:
1060 if (!vt_hotkeys) /* hotkeys are disabled? */
1061 break;
1063 vt_do_hotkeys(ucred_getpid(uc), vtargp->vt_num);
1064 break;
1066 default:
1067 break;
1070 ucred_free(uc);
1071 (void) door_return(NULL, 0, NULL, 0);
1074 static boolean_t
1075 setup_door(void)
1077 if ((vt_door = door_create(server_for_door, NULL,
1078 DOOR_UNREF | DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) < 0) {
1079 syslog(LOG_ERR, "door_create failed: %s", strerror(errno));
1080 return (B_FALSE);
1083 (void) fdetach(vt_door_path);
1085 if (fattach(vt_door, vt_door_path) != 0) {
1086 syslog(LOG_ERR, "fattach to %s failed: %s",
1087 vt_door_path, strerror(errno));
1088 (void) door_revoke(vt_door);
1089 (void) fdetach(vt_door_path);
1090 vt_door = -1;
1091 return (B_FALSE);
1094 return (B_TRUE);
1098 * check to see if vtdaemon is already running.
1100 * The idea here is that we want to open the path to which we will
1101 * attach our door, lock it, and then make sure that no-one has beat us
1102 * to fattach(3c)ing onto it.
1104 * fattach(3c) is really a mount, so there are actually two possible
1105 * vnodes we could be dealing with. Our strategy is as follows:
1107 * - If the file we opened is a regular file (common case):
1108 * There is no fattach(3c)ed door, so we have a chance of becoming
1109 * the running vtdaemon. We attempt to lock the file: if it is
1110 * already locked, that means someone else raced us here, so we
1111 * lose and give up.
1113 * - If the file we opened is a namefs file:
1114 * This means there is already an established door fattach(3c)'ed
1115 * to the rendezvous path. We've lost the race, so we give up.
1116 * Note that in this case we also try to grab the file lock, and
1117 * will succeed in acquiring it since the vnode locked by the
1118 * "winning" vtdaemon was a regular one, and the one we locked was
1119 * the fattach(3c)'ed door node. At any rate, no harm is done.
1121 static boolean_t
1122 make_daemon_exclusive(void)
1124 int doorfd = -1;
1125 boolean_t ret = B_FALSE;
1126 struct stat st;
1127 struct flock flock;
1129 top:
1130 if ((doorfd = open(vt_door_path, O_CREAT|O_RDWR,
1131 S_IREAD|S_IWRITE|S_IRGRP|S_IROTH)) < 0) {
1132 syslog(LOG_ERR, "failed to open %s", vt_door_path);
1133 goto out;
1135 if (fstat(doorfd, &st) < 0) {
1136 syslog(LOG_ERR, "failed to stat %s", vt_door_path);
1137 goto out;
1140 * Lock the file to synchronize
1142 flock.l_type = F_WRLCK;
1143 flock.l_whence = SEEK_SET;
1144 flock.l_start = (off_t)0;
1145 flock.l_len = (off_t)0;
1146 if (fcntl(doorfd, F_SETLK, &flock) < 0) {
1148 * Someone else raced us here and grabbed the lock file
1149 * first. A warning here and exit.
1151 syslog(LOG_ERR, "vtdaemon is already running!");
1152 goto out;
1155 if (strcmp(st.st_fstype, "namefs") == 0) {
1156 struct door_info info;
1159 * There is already something fattach()'ed to this file.
1160 * Lets see what the door is up to.
1162 if (door_info(doorfd, &info) == 0 && info.di_target != -1) {
1163 syslog(LOG_ERR, "vtdaemon is already running!");
1164 goto out;
1167 (void) fdetach(vt_door_path);
1168 (void) close(doorfd);
1169 goto top;
1172 ret = setup_door();
1174 out:
1175 (void) close(doorfd);
1176 return (ret);
1179 static boolean_t
1180 mkvtdir(void)
1182 struct stat st;
1184 * We must create and lock everyone but root out of VT_TMPDIR
1185 * since anyone can open any UNIX domain socket, regardless of
1186 * its file system permissions.
1188 if (mkdir(VT_TMPDIR, S_IRWXU|S_IROTH|S_IXOTH|S_IRGRP|S_IXGRP) < 0 &&
1189 errno != EEXIST) {
1190 syslog(LOG_ERR, "could not mkdir '%s'", VT_TMPDIR);
1191 return (B_FALSE);
1193 /* paranoia */
1194 if ((stat(VT_TMPDIR, &st) < 0) || !S_ISDIR(st.st_mode)) {
1195 syslog(LOG_ERR, "'%s' is not a directory", VT_TMPDIR);
1196 return (B_FALSE);
1198 (void) chmod(VT_TMPDIR, S_IRWXU|S_IROTH|S_IXOTH|S_IRGRP|S_IXGRP);
1199 return (B_TRUE);
1203 main(int argc, char *argv[])
1205 int i;
1206 int opt;
1207 priv_set_t *privset;
1208 int active;
1210 openlog("vtdaemon", LOG_PID | LOG_CONS, 0);
1213 * Check that we have all privileges. It would be nice to pare
1214 * this down, but this is at least a first cut.
1216 if ((privset = priv_allocset()) == NULL) {
1217 syslog(LOG_ERR, "priv_allocset failed");
1218 return (1);
1221 if (getppriv(PRIV_EFFECTIVE, privset) != 0) {
1222 syslog(LOG_ERR, "getppriv failed", "getppriv");
1223 priv_freeset(privset);
1224 return (1);
1227 if (priv_isfullset(privset) == B_FALSE) {
1228 syslog(LOG_ERR, "You lack sufficient privilege "
1229 "to run this command (all privs required)");
1230 priv_freeset(privset);
1231 return (1);
1233 priv_freeset(privset);
1235 while ((opt = getopt(argc, argv, "ksrc:")) != EOF) {
1236 switch (opt) {
1237 case 'k':
1238 vt_hotkeys = B_FALSE;
1239 break;
1240 case 's':
1241 vt_secure = B_FALSE;
1242 break;
1243 case 'c':
1244 vtnodecount = atoi(optarg);
1245 break;
1246 default:
1247 break;
1251 (void) vt_setup_signal(SIGINT, 1);
1253 if (!mkvtdir())
1254 return (1);
1256 if (!eventstream_init())
1257 return (1);
1259 (void) snprintf(vt_door_path, sizeof (vt_door_path),
1260 VT_TMPDIR "/vtdaemon_door");
1262 if (!make_daemon_exclusive())
1263 return (1);
1265 /* only the main thread accepts SIGINT */
1266 (void) vt_setup_signal(SIGINT, 0);
1267 (void) sigset(SIGPIPE, SIG_IGN);
1268 (void) signal(SIGQUIT, SIG_IGN);
1269 (void) signal(SIGINT, catch);
1271 for (i = 0; i < 3; i++)
1272 (void) close(i);
1273 (void) setsid();
1275 if ((daemonfd = open(VT_DAEMON_CONSOLE_FILE, O_RDWR)) < 0) {
1276 return (1);
1279 if (daemonfd != 0)
1280 (void) dup2(daemonfd, STDIN_FILENO);
1281 if (daemonfd != 1)
1282 (void) dup2(daemonfd, STDOUT_FILENO);
1284 if (vtnodecount >= 2)
1285 (void) ioctl(daemonfd, VT_CONFIG, vtnodecount);
1287 if ((vt_ah_array = calloc(vtnodecount - 1,
1288 sizeof (adt_session_data_t *))) == NULL)
1289 return (1);
1291 (void) ioctl(daemonfd, VT_GETACTIVE, &active);
1293 if (active == 1) {
1295 * This is for someone who restarts vtdaemon while vtdaemon
1296 * is doing authentication on /dev/vt/1.
1297 * A better way is to continue the authentication, but there
1298 * are chances that the status of the target VT has changed.
1299 * So we just clear the screen here.
1301 (void) write(daemonfd, VT_CLEAR_SCREEN_STR,
1302 strlen(VT_CLEAR_SCREEN_STR));
1305 vt_serve_events();
1306 /*NOTREACHED*/
1309 static int
1310 vt_audit_start(adt_session_data_t **ah, pid_t pid)
1312 ucred_t *uc;
1314 if (adt_start_session(ah, NULL, 0))
1315 return (-1);
1317 if ((uc = ucred_get(pid)) == NULL) {
1318 (void) adt_end_session(*ah);
1319 return (-1);
1322 if (adt_set_from_ucred(*ah, uc, ADT_NEW)) {
1323 ucred_free(uc);
1324 (void) adt_end_session(*ah);
1325 return (-1);
1328 ucred_free(uc);
1329 return (0);
1333 * Write audit event
1335 static void
1336 vt_audit_event(adt_session_data_t *ah, au_event_t event_id, int status)
1338 adt_event_data_t *event;
1341 if ((event = adt_alloc_event(ah, event_id)) == NULL) {
1342 return;
1345 (void) adt_put_event(event,
1346 status == PAM_SUCCESS ? ADT_SUCCESS : ADT_FAILURE,
1347 status == PAM_SUCCESS ? ADT_SUCCESS : ADT_FAIL_PAM + status);
1349 adt_free_event(event);
1352 static void
1353 vt_check_source_audit(void)
1355 int fd;
1356 int source_vt;
1357 int real_vt;
1358 struct vt_stat state;
1359 pid_t pid;
1360 adt_session_data_t *ah;
1362 if ((fd = open(VT_DAEMON_CONSOLE_FILE, O_WRONLY)) < 0)
1363 return;
1365 if (ioctl(fd, VT_GETSTATE, &state) != 0 ||
1366 ioctl(fd, VT_GETACTIVE, &real_vt) != 0) {
1367 (void) close(fd);
1368 return;
1371 source_vt = state.v_active; /* 1..n */
1372 (void) close(fd);
1374 /* check if it's already locked */
1375 if (real_vt == 1) /* vtdaemon is taking over the screen */
1376 return;
1378 vt_read_utx(source_vt, &pid, NULL);
1379 if (pid == (pid_t)-1)
1380 return;
1382 if (vt_audit_start(&ah, pid) != 0) {
1383 syslog(LOG_ERR, "audit start failed ");
1384 return;
1388 * In case the previous session terminated abnormally.
1390 if (vt_ah_array[source_vt - 1] != NULL)
1391 (void) adt_end_session(vt_ah_array[source_vt - 1]);
1393 vt_ah_array[source_vt - 1] = ah;
1395 vt_audit_event(ah, ADT_screenlock, PAM_SUCCESS);