Unleashed v1.4
[unleashed.git] / usr / src / cmd / vt / vtdaemon.c
blobeb479fa6e70ad4bc0cf721032985d4122362477d
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 <alloca.h>
134 #include <assert.h>
135 #include <errno.h>
136 #include <door.h>
137 #include <fcntl.h>
138 #include <signal.h>
139 #include <stdarg.h>
140 #include <stdio.h>
141 #include <stdlib.h>
142 #include <string.h>
143 #include <strings.h>
144 #include <synch.h>
145 #include <thread.h>
146 #include <unistd.h>
147 #include <wait.h>
148 #include <limits.h>
149 #include <zone.h>
150 #include <priv.h>
151 #include <pwd.h>
152 #include <utmpx.h>
153 #include <procfs.h>
154 #include <poll.h>
155 #include <termio.h>
156 #include <security/pam_appl.h>
157 #include <time.h>
158 #include <sys/console.h>
159 #include <assert.h>
160 #include <syslog.h>
162 #include <sys/vt.h>
163 #include <sys/vtdaemon.h>
166 * The door file /var/run/vt/vtdaemon_door
168 #define VT_TMPDIR "/var/run/vt"
170 #define VT_DAEMON_ARG 0
171 #define VT_DAEMON_CONSOLE_FILE "/dev/vt/1"
173 #define VT_IS_SYSTEM_CONSOLE(vtno) ((vtno) == 1)
175 /* Defaults for updating expired passwords */
176 #define DEF_ATTEMPTS 3
178 int daemonfd;
180 static boolean_t vt_hotkeys = B_TRUE; /* '-k' option to disable */
181 static boolean_t vt_secure = B_TRUE; /* '-s' option to disable */
183 static char vt_door_path[MAXPATHLEN];
184 static int vt_door = -1;
186 /* protecting vt_hotkeys_pending and vt_auth_doing */
187 static mutex_t vt_mutex = DEFAULTMUTEX;
189 static boolean_t vt_hotkeys_pending = B_FALSE;
190 static boolean_t vt_auth_doing = B_FALSE;
192 static int vtnodecount = 0;
194 static int
195 vt_setup_signal(int signo, int mask)
197 sigset_t set;
199 (void) sigemptyset(&set);
200 (void) sigaddset(&set, signo);
202 if (mask)
203 return (sigprocmask(SIG_BLOCK, &set, NULL));
204 else
205 return (sigprocmask(SIG_UNBLOCK, &set, NULL));
208 static void
209 do_activate_screenlock(int display_num)
211 char dpy[16];
213 (void) snprintf(dpy, sizeof (dpy), "%d", display_num);
214 (void) execl("/usr/lib/vtxlock", "vtxlock", dpy, NULL);
217 static void
218 vt_activate_screenlock(int display)
220 pid_t pid;
222 if ((pid = fork()) == -1)
223 return;
225 if (pid == 0) { /* child */
226 do_activate_screenlock(display);
227 exit(0);
230 /* parent */
231 while (waitpid(pid, (int *)0, 0) != pid)
232 continue;
236 * Find the login process and user logged in on the target vt.
238 static void
239 vt_read_utx(int target_vt, pid_t *pid, char name[])
241 struct utmpx *u;
242 char ttyntail[sizeof (u->ut_line)];
244 *pid = (pid_t)-1;
246 if (VT_IS_SYSTEM_CONSOLE(target_vt)) /* system console */
247 (void) snprintf(ttyntail, sizeof (ttyntail),
248 "%s", "console");
249 else
250 (void) snprintf(ttyntail, sizeof (ttyntail),
251 "%s%d", "vt/", target_vt);
253 setutxent();
254 while ((u = getutxent()) != NULL)
255 /* see if this is the entry we want */
256 if ((u->ut_type == USER_PROCESS) &&
257 (!nonuserx(*u)) &&
258 (u->ut_host[0] == '\0') &&
259 (strncmp(u->ut_line, ttyntail, sizeof (u->ut_line)) == 0)) {
261 *pid = u->ut_pid;
262 if (name != NULL) {
263 (void) strncpy(name, u->ut_user,
264 sizeof (u->ut_user));
265 name[sizeof (u->ut_user)] = '\0';
267 break;
270 endutxent();
273 static boolean_t
274 vt_is_tipline(void)
276 static int is_tipline = 0;
277 int fd;
278 static char termbuf[MAX_TERM_TYPE_LEN];
279 static struct cons_getterm cons_term = { sizeof (termbuf), termbuf};
281 if (is_tipline != 0)
282 return (is_tipline == 1);
284 if ((fd = open("/dev/console", O_RDONLY)) < 0)
285 return (B_FALSE);
287 if (ioctl(fd, CONS_GETTERM, &cons_term) != 0 &&
288 errno == ENODEV) {
289 is_tipline = 1;
290 } else {
291 is_tipline = -1;
294 (void) close(fd);
295 return (is_tipline == 1);
298 static int
299 validate_target_vt(int target_vt)
301 int fd;
302 struct vt_stat state;
304 if (target_vt < 1)
305 return (-1);
307 if ((fd = open(VT_DAEMON_CONSOLE_FILE, O_WRONLY)) < 0)
308 return (-1);
310 if (ioctl(fd, VT_GETSTATE, &state) != 0) {
311 (void) close(fd);
312 return (-1);
315 (void) close(fd);
317 if (state.v_active == target_vt) {
318 return (1); /* it's current active vt */
321 if (target_vt == 1) {
323 * In tipline case, the system console is always
324 * available, so ignore this request.
326 if (vt_is_tipline())
327 return (-1);
329 target_vt = 0;
333 * The hotkey request and corresponding target_vt number can come
334 * from either kernel or Xserver (or other user applications).
335 * In kernel we've validated the hotkey request, but Xserver (or
336 * other user applications) cannot do it, so here we still try
337 * to validate it.
339 * VT_GETSTATE is only valid for first 16 VTs for historical reasons.
340 * Fortunately, in practice, Xserver can only send the hotkey
341 * request of target_vt number from 1 to 12 (Ctrl + Alt + F1 to F2).
343 if (target_vt < 8 * sizeof (state.v_state)) {
344 if ((state.v_state & (1 << target_vt)) != 0) {
345 return (0);
346 } else {
347 return (-1);
351 return (0);
354 static void
355 vt_do_activate(int target_vt)
357 (void) ioctl(daemonfd, VT_ACTIVATE, target_vt);
358 (void) mutex_lock(&vt_mutex);
359 vt_hotkeys_pending = B_FALSE;
360 (void) mutex_unlock(&vt_mutex);
363 /* events written to fd 0 and read from fd 1 */
364 #define VT_EV_AUTH 1
365 #define VT_EV_LOCK 2
366 #define VT_EV_ACTIVATE 3
368 /* events written to fd 1 and read from fd 0 */
369 #define VT_EV_TERMINATE_AUTH 4
371 typedef struct vt_evt {
372 int ve_cmd;
373 int ve_info; /* vtno or display num */
374 } vt_evt_t;
376 static int eventstream[2];
378 boolean_t
379 eventstream_init(void)
381 if (pipe(eventstream) == -1)
382 return (B_FALSE);
383 return (B_TRUE);
386 void
387 eventstream_write(int channel, vt_evt_t *pevt)
389 (void) write(eventstream[channel], pevt, sizeof (vt_evt_t));
392 static boolean_t
393 eventstream_read(int channel, vt_evt_t *pevt)
395 ssize_t rval;
397 rval = read(eventstream[channel], pevt, sizeof (vt_evt_t));
398 return (rval > 0);
401 static void
402 vt_ev_request(int cmd, int info)
404 int channel;
405 vt_evt_t ve;
407 ve.ve_cmd = cmd;
408 ve.ve_info = info;
410 channel = (cmd == VT_EV_TERMINATE_AUTH) ? 1 : 0;
411 eventstream_write(channel, &ve);
414 static void
415 vt_clear_events(void)
417 int rval = 0;
418 struct stat buf;
419 vt_evt_t evt;
421 while (rval == 0) {
422 rval = fstat(eventstream[0], &buf);
423 if (rval != -1 && buf.st_size > 0)
424 (void) eventstream_read(0, &evt);
425 else
426 break;
430 static int vt_conv(int, struct pam_message **,
431 struct pam_response **, void *);
433 /*ARGSUSED*/
434 static void
435 catch(int x)
437 (void) signal(SIGINT, catch);
441 * The SIGINT (ctl_c) will restart the authentication, and re-prompt
442 * the end user to input the password.
444 static int
445 vt_poll()
447 struct pollfd pollfds[2];
448 vt_evt_t ve;
449 int ret;
451 pollfds[0].fd = eventstream[0];
452 pollfds[1].fd = daemonfd;
453 pollfds[0].events = pollfds[1].events =
454 POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI;
456 for (;;) {
457 pollfds[0].revents = pollfds[1].revents = 0;
459 ret = poll(pollfds,
460 sizeof (pollfds) / sizeof (struct pollfd), -1);
461 if (ret == -1 && errno != EINTR) {
462 continue;
465 if (ret == -1 && errno == EINTR)
466 return (-1);
468 if (pollfds[0].revents) {
469 (void) eventstream_read(0, &ve);
470 return (0);
473 if (pollfds[1].revents)
474 return (1);
476 return (0);
481 static char
482 vt_getchar(int fd)
484 char c;
485 int cnt;
487 cnt = read(fd, &c, 1);
488 if (cnt > 0) {
489 return (c);
492 return (EOF);
495 static char *
496 vt_getinput(int noecho)
498 int c;
499 int i = 0;
500 struct termio tty;
501 tcflag_t tty_flags;
502 char input[PAM_MAX_RESP_SIZE];
504 if (noecho) {
505 (void) ioctl(daemonfd, TCGETA, &tty);
506 tty_flags = tty.c_lflag;
507 tty.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
508 (void) ioctl(daemonfd, TCSETAF, &tty);
511 while ((vt_poll()) == 1) {
512 if ((c = vt_getchar(daemonfd)) != '\n' && c != '\r' &&
513 c != EOF && (i < PAM_MAX_RESP_SIZE - 1))
514 input[i++] = (char)c;
515 else
516 break;
519 input[i] = '\0';
521 if (noecho) {
522 tty.c_lflag = tty_flags;
523 (void) ioctl(daemonfd, TCSETAW, &tty);
524 (void) fputc('\n', stdout);
527 return (strdup(input));
531 * vt_conv: vtdaemon PAM conversation function.
532 * SIGINT/EINTR is handled in vt_getinput()/vt_poll().
535 /*ARGSUSED*/
536 static int
537 vt_conv(int num_msg, struct pam_message **msg,
538 struct pam_response **response, void *appdata_ptr)
540 struct pam_message *m;
541 struct pam_response *r;
542 int i, k;
544 if (num_msg >= PAM_MAX_NUM_MSG) {
545 syslog(LOG_ERR, "too many messages %d >= %d",
546 num_msg, PAM_MAX_NUM_MSG);
547 *response = NULL;
548 return (PAM_CONV_ERR);
551 *response = calloc(num_msg, sizeof (struct pam_response));
552 if (*response == NULL)
553 return (PAM_BUF_ERR);
555 m = *msg;
556 r = *response;
557 for (i = 0; i < num_msg; i++) {
558 int echo_off = 0;
560 /* Bad message */
561 if (m->msg == NULL) {
562 syslog(LOG_ERR, "message[%d]: %d/NULL\n",
563 i, m->msg_style);
564 goto err;
568 * Fix up final newline:
569 * remove from prompts, add back for messages.
571 if (m->msg[strlen(m->msg)] == '\n')
572 m->msg[strlen(m->msg)] = '\0';
574 r->resp = NULL;
575 r->resp_retcode = 0;
577 switch (m->msg_style) {
579 case PAM_PROMPT_ECHO_OFF:
580 echo_off = 1;
581 /* FALLTHROUGH */
583 case PAM_PROMPT_ECHO_ON:
584 (void) fputs(m->msg, stdout);
586 r->resp = vt_getinput(echo_off);
587 break;
589 case PAM_ERROR_MSG:
590 /* the user may want to see this */
591 (void) fputs(m->msg, stdout);
592 (void) fputs("\n", stdout);
593 break;
595 case PAM_TEXT_INFO:
596 (void) fputs(m->msg, stdout);
597 (void) fputs("\n", stdout);
598 break;
600 default:
601 syslog(LOG_ERR, "message[%d]: unknown type"
602 "%d/val=\"%s\"", i, m->msg_style, m->msg);
604 /* error, service module won't clean up */
605 goto err;
608 /* Next message/response */
609 m++;
610 r++;
613 return (PAM_SUCCESS);
615 err:
617 * Service modules don't clean up responses if an error is returned.
618 * Free responses here.
620 r = *response;
621 for (k = 0; k < i; k++, r++) {
622 if (r->resp) {
623 /* Clear before freeing -- maybe a password */
624 bzero(r->resp, strlen(r->resp));
625 free(r->resp);
626 r->resp = NULL;
630 free(*response);
631 *response = NULL;
632 return (PAM_CONV_ERR);
635 #define DEF_FILE "/etc/default/login"
637 /* Get PASSREQ from default file */
638 static boolean_t
639 vt_default(void)
641 int flags;
642 char *ptr;
643 boolean_t retval = B_FALSE;
645 if ((defopen(DEF_FILE)) == 0) {
646 /* ignore case */
647 flags = defcntl(DC_GETFLAGS, 0);
648 TURNOFF(flags, DC_CASE);
649 (void) defcntl(DC_SETFLAGS, flags);
651 if ((ptr = defread("PASSREQ=")) != NULL &&
652 strcasecmp("YES", ptr) == 0)
653 retval = B_TRUE;
655 (void) defopen(NULL);
658 return (retval);
662 * VT_CLEAR_SCREEN_STR is the console terminal escape sequence used to
663 * clear the current screen. The vt special console (/dev/vt/1) is
664 * just reserved for vtdaemon, and the TERM/termcap of it is always
665 * the local sun-color, which is always supported by our kernel terminal
666 * emulator.
668 #define VT_CLEAR_SCREEN_STR "\033[2J\033[1;1H"
670 static void
671 vt_do_auth(int target_vt)
673 char user_name[sizeof (((struct utmpx *)0)->ut_line) + 1] = {'\0'};
674 pam_handle_t *vt_pamh;
675 int err;
676 int pam_flag = 0;
677 int chpasswd_tries;
678 struct pam_conv pam_conv = {vt_conv, NULL};
679 pid_t pid;
681 vt_read_utx(target_vt, &pid, user_name);
683 if (pid == (pid_t)-1 || user_name[0] == '\0')
684 return;
686 if ((err = pam_start("vtdaemon", user_name, &pam_conv,
687 &vt_pamh)) != PAM_SUCCESS)
688 return;
691 * firstly switch to the vtdaemon special console
692 * and clear the current screen
694 (void) ioctl(daemonfd, VT_ACTIVATE, VT_DAEMON_ARG);
695 (void) write(daemonfd, VT_CLEAR_SCREEN_STR,
696 strlen(VT_CLEAR_SCREEN_STR));
697 (void) ioctl(daemonfd, VT_SET_TARGET, target_vt);
699 (void) mutex_lock(&vt_mutex);
700 vt_auth_doing = B_TRUE;
701 vt_hotkeys_pending = B_FALSE;
702 (void) mutex_unlock(&vt_mutex);
704 if (vt_default())
705 pam_flag = PAM_DISALLOW_NULL_AUTHTOK;
707 do {
708 if (VT_IS_SYSTEM_CONSOLE(target_vt))
709 (void) fprintf(stdout,
710 "\nUnlock user %s on the system console\n",
711 user_name);
712 else
713 (void) fprintf(stdout,
714 "\nUnlock user %s on vt/%d\n", user_name,
715 target_vt);
717 err = pam_authenticate(vt_pamh, pam_flag);
719 (void) mutex_lock(&vt_mutex);
720 if (vt_hotkeys_pending) {
721 (void) mutex_unlock(&vt_mutex);
722 break;
724 (void) mutex_unlock(&vt_mutex);
726 if (err == PAM_SUCCESS) {
727 err = pam_acct_mgmt(vt_pamh, pam_flag);
729 (void) mutex_lock(&vt_mutex);
730 if (vt_hotkeys_pending) {
731 (void) mutex_unlock(&vt_mutex);
732 break;
734 (void) mutex_unlock(&vt_mutex);
736 if (err == PAM_NEW_AUTHTOK_REQD) {
737 chpasswd_tries = 0;
739 do {
740 err = pam_chauthtok(vt_pamh,
741 PAM_CHANGE_EXPIRED_AUTHTOK);
742 chpasswd_tries++;
744 (void) mutex_lock(&vt_mutex);
745 if (vt_hotkeys_pending) {
746 (void) mutex_unlock(&vt_mutex);
747 break;
749 (void) mutex_unlock(&vt_mutex);
751 } while ((err == PAM_AUTHTOK_ERR ||
752 err == PAM_TRY_AGAIN) &&
753 chpasswd_tries < DEF_ATTEMPTS);
755 (void) mutex_lock(&vt_mutex);
756 if (vt_hotkeys_pending) {
757 (void) mutex_unlock(&vt_mutex);
758 break;
760 (void) mutex_unlock(&vt_mutex);
764 if (err != PAM_SUCCESS) {
765 (void) fprintf(stdout, "%s",
766 pam_strerror(vt_pamh, err));
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 } while (err != PAM_SUCCESS);
778 (void) mutex_lock(&vt_mutex);
779 if (!vt_hotkeys_pending) {
781 * Should be PAM_SUCCESS to reach here.
783 (void) ioctl(daemonfd, VT_ACTIVATE, target_vt);
785 (void) mutex_unlock(&vt_mutex);
787 (void) pam_end(vt_pamh, err);
789 (void) mutex_lock(&vt_mutex);
790 vt_auth_doing = B_FALSE;
791 vt_clear_events();
792 (void) mutex_unlock(&vt_mutex);
795 /* main thread (lock and auth) */
796 static void __NORETURN
797 vt_serve_events(void)
799 struct pollfd pollfds[1];
800 int ret;
801 vt_evt_t ve;
803 pollfds[0].fd = eventstream[1];
804 pollfds[0].events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI;
806 for (;;) {
807 pollfds[0].revents = 0;
808 ret = poll(pollfds,
809 sizeof (pollfds) / sizeof (struct pollfd), -1);
810 if (ret == -1 && errno == EINTR) {
811 continue;
814 if (pollfds[0].revents && eventstream_read(1, &ve)) {
815 /* new request */
816 switch (ve.ve_cmd) {
817 case VT_EV_AUTH:
818 vt_do_auth(ve.ve_info);
819 break;
821 case VT_EV_LOCK:
822 vt_activate_screenlock(ve.ve_info);
823 break;
825 case VT_EV_ACTIVATE:
826 /* directly activate target vt */
827 vt_do_activate(ve.ve_info);
828 break;
834 static void
835 vt_check_target_session(uint32_t target_vt)
837 pid_t pid = (pid_t)-1;
839 if (!vt_secure) {
840 vt_ev_request(VT_EV_ACTIVATE, target_vt);
841 return;
844 /* check the target session */
845 vt_read_utx(target_vt, &pid, NULL);
846 if (pid == (pid_t)-1) {
847 vt_ev_request(VT_EV_ACTIVATE, target_vt);
848 return;
851 vt_ev_request(VT_EV_AUTH, target_vt);
854 static boolean_t
855 vt_get_active_disp_info(struct vt_dispinfo *vd)
857 int fd;
858 struct vt_stat state;
859 char vtname[16];
861 if ((fd = open(VT_DAEMON_CONSOLE_FILE, O_RDONLY)) < 0)
862 return (B_FALSE);
864 if (ioctl(fd, VT_GETSTATE, &state) != 0) {
865 (void) close(fd);
866 return (B_FALSE);
868 (void) close(fd);
870 (void) snprintf(vtname, sizeof (vtname), "/dev/vt/%d", state.v_active);
871 if ((fd = open(vtname, O_RDONLY)) < 0)
872 return (B_FALSE);
874 if (ioctl(fd, VT_GETDISPINFO, vd) != 0) {
875 (void) close(fd);
876 return (B_FALSE);
879 (void) close(fd);
880 return (B_TRUE);
884 * Xserver registers its pid into kernel to associate it with
885 * its vt upon startup for each graphical display. So here we can
886 * check if the pid is of the Xserver for the current active
887 * display when we receive a special VT_EV_X_EXIT request from
888 * a process. If the request does not come from the current
889 * active Xserver, it is discarded.
891 static boolean_t
892 vt_check_disp_active(pid_t x_pid)
894 struct vt_dispinfo vd;
896 if (vt_get_active_disp_info(&vd) &&
897 vd.v_pid == x_pid)
898 return (B_TRUE);
900 return (B_FALSE);
904 * check if the pid is of the Xserver for the current active display,
905 * return true when it is, and then also return other associated
906 * information with the Xserver.
908 static boolean_t
909 vt_get_disp_info(pid_t x_pid, int *logged_in, int *display_num)
911 struct vt_dispinfo vd;
913 if (!vt_get_active_disp_info(&vd) ||
914 vd.v_pid != x_pid)
915 return (B_FALSE);
917 *logged_in = vd.v_login;
918 *display_num = vd.v_dispnum;
919 return (B_TRUE);
922 static void
923 vt_terminate_auth(void)
925 struct timespec sleeptime;
927 sleeptime.tv_sec = 0;
928 sleeptime.tv_nsec = 1000000; /* 1ms */
930 (void) mutex_lock(&vt_mutex);
931 while (vt_auth_doing) {
932 vt_ev_request(VT_EV_TERMINATE_AUTH, 0);
934 if (vt_auth_doing) {
935 (void) mutex_unlock(&vt_mutex);
936 (void) nanosleep(&sleeptime, NULL);
937 sleeptime.tv_nsec *= 2;
938 (void) mutex_lock(&vt_mutex);
941 (void) mutex_unlock(&vt_mutex);
944 static void
945 vt_do_hotkeys(pid_t pid, uint32_t target_vt)
947 int logged_in;
948 int display_num;
950 if (validate_target_vt(target_vt) != 0)
951 return;
954 * Maybe last switch action is being taken and the lock is ongoing,
955 * here we must reject the newly request.
957 (void) mutex_lock(&vt_mutex);
958 if (vt_hotkeys_pending) {
959 (void) mutex_unlock(&vt_mutex);
960 return;
963 /* cleared in vt_do_active and vt_do_auth */
964 vt_hotkeys_pending = B_TRUE;
965 (void) mutex_unlock(&vt_mutex);
967 vt_terminate_auth();
969 /* check source session for this hotkeys request */
970 if (pid == 0) {
971 /* then only need to check target session */
972 vt_check_target_session(target_vt);
973 return;
977 * check if it comes from current active X graphical session,
978 * if not, ignore this request.
980 if (!vt_get_disp_info(pid, &logged_in, &display_num)) {
981 (void) mutex_lock(&vt_mutex);
982 vt_hotkeys_pending = B_FALSE;
983 (void) mutex_unlock(&vt_mutex);
984 return;
987 if (logged_in && vt_secure)
988 vt_ev_request(VT_EV_LOCK, display_num);
990 vt_check_target_session(target_vt);
994 * The main routine for the door server that deals with secure hotkeys
996 /* ARGSUSED */
997 static void
998 server_for_door(void *cookie, char *args, size_t alen, door_desc_t *dp,
999 uint_t n_desc)
1001 ucred_t *uc = NULL;
1002 vt_cmd_arg_t *vtargp;
1004 /* LINTED E_BAD_PTR_CAST_ALIGN */
1005 vtargp = (vt_cmd_arg_t *)args;
1007 if (vtargp == NULL ||
1008 alen != sizeof (vt_cmd_arg_t) ||
1009 door_ucred(&uc) != 0) {
1010 (void) door_return(NULL, 0, NULL, 0);
1011 return;
1014 switch (vtargp->vt_ev) {
1015 case VT_EV_X_EXIT:
1017 * Xserver will issue this event requesting to switch back
1018 * to previous active vt when it's exiting and the associated
1019 * vt is currently active.
1021 if (vt_check_disp_active(ucred_getpid(uc)))
1022 vt_do_hotkeys(0, vtargp->vt_num);
1023 break;
1025 case VT_EV_HOTKEYS:
1026 if (!vt_hotkeys) /* hotkeys are disabled? */
1027 break;
1029 vt_do_hotkeys(ucred_getpid(uc), vtargp->vt_num);
1030 break;
1032 default:
1033 break;
1036 ucred_free(uc);
1037 (void) door_return(NULL, 0, NULL, 0);
1040 static boolean_t
1041 setup_door(void)
1043 if ((vt_door = door_create(server_for_door, NULL,
1044 DOOR_UNREF | DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) < 0) {
1045 syslog(LOG_ERR, "door_create failed: %s", strerror(errno));
1046 return (B_FALSE);
1049 (void) fdetach(vt_door_path);
1051 if (fattach(vt_door, vt_door_path) != 0) {
1052 syslog(LOG_ERR, "fattach to %s failed: %s",
1053 vt_door_path, strerror(errno));
1054 (void) door_revoke(vt_door);
1055 (void) fdetach(vt_door_path);
1056 vt_door = -1;
1057 return (B_FALSE);
1060 return (B_TRUE);
1064 * check to see if vtdaemon is already running.
1066 * The idea here is that we want to open the path to which we will
1067 * attach our door, lock it, and then make sure that no-one has beat us
1068 * to fattach(3c)ing onto it.
1070 * fattach(3c) is really a mount, so there are actually two possible
1071 * vnodes we could be dealing with. Our strategy is as follows:
1073 * - If the file we opened is a regular file (common case):
1074 * There is no fattach(3c)ed door, so we have a chance of becoming
1075 * the running vtdaemon. We attempt to lock the file: if it is
1076 * already locked, that means someone else raced us here, so we
1077 * lose and give up.
1079 * - If the file we opened is a namefs file:
1080 * This means there is already an established door fattach(3c)'ed
1081 * to the rendezvous path. We've lost the race, so we give up.
1082 * Note that in this case we also try to grab the file lock, and
1083 * will succeed in acquiring it since the vnode locked by the
1084 * "winning" vtdaemon was a regular one, and the one we locked was
1085 * the fattach(3c)'ed door node. At any rate, no harm is done.
1087 static boolean_t
1088 make_daemon_exclusive(void)
1090 int doorfd = -1;
1091 boolean_t ret = B_FALSE;
1092 struct stat st;
1093 struct flock flock;
1095 top:
1096 if ((doorfd = open(vt_door_path, O_CREAT|O_RDWR,
1097 S_IREAD|S_IWRITE|S_IRGRP|S_IROTH)) < 0) {
1098 syslog(LOG_ERR, "failed to open %s", vt_door_path);
1099 goto out;
1101 if (fstat(doorfd, &st) < 0) {
1102 syslog(LOG_ERR, "failed to stat %s", vt_door_path);
1103 goto out;
1106 * Lock the file to synchronize
1108 flock.l_type = F_WRLCK;
1109 flock.l_whence = SEEK_SET;
1110 flock.l_start = (off_t)0;
1111 flock.l_len = (off_t)0;
1112 if (fcntl(doorfd, F_SETLK, &flock) < 0) {
1114 * Someone else raced us here and grabbed the lock file
1115 * first. A warning here and exit.
1117 syslog(LOG_ERR, "vtdaemon is already running!");
1118 goto out;
1121 if (strcmp(st.st_fstype, "namefs") == 0) {
1122 struct door_info info;
1125 * There is already something fattach()'ed to this file.
1126 * Lets see what the door is up to.
1128 if (door_info(doorfd, &info) == 0 && info.di_target != -1) {
1129 syslog(LOG_ERR, "vtdaemon is already running!");
1130 goto out;
1133 (void) fdetach(vt_door_path);
1134 (void) close(doorfd);
1135 goto top;
1138 ret = setup_door();
1140 out:
1141 (void) close(doorfd);
1142 return (ret);
1145 static boolean_t
1146 mkvtdir(void)
1148 struct stat st;
1150 * We must create and lock everyone but root out of VT_TMPDIR
1151 * since anyone can open any UNIX domain socket, regardless of
1152 * its file system permissions.
1154 if (mkdir(VT_TMPDIR, S_IRWXU|S_IROTH|S_IXOTH|S_IRGRP|S_IXGRP) < 0 &&
1155 errno != EEXIST) {
1156 syslog(LOG_ERR, "could not mkdir '%s'", VT_TMPDIR);
1157 return (B_FALSE);
1159 /* paranoia */
1160 if ((stat(VT_TMPDIR, &st) < 0) || !S_ISDIR(st.st_mode)) {
1161 syslog(LOG_ERR, "'%s' is not a directory", VT_TMPDIR);
1162 return (B_FALSE);
1164 (void) chmod(VT_TMPDIR, S_IRWXU|S_IROTH|S_IXOTH|S_IRGRP|S_IXGRP);
1165 return (B_TRUE);
1169 main(int argc, char *argv[])
1171 int i;
1172 int opt;
1173 priv_set_t *privset;
1174 int active;
1176 openlog("vtdaemon", LOG_PID | LOG_CONS, 0);
1179 * Check that we have all privileges. It would be nice to pare
1180 * this down, but this is at least a first cut.
1182 if ((privset = priv_allocset()) == NULL) {
1183 syslog(LOG_ERR, "priv_allocset failed");
1184 return (1);
1187 if (getppriv(PRIV_EFFECTIVE, privset) != 0) {
1188 syslog(LOG_ERR, "getppriv failed", "getppriv");
1189 priv_freeset(privset);
1190 return (1);
1193 if (priv_isfullset(privset) == B_FALSE) {
1194 syslog(LOG_ERR, "You lack sufficient privilege "
1195 "to run this command (all privs required)");
1196 priv_freeset(privset);
1197 return (1);
1199 priv_freeset(privset);
1201 while ((opt = getopt(argc, argv, "ksrc:")) != EOF) {
1202 switch (opt) {
1203 case 'k':
1204 vt_hotkeys = B_FALSE;
1205 break;
1206 case 's':
1207 vt_secure = B_FALSE;
1208 break;
1209 case 'c':
1210 vtnodecount = atoi(optarg);
1211 break;
1212 default:
1213 break;
1217 (void) vt_setup_signal(SIGINT, 1);
1219 if (!mkvtdir())
1220 return (1);
1222 if (!eventstream_init())
1223 return (1);
1225 (void) snprintf(vt_door_path, sizeof (vt_door_path),
1226 VT_TMPDIR "/vtdaemon_door");
1228 if (!make_daemon_exclusive())
1229 return (1);
1231 /* only the main thread accepts SIGINT */
1232 (void) vt_setup_signal(SIGINT, 0);
1233 (void) sigset(SIGPIPE, SIG_IGN);
1234 (void) signal(SIGQUIT, SIG_IGN);
1235 (void) signal(SIGINT, catch);
1237 for (i = 0; i < 3; i++)
1238 (void) close(i);
1239 (void) setsid();
1241 if ((daemonfd = open(VT_DAEMON_CONSOLE_FILE, O_RDWR)) < 0) {
1242 return (1);
1245 if (daemonfd != 0)
1246 (void) dup2(daemonfd, STDIN_FILENO);
1247 if (daemonfd != 1)
1248 (void) dup2(daemonfd, STDOUT_FILENO);
1250 if (vtnodecount >= 2)
1251 (void) ioctl(daemonfd, VT_CONFIG, vtnodecount);
1253 (void) ioctl(daemonfd, VT_GETACTIVE, &active);
1255 if (active == 1) {
1257 * This is for someone who restarts vtdaemon while vtdaemon
1258 * is doing authentication on /dev/vt/1.
1259 * A better way is to continue the authentication, but there
1260 * are chances that the status of the target VT has changed.
1261 * So we just clear the screen here.
1263 (void) write(daemonfd, VT_CLEAR_SCREEN_STR,
1264 strlen(VT_CLEAR_SCREEN_STR));
1267 vt_serve_events();
1268 /*NOTREACHED*/