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]
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
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
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
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>
156 #include <security/pam_appl.h>
158 #include <sys/console.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
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;
195 vt_setup_signal(int signo
, int mask
)
199 (void) sigemptyset(&set
);
200 (void) sigaddset(&set
, signo
);
203 return (sigprocmask(SIG_BLOCK
, &set
, NULL
));
205 return (sigprocmask(SIG_UNBLOCK
, &set
, NULL
));
209 do_activate_screenlock(int display_num
)
213 (void) snprintf(dpy
, sizeof (dpy
), "%d", display_num
);
214 (void) execl("/usr/lib/vtxlock", "vtxlock", dpy
, NULL
);
218 vt_activate_screenlock(int display
)
222 if ((pid
= fork()) == -1)
225 if (pid
== 0) { /* child */
226 do_activate_screenlock(display
);
231 while (waitpid(pid
, (int *)0, 0) != pid
)
236 * Find the login process and user logged in on the target vt.
239 vt_read_utx(int target_vt
, pid_t
*pid
, char name
[])
242 char ttyntail
[sizeof (u
->ut_line
)];
246 if (VT_IS_SYSTEM_CONSOLE(target_vt
)) /* system console */
247 (void) snprintf(ttyntail
, sizeof (ttyntail
),
250 (void) snprintf(ttyntail
, sizeof (ttyntail
),
251 "%s%d", "vt/", target_vt
);
254 while ((u
= getutxent()) != NULL
)
255 /* see if this is the entry we want */
256 if ((u
->ut_type
== USER_PROCESS
) &&
258 (u
->ut_host
[0] == '\0') &&
259 (strncmp(u
->ut_line
, ttyntail
, sizeof (u
->ut_line
)) == 0)) {
263 (void) strncpy(name
, u
->ut_user
,
264 sizeof (u
->ut_user
));
265 name
[sizeof (u
->ut_user
)] = '\0';
276 static int is_tipline
= 0;
278 static char termbuf
[MAX_TERM_TYPE_LEN
];
279 static struct cons_getterm cons_term
= { sizeof (termbuf
), termbuf
};
282 return (is_tipline
== 1);
284 if ((fd
= open("/dev/console", O_RDONLY
)) < 0)
287 if (ioctl(fd
, CONS_GETTERM
, &cons_term
) != 0 &&
295 return (is_tipline
== 1);
299 validate_target_vt(int target_vt
)
302 struct vt_stat state
;
307 if ((fd
= open(VT_DAEMON_CONSOLE_FILE
, O_WRONLY
)) < 0)
310 if (ioctl(fd
, VT_GETSTATE
, &state
) != 0) {
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.
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
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) {
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 */
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
{
373 int ve_info
; /* vtno or display num */
376 static int eventstream
[2];
379 eventstream_init(void)
381 if (pipe(eventstream
) == -1)
387 eventstream_write(int channel
, vt_evt_t
*pevt
)
389 (void) write(eventstream
[channel
], pevt
, sizeof (vt_evt_t
));
393 eventstream_read(int channel
, vt_evt_t
*pevt
)
397 rval
= read(eventstream
[channel
], pevt
, sizeof (vt_evt_t
));
402 vt_ev_request(int cmd
, int info
)
410 channel
= (cmd
== VT_EV_TERMINATE_AUTH
) ? 1 : 0;
411 eventstream_write(channel
, &ve
);
415 vt_clear_events(void)
422 rval
= fstat(eventstream
[0], &buf
);
423 if (rval
!= -1 && buf
.st_size
> 0)
424 (void) eventstream_read(0, &evt
);
430 static int vt_conv(int, struct pam_message
**,
431 struct pam_response
**, void *);
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.
447 struct pollfd pollfds
[2];
451 pollfds
[0].fd
= eventstream
[0];
452 pollfds
[1].fd
= daemonfd
;
453 pollfds
[0].events
= pollfds
[1].events
=
454 POLLIN
| POLLRDNORM
| POLLRDBAND
| POLLPRI
;
457 pollfds
[0].revents
= pollfds
[1].revents
= 0;
460 sizeof (pollfds
) / sizeof (struct pollfd
), -1);
461 if (ret
== -1 && errno
!= EINTR
) {
465 if (ret
== -1 && errno
== EINTR
)
468 if (pollfds
[0].revents
) {
469 (void) eventstream_read(0, &ve
);
473 if (pollfds
[1].revents
)
487 cnt
= read(fd
, &c
, 1);
496 vt_getinput(int noecho
)
502 char input
[PAM_MAX_RESP_SIZE
];
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
;
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().
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
;
544 if (num_msg
>= PAM_MAX_NUM_MSG
) {
545 syslog(LOG_ERR
, "too many messages %d >= %d",
546 num_msg
, PAM_MAX_NUM_MSG
);
548 return (PAM_CONV_ERR
);
551 *response
= calloc(num_msg
, sizeof (struct pam_response
));
552 if (*response
== NULL
)
553 return (PAM_BUF_ERR
);
557 for (i
= 0; i
< num_msg
; i
++) {
561 if (m
->msg
== NULL
) {
562 syslog(LOG_ERR
, "message[%d]: %d/NULL\n",
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';
577 switch (m
->msg_style
) {
579 case PAM_PROMPT_ECHO_OFF
:
583 case PAM_PROMPT_ECHO_ON
:
584 (void) fputs(m
->msg
, stdout
);
586 r
->resp
= vt_getinput(echo_off
);
590 /* the user may want to see this */
591 (void) fputs(m
->msg
, stdout
);
592 (void) fputs("\n", stdout
);
596 (void) fputs(m
->msg
, stdout
);
597 (void) fputs("\n", stdout
);
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 */
608 /* Next message/response */
613 return (PAM_SUCCESS
);
617 * Service modules don't clean up responses if an error is returned.
618 * Free responses here.
621 for (k
= 0; k
< i
; k
++, r
++) {
623 /* Clear before freeing -- maybe a password */
624 bzero(r
->resp
, strlen(r
->resp
));
632 return (PAM_CONV_ERR
);
635 #define DEF_FILE "/etc/default/login"
637 /* Get PASSREQ from default file */
643 boolean_t retval
= B_FALSE
;
645 if ((defopen(DEF_FILE
)) == 0) {
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)
655 (void) defopen(NULL
);
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
668 #define VT_CLEAR_SCREEN_STR "\033[2J\033[1;1H"
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
;
678 struct pam_conv pam_conv
= {vt_conv
, NULL
};
681 vt_read_utx(target_vt
, &pid
, user_name
);
683 if (pid
== (pid_t
)-1 || user_name
[0] == '\0')
686 if ((err
= pam_start("vtdaemon", user_name
, &pam_conv
,
687 &vt_pamh
)) != PAM_SUCCESS
)
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
);
705 pam_flag
= PAM_DISALLOW_NULL_AUTHTOK
;
708 if (VT_IS_SYSTEM_CONSOLE(target_vt
))
709 (void) fprintf(stdout
,
710 "\nUnlock user %s on the system console\n",
713 (void) fprintf(stdout
,
714 "\nUnlock user %s on vt/%d\n", user_name
,
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
);
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
);
734 (void) mutex_unlock(&vt_mutex
);
736 if (err
== PAM_NEW_AUTHTOK_REQD
) {
740 err
= pam_chauthtok(vt_pamh
,
741 PAM_CHANGE_EXPIRED_AUTHTOK
);
744 (void) mutex_lock(&vt_mutex
);
745 if (vt_hotkeys_pending
) {
746 (void) mutex_unlock(&vt_mutex
);
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
);
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
);
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
;
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];
803 pollfds
[0].fd
= eventstream
[1];
804 pollfds
[0].events
= POLLIN
| POLLRDNORM
| POLLRDBAND
| POLLPRI
;
807 pollfds
[0].revents
= 0;
809 sizeof (pollfds
) / sizeof (struct pollfd
), -1);
810 if (ret
== -1 && errno
== EINTR
) {
814 if (pollfds
[0].revents
&& eventstream_read(1, &ve
)) {
818 vt_do_auth(ve
.ve_info
);
822 vt_activate_screenlock(ve
.ve_info
);
826 /* directly activate target vt */
827 vt_do_activate(ve
.ve_info
);
835 vt_check_target_session(uint32_t target_vt
)
837 pid_t pid
= (pid_t
)-1;
840 vt_ev_request(VT_EV_ACTIVATE
, target_vt
);
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
);
851 vt_ev_request(VT_EV_AUTH
, target_vt
);
855 vt_get_active_disp_info(struct vt_dispinfo
*vd
)
858 struct vt_stat state
;
861 if ((fd
= open(VT_DAEMON_CONSOLE_FILE
, O_RDONLY
)) < 0)
864 if (ioctl(fd
, VT_GETSTATE
, &state
) != 0) {
870 (void) snprintf(vtname
, sizeof (vtname
), "/dev/vt/%d", state
.v_active
);
871 if ((fd
= open(vtname
, O_RDONLY
)) < 0)
874 if (ioctl(fd
, VT_GETDISPINFO
, vd
) != 0) {
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.
892 vt_check_disp_active(pid_t x_pid
)
894 struct vt_dispinfo vd
;
896 if (vt_get_active_disp_info(&vd
) &&
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.
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
) ||
917 *logged_in
= vd
.v_login
;
918 *display_num
= vd
.v_dispnum
;
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);
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
);
945 vt_do_hotkeys(pid_t pid
, uint32_t target_vt
)
950 if (validate_target_vt(target_vt
) != 0)
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
);
963 /* cleared in vt_do_active and vt_do_auth */
964 vt_hotkeys_pending
= B_TRUE
;
965 (void) mutex_unlock(&vt_mutex
);
969 /* check source session for this hotkeys request */
971 /* then only need to check target session */
972 vt_check_target_session(target_vt
);
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
);
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
998 server_for_door(void *cookie
, char *args
, size_t alen
, door_desc_t
*dp
,
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);
1014 switch (vtargp
->vt_ev
) {
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
);
1026 if (!vt_hotkeys
) /* hotkeys are disabled? */
1029 vt_do_hotkeys(ucred_getpid(uc
), vtargp
->vt_num
);
1037 (void) door_return(NULL
, 0, NULL
, 0);
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
));
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
);
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
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.
1088 make_daemon_exclusive(void)
1091 boolean_t ret
= B_FALSE
;
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
);
1101 if (fstat(doorfd
, &st
) < 0) {
1102 syslog(LOG_ERR
, "failed to stat %s", vt_door_path
);
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!");
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!");
1133 (void) fdetach(vt_door_path
);
1134 (void) close(doorfd
);
1141 (void) close(doorfd
);
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 &&
1156 syslog(LOG_ERR
, "could not mkdir '%s'", VT_TMPDIR
);
1160 if ((stat(VT_TMPDIR
, &st
) < 0) || !S_ISDIR(st
.st_mode
)) {
1161 syslog(LOG_ERR
, "'%s' is not a directory", VT_TMPDIR
);
1164 (void) chmod(VT_TMPDIR
, S_IRWXU
|S_IROTH
|S_IXOTH
|S_IRGRP
|S_IXGRP
);
1169 main(int argc
, char *argv
[])
1173 priv_set_t
*privset
;
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");
1187 if (getppriv(PRIV_EFFECTIVE
, privset
) != 0) {
1188 syslog(LOG_ERR
, "getppriv failed", "getppriv");
1189 priv_freeset(privset
);
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
);
1199 priv_freeset(privset
);
1201 while ((opt
= getopt(argc
, argv
, "ksrc:")) != EOF
) {
1204 vt_hotkeys
= B_FALSE
;
1207 vt_secure
= B_FALSE
;
1210 vtnodecount
= atoi(optarg
);
1217 (void) vt_setup_signal(SIGINT
, 1);
1222 if (!eventstream_init())
1225 (void) snprintf(vt_door_path
, sizeof (vt_door_path
),
1226 VT_TMPDIR
"/vtdaemon_door");
1228 if (!make_daemon_exclusive())
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
++)
1241 if ((daemonfd
= open(VT_DAEMON_CONSOLE_FILE
, O_RDWR
)) < 0) {
1246 (void) dup2(daemonfd
, STDIN_FILENO
);
1248 (void) dup2(daemonfd
, STDOUT_FILENO
);
1250 if (vtnodecount
>= 2)
1251 (void) ioctl(daemonfd
, VT_CONFIG
, vtnodecount
);
1253 (void) ioctl(daemonfd
, VT_GETACTIVE
, &active
);
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
));