1 /*
2 * Copyright © 2012 Benjamin Franzke
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 */
25
26 #include "config.h"
27
28 #include <stdbool.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <assert.h>
33 #include <poll.h>
34 #include <errno.h>
35
36 #include <getopt.h>
37
38 #include <sys/types.h>
39 #include <sys/ioctl.h>
40 #include <sys/stat.h>
41 #include <sys/wait.h>
42 #include <sys/socket.h>
43 #include <sys/signalfd.h>
44 #include <signal.h>
45 #include <unistd.h>
46 #include <fcntl.h>
47
48 #include <linux/vt.h>
49 #include <linux/major.h>
50 #include <linux/kd.h>
51
52 #include <pwd.h>
53 #include <grp.h>
54 #include <security/pam_appl.h>
55
56 #ifdef HAVE_SYSTEMD_LOGIN
57 #include <systemd/sd-login.h>
58 #endif
59
60 #include "weston-launch.h"
61
62 #define DRM_MAJOR 226
63
64 #ifndef KDSKBMUTE
65 #define KDSKBMUTE 0x4B51
66 #endif
67
68 #ifndef EVIOCREVOKE
69 #define EVIOCREVOKE _IOW('E', 0x91, int)
70 #endif
71
72 #define MAX_ARGV_SIZE 256
73
74 #ifdef BUILD_DRM_COMPOSITOR
75
76 #include <xf86drm.h>
77
78 #else
79
80 static inline int
drmDropMaster(int drm_fd)81 drmDropMaster(int drm_fd)
82 {
83 return 0;
84 }
85
86 static inline int
drmSetMaster(int drm_fd)87 drmSetMaster(int drm_fd)
88 {
89 return 0;
90 }
91
92 #endif
93
94 /* major()/minor() */
95 #ifdef MAJOR_IN_MKDEV
96 # include <sys/mkdev.h>
97 #endif
98 #ifdef MAJOR_IN_SYSMACROS
99 # include <sys/sysmacros.h>
100 #endif
101
102 struct weston_launch {
103 struct pam_conv pc;
104 pam_handle_t *ph;
105 int tty;
106 int ttynr;
107 int sock[2];
108 int drm_fd;
109 int last_input_fd;
110 int kb_mode;
111 struct passwd *pw;
112
113 int signalfd;
114
115 pid_t child;
116 int verbose;
117 char *new_user;
118 };
119
120 union cmsg_data { unsigned char b[4]; int fd; };
121
122 static gid_t *
read_groups(int * ngroups)123 read_groups(int *ngroups)
124 {
125 int n;
126 gid_t *groups;
127
128 n = getgroups(0, NULL);
129
130 if (n < 0) {
131 fprintf(stderr, "Unable to retrieve groups: %s\n",
132 strerror(errno));
133 return NULL;
134 }
135
136 groups = malloc(n * sizeof(gid_t));
137 if (!groups)
138 return NULL;
139
140 if (getgroups(n, groups) < 0) {
141 fprintf(stderr, "Unable to retrieve groups: %s\n",
142 strerror(errno));
143 free(groups);
144 return NULL;
145 }
146
147 *ngroups = n;
148 return groups;
149 }
150
151 static bool
weston_launch_allowed(struct weston_launch * wl)152 weston_launch_allowed(struct weston_launch *wl)
153 {
154 struct group *gr;
155 gid_t *groups;
156 int ngroups;
157 #ifdef HAVE_SYSTEMD_LOGIN
158 char *session, *seat;
159 int err;
160 #endif
161
162 if (getuid() == 0)
163 return true;
164
165 gr = getgrnam("weston-launch");
166 if (gr) {
167 groups = read_groups(&ngroups);
168 if (groups && ngroups > 0) {
169 while (ngroups--) {
170 if (groups[ngroups] == gr->gr_gid) {
171 free(groups);
172 return true;
173 }
174 }
175 free(groups);
176 }
177 }
178
179 #ifdef HAVE_SYSTEMD_LOGIN
180 err = sd_pid_get_session(getpid(), &session);
181 if (err == 0 && session) {
182 if (sd_session_is_active(session) &&
183 sd_session_get_seat(session, &seat) == 0) {
184 free(seat);
185 free(session);
186 return true;
187 }
188 free(session);
189 }
190 #endif
191
192 return false;
193 }
194
195 static int
pam_conversation_fn(int msg_count,const struct pam_message ** messages,struct pam_response ** responses,void * user_data)196 pam_conversation_fn(int msg_count,
197 const struct pam_message **messages,
198 struct pam_response **responses,
199 void *user_data)
200 {
201 return PAM_SUCCESS;
202 }
203
204 static int
setup_pam(struct weston_launch * wl)205 setup_pam(struct weston_launch *wl)
206 {
207 int err;
208
209 wl->pc.conv = pam_conversation_fn;
210 wl->pc.appdata_ptr = wl;
211
212 err = pam_start("login", wl->pw->pw_name, &wl->pc, &wl->ph);
213 if (err != PAM_SUCCESS) {
214 fprintf(stderr, "failed to start pam transaction: %d: %s\n",
215 err, pam_strerror(wl->ph, err));
216 return -1;
217 }
218
219 err = pam_set_item(wl->ph, PAM_TTY, ttyname(wl->tty));
220 if (err != PAM_SUCCESS) {
221 fprintf(stderr, "failed to set PAM_TTY item: %d: %s\n",
222 err, pam_strerror(wl->ph, err));
223 return -1;
224 }
225
226 err = pam_open_session(wl->ph, 0);
227 if (err != PAM_SUCCESS) {
228 fprintf(stderr, "failed to open pam session: %d: %s\n",
229 err, pam_strerror(wl->ph, err));
230 return -1;
231 }
232
233 return 0;
234 }
235
236 static int
setup_launcher_socket(struct weston_launch * wl)237 setup_launcher_socket(struct weston_launch *wl)
238 {
239 if (socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, wl->sock) < 0) {
240 fprintf(stderr, "weston: socketpair failed: %s\n",
241 strerror(errno));
242 return -1;
243 }
244
245 if (fcntl(wl->sock[0], F_SETFD, FD_CLOEXEC) < 0) {
246 fprintf(stderr, "weston: fcntl failed: %s\n",
247 strerror(errno));
248 return -1;
249 }
250
251 return 0;
252 }
253
254 static int
setup_signals(struct weston_launch * wl)255 setup_signals(struct weston_launch *wl)
256 {
257 int ret;
258 sigset_t mask;
259 struct sigaction sa;
260
261 memset(&sa, 0, sizeof sa);
262 sa.sa_handler = SIG_DFL;
263 sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
264 ret = sigaction(SIGCHLD, &sa, NULL);
265 assert(ret == 0);
266
267 sa.sa_handler = SIG_IGN;
268 sa.sa_flags = 0;
269 sigaction(SIGHUP, &sa, NULL);
270
271 ret = sigemptyset(&mask);
272 assert(ret == 0);
273 sigaddset(&mask, SIGCHLD);
274 sigaddset(&mask, SIGINT);
275 sigaddset(&mask, SIGTERM);
276 sigaddset(&mask, SIGUSR1);
277 sigaddset(&mask, SIGUSR2);
278 ret = sigprocmask(SIG_BLOCK, &mask, NULL);
279 assert(ret == 0);
280
281 wl->signalfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
282 if (wl->signalfd < 0)
283 return -errno;
284
285 return 0;
286 }
287
288 static void
setenv_fd(const char * env,int fd)289 setenv_fd(const char *env, int fd)
290 {
291 char buf[32];
292
293 snprintf(buf, sizeof buf, "%d", fd);
294 setenv(env, buf, 1);
295 }
296
297 static int
open_tty_by_number(int ttynr)298 open_tty_by_number(int ttynr)
299 {
300 int ret;
301 char filename[16];
302
303 ret = snprintf(filename, sizeof filename, "/dev/tty%d", ttynr);
304 if (ret < 0)
305 return -1;
306
307 return open(filename, O_RDWR | O_NOCTTY);
308 }
309
310 static int
send_reply(struct weston_launch * wl,int reply)311 send_reply(struct weston_launch *wl, int reply)
312 {
313 int len;
314
315 do {
316 len = send(wl->sock[0], &reply, sizeof reply, 0);
317 } while (len < 0 && errno == EINTR);
318
319 return len;
320 }
321
322 static int
handle_open(struct weston_launch * wl,struct msghdr * msg,ssize_t len)323 handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
324 {
325 int fd = -1, ret = -1;
326 char control[CMSG_SPACE(sizeof(fd))];
327 struct cmsghdr *cmsg;
328 struct stat s;
329 struct msghdr nmsg;
330 struct iovec iov;
331 struct weston_launcher_open *message;
332 union cmsg_data *data;
333
334 message = msg->msg_iov->iov_base;
335 if ((size_t)len < sizeof(*message))
336 goto err0;
337
338 /* Ensure path is null-terminated */
339 ((char *) message)[len-1] = '\0';
340
341 fd = open(message->path, message->flags);
342 if (fd < 0) {
343 fprintf(stderr, "Error opening device %s: %s\n",
344 message->path, strerror(errno));
345 goto err0;
346 }
347
348 if (fstat(fd, &s) < 0) {
349 close(fd);
350 fd = -1;
351 fprintf(stderr, "Failed to stat %s\n", message->path);
352 goto err0;
353 }
354
355 if (major(s.st_rdev) != INPUT_MAJOR &&
356 major(s.st_rdev) != DRM_MAJOR) {
357 close(fd);
358 fd = -1;
359 fprintf(stderr, "Device %s is not an input or drm device\n",
360 message->path);
361 goto err0;
362 }
363
364 err0:
365 memset(&nmsg, 0, sizeof nmsg);
366 nmsg.msg_iov = &iov;
367 nmsg.msg_iovlen = 1;
368 if (fd != -1) {
369 nmsg.msg_control = control;
370 nmsg.msg_controllen = sizeof control;
371 cmsg = CMSG_FIRSTHDR(&nmsg);
372 cmsg->cmsg_level = SOL_SOCKET;
373 cmsg->cmsg_type = SCM_RIGHTS;
374 cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
375 data = (union cmsg_data *) CMSG_DATA(cmsg);
376 data->fd = fd;
377 nmsg.msg_controllen = cmsg->cmsg_len;
378 ret = 0;
379 }
380 iov.iov_base = &ret;
381 iov.iov_len = sizeof ret;
382
383 if (wl->verbose)
384 fprintf(stderr, "weston-launch: opened %s: ret: %d, fd: %d\n",
385 message->path, ret, fd);
386 do {
387 len = sendmsg(wl->sock[0], &nmsg, 0);
388 } while (len < 0 && errno == EINTR);
389
390 if (len < 0)
391 return -1;
392
393 if (fd != -1 && major(s.st_rdev) == DRM_MAJOR)
394 wl->drm_fd = fd;
395 if (fd != -1 && major(s.st_rdev) == INPUT_MAJOR &&
396 wl->last_input_fd < fd)
397 wl->last_input_fd = fd;
398
399 return 0;
400 }
401
402 static void
close_input_fds(struct weston_launch * wl)403 close_input_fds(struct weston_launch *wl)
404 {
405 struct stat s;
406 int fd;
407
408 for (fd = 3; fd <= wl->last_input_fd; fd++) {
409 if (fstat(fd, &s) == 0 && major(s.st_rdev) == INPUT_MAJOR) {
410 /* EVIOCREVOKE may fail if the kernel doesn't
411 * support it, but all we can do is ignore it. */
412 ioctl(fd, EVIOCREVOKE, 0);
413 close(fd);
414 }
415 }
416 }
417
418 static int
handle_socket_msg(struct weston_launch * wl)419 handle_socket_msg(struct weston_launch *wl)
420 {
421 char control[CMSG_SPACE(sizeof(int))];
422 char buf[BUFSIZ];
423 struct msghdr msg;
424 struct iovec iov;
425 int ret = -1;
426 ssize_t len;
427 struct weston_launcher_message *message;
428
429 memset(&msg, 0, sizeof(msg));
430 iov.iov_base = buf;
431 iov.iov_len = sizeof buf;
432 msg.msg_iov = &iov;
433 msg.msg_iovlen = 1;
434 msg.msg_control = control;
435 msg.msg_controllen = sizeof control;
436
437 do {
438 len = recvmsg(wl->sock[0], &msg, 0);
439 } while (len < 0 && errno == EINTR);
440
441 if (len < 1)
442 return -1;
443
444 message = (void *) buf;
445 switch (message->opcode) {
446 case WESTON_LAUNCHER_OPEN:
447 ret = handle_open(wl, &msg, len);
448 break;
449 case WESTON_LAUNCHER_DEACTIVATE_DONE:
450 close_input_fds(wl);
451 drmDropMaster(wl->drm_fd);
452 ioctl(wl->tty, VT_RELDISP, 1);
453 break;
454 }
455
456 return ret;
457 }
458
459 static void
quit(struct weston_launch * wl,int status)460 quit(struct weston_launch *wl, int status)
461 {
462 struct vt_mode mode = { 0 };
463 int err;
464 int oldtty;
465
466 close(wl->signalfd);
467 close(wl->sock[0]);
468
469 if (wl->new_user) {
470 err = pam_close_session(wl->ph, 0);
471 if (err)
472 fprintf(stderr, "pam_close_session failed: %d: %s\n",
473 err, pam_strerror(wl->ph, err));
474 pam_end(wl->ph, err);
475 }
476
477 /*
478 * Get a fresh handle to the tty as the previous one is in
479 * hang-up state since weston (the controlling process for
480 * the tty) exit at this point. Reopen before closing the
481 * file descriptor to avoid a potential race condition.
482 *
483 * A similar fix exists in logind, see:
484 * https://github.com/systemd/systemd/pull/990
485 */
486 oldtty = wl->tty;
487 wl->tty = open_tty_by_number(wl->ttynr);
488 close(oldtty);
489
490 if (ioctl(wl->tty, KDSKBMUTE, 0) &&
491 ioctl(wl->tty, KDSKBMODE, wl->kb_mode))
492 fprintf(stderr, "failed to restore keyboard mode: %s\n",
493 strerror(errno));
494
495 if (ioctl(wl->tty, KDSETMODE, KD_TEXT))
496 fprintf(stderr, "failed to set KD_TEXT mode on tty: %s\n",
497 strerror(errno));
498
499 /* We have to drop master before we switch the VT back in
500 * VT_AUTO, so we don't risk switching to a VT with another
501 * display server, that will then fail to set drm master. */
502 drmDropMaster(wl->drm_fd);
503
504 mode.mode = VT_AUTO;
505 if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
506 fprintf(stderr, "could not reset vt handling\n");
507
508 if (wl->tty != STDIN_FILENO)
509 close(wl->tty);
510
511 exit(status);
512 }
513
514 static int
handle_signal(struct weston_launch * wl)515 handle_signal(struct weston_launch *wl)
516 {
517 struct signalfd_siginfo sig;
518 int pid, status, ret;
519
520 if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) {
521 fprintf(stderr, "weston: reading signalfd failed: %s\n",
522 strerror(errno));
523 return -1;
524 }
525
526 switch (sig.ssi_signo) {
527 case SIGCHLD:
528 pid = waitpid(-1, &status, 0);
529 if (pid == wl->child) {
530 wl->child = 0;
531 if (WIFEXITED(status))
532 ret = WEXITSTATUS(status);
533 else if (WIFSIGNALED(status))
534 /*
535 * If weston dies because of signal N, we
536 * return 10+N. This is distinct from
537 * weston-launch dying because of a signal
538 * (128+N).
539 */
540 ret = 10 + WTERMSIG(status);
541 else
542 ret = 0;
543 quit(wl, ret);
544 }
545 break;
546 case SIGTERM:
547 case SIGINT:
548 if (!wl->child)
549 break;
550
551 if (wl->verbose)
552 fprintf(stderr, "weston-launch: sending %s to pid %d\n",
553 strsignal(sig.ssi_signo), wl->child);
554
555 kill(wl->child, sig.ssi_signo);
556 break;
557 case SIGUSR1:
558 send_reply(wl, WESTON_LAUNCHER_DEACTIVATE);
559 break;
560 case SIGUSR2:
561 ioctl(wl->tty, VT_RELDISP, VT_ACKACQ);
562 drmSetMaster(wl->drm_fd);
563 send_reply(wl, WESTON_LAUNCHER_ACTIVATE);
564 break;
565 default:
566 return -1;
567 }
568
569 return 0;
570 }
571
572 static int
setup_tty(struct weston_launch * wl,const char * tty)573 setup_tty(struct weston_launch *wl, const char *tty)
574 {
575 struct stat buf;
576 struct vt_mode mode = { 0 };
577 char *t;
578
579 if (!wl->new_user) {
580 wl->tty = STDIN_FILENO;
581 } else if (tty) {
582 t = ttyname(STDIN_FILENO);
583 if (t && strcmp(t, tty) == 0)
584 wl->tty = STDIN_FILENO;
585 else
586 wl->tty = open(tty, O_RDWR | O_NOCTTY);
587 } else {
588 int tty0 = open("/dev/tty0", O_WRONLY | O_CLOEXEC);
589
590 if (tty0 < 0) {
591 fprintf(stderr, "weston: could not open tty0: %s\n",
592 strerror(errno));
593 return -1;
594 }
595
596 if (ioctl(tty0, VT_OPENQRY, &wl->ttynr) < 0 || wl->ttynr == -1)
597 {
598 fprintf(stderr, "weston: failed to find non-opened console: %s\n",
599 strerror(errno));
600 return -1;
601 }
602
603 wl->tty = open_tty_by_number(wl->ttynr);
604 close(tty0);
605 }
606
607 if (wl->tty < 0) {
608 fprintf(stderr, "weston: failed to open tty: %s\n",
609 strerror(errno));
610 return -1;
611 }
612
613 if (fstat(wl->tty, &buf) == -1 ||
614 major(buf.st_rdev) != TTY_MAJOR || minor(buf.st_rdev) == 0) {
615 fprintf(stderr, "weston: weston-launch must be run from a virtual terminal\n");
616 return -1;
617 }
618
619 if (!wl->new_user || tty) {
620 if (fstat(wl->tty, &buf) < 0) {
621 fprintf(stderr, "weston: stat %s failed: %s\n", tty,
622 strerror(errno));
623 return -1;
624 }
625
626 if (major(buf.st_rdev) != TTY_MAJOR) {
627 fprintf(stderr,
628 "weston: invalid tty device: %s\n", tty);
629 return -1;
630 }
631
632 wl->ttynr = minor(buf.st_rdev);
633 }
634
635 if (ioctl(wl->tty, VT_ACTIVATE, wl->ttynr) < 0) {
636 fprintf(stderr,
637 "weston: failed to activate VT: %s\n",
638 strerror(errno));
639 return -1;
640 }
641
642 if (ioctl(wl->tty, VT_WAITACTIVE, wl->ttynr) < 0) {
643 fprintf(stderr,
644 "weston: failed to wait for VT to be active: %s\n",
645 strerror(errno));
646 return -1;
647 }
648
649 if (ioctl(wl->tty, KDGKBMODE, &wl->kb_mode)) {
650 fprintf(stderr,
651 "weston: failed to get current keyboard mode: %s\n",
652 strerror(errno));
653 return -1;
654 }
655
656 if (ioctl(wl->tty, KDSKBMUTE, 1) &&
657 ioctl(wl->tty, KDSKBMODE, K_OFF)) {
658 fprintf(stderr,
659 "weston: failed to set K_OFF keyboard mode: %s\n",
660 strerror(errno));
661 return -1;
662 }
663
664 if (ioctl(wl->tty, KDSETMODE, KD_GRAPHICS)) {
665 fprintf(stderr,
666 "weston: failed to set KD_GRAPHICS mode on tty: %s\n",
667 strerror(errno));
668 return -1;
669 }
670
671 mode.mode = VT_PROCESS;
672 mode.relsig = SIGUSR1;
673 mode.acqsig = SIGUSR2;
674 if (ioctl(wl->tty, VT_SETMODE, &mode) < 0) {
675 fprintf(stderr,
676 "weston: failed to take control of vt handling %s\n",
677 strerror(errno));
678 return -1;
679 }
680
681 return 0;
682 }
683
684 static int
setup_session(struct weston_launch * wl,char ** child_argv)685 setup_session(struct weston_launch *wl, char **child_argv)
686 {
687 char **env;
688 char *term;
689 int i;
690
691 if (wl->tty != STDIN_FILENO) {
692 if (setsid() < 0) {
693 fprintf(stderr, "weston: setsid failed %s\n",
694 strerror(errno));
695 exit(EXIT_FAILURE);
696 }
697 if (ioctl(wl->tty, TIOCSCTTY, 0) < 0) {
698 fprintf(stderr, "TIOCSCTTY failed - tty is in use %s\n",
699 strerror(errno));
700 exit(EXIT_FAILURE);
701 }
702 }
703
704 term = getenv("TERM");
705 clearenv();
706 if (term)
707 setenv("TERM", term, 1);
708 setenv("USER", wl->pw->pw_name, 1);
709 setenv("LOGNAME", wl->pw->pw_name, 1);
710 setenv("HOME", wl->pw->pw_dir, 1);
711 setenv("SHELL", wl->pw->pw_shell, 1);
712
713 env = pam_getenvlist(wl->ph);
714 if (env) {
715 for (i = 0; env[i]; ++i) {
716 if (putenv(env[i]) != 0)
717 fprintf(stderr, "putenv %s failed\n", env[i]);
718 }
719 free(env);
720 }
721
722 /*
723 * We open a new session, so it makes sense
724 * to run a new login shell
725 */
726 child_argv[0] = "/bin/sh";
727 child_argv[1] = "-l";
728 child_argv[2] = "-c";
729 child_argv[3] = "exec " BINDIR "/weston \"$@\"";
730 child_argv[4] = "weston";
731 return 5;
732 }
733
734 static void
drop_privileges(struct weston_launch * wl)735 drop_privileges(struct weston_launch *wl)
736 {
737 if (setgid(wl->pw->pw_gid) < 0 ||
738 #ifdef HAVE_INITGROUPS
739 initgroups(wl->pw->pw_name, wl->pw->pw_gid) < 0 ||
740 #endif
741 setuid(wl->pw->pw_uid) < 0) {
742 fprintf(stderr, "weston: dropping privileges failed %s\n",
743 strerror(errno));
744 exit(EXIT_FAILURE);
745 }
746 }
747
748 static void
launch_compositor(struct weston_launch * wl,int argc,char * argv[])749 launch_compositor(struct weston_launch *wl, int argc, char *argv[])
750 {
751 char *child_argv[MAX_ARGV_SIZE];
752 sigset_t mask;
753 int o, i;
754
755 if (wl->verbose)
756 printf("weston-launch: spawned weston with pid: %d\n", getpid());
757 if (wl->new_user) {
758 o = setup_session(wl, child_argv);
759 } else {
760 child_argv[0] = BINDIR "/weston";
761 o = 1;
762 }
763 for (i = 0; i < argc; ++i)
764 child_argv[o + i] = argv[i];
765 child_argv[o + i] = NULL;
766
767 if (geteuid() == 0)
768 drop_privileges(wl);
769
770 setenv_fd("WESTON_TTY_FD", wl->tty);
771 setenv_fd("WESTON_LAUNCHER_SOCK", wl->sock[1]);
772
773 unsetenv("DISPLAY");
774
775 /* Do not give our signal mask to the new process. */
776 sigemptyset(&mask);
777 sigaddset(&mask, SIGTERM);
778 sigaddset(&mask, SIGCHLD);
779 sigaddset(&mask, SIGINT);
780 sigprocmask(SIG_UNBLOCK, &mask, NULL);
781
782
783 execv(child_argv[0], child_argv);
784 fprintf(stderr, "weston: exec failed: %s\n", strerror(errno));
785 exit(EXIT_FAILURE);
786 }
787
788 static void
help(const char * name)789 help(const char *name)
790 {
791 fprintf(stderr, "Usage: %s [args...] [-- [weston args..]]\n", name);
792 fprintf(stderr, " -u, --user Start session as specified username,\n"
793 " e.g. -u joe, requires root.\n");
794 fprintf(stderr, " -t, --tty Start session on alternative tty,\n"
795 " e.g. -t /dev/tty4, requires -u option.\n");
796 fprintf(stderr, " -v, --verbose Be verbose\n");
797 fprintf(stderr, " -h, --help Display this help message\n");
798 }
799
800 int
main(int argc,char * argv[])801 main(int argc, char *argv[])
802 {
803 struct weston_launch wl;
804 int i, c;
805 char *tty = NULL;
806 struct option opts[] = {
807 { "user", required_argument, NULL, 'u' },
808 { "tty", required_argument, NULL, 't' },
809 { "verbose", no_argument, NULL, 'v' },
810 { "help", no_argument, NULL, 'h' },
811 { 0, 0, NULL, 0 }
812 };
813
814 memset(&wl, 0, sizeof wl);
815
816 while ((c = getopt_long(argc, argv, "u:t:vh", opts, &i)) != -1) {
817 switch (c) {
818 case 'u':
819 wl.new_user = optarg;
820 if (getuid() != 0) {
821 fprintf(stderr, "weston: Permission denied. -u allowed for root only\n");
822 exit(EXIT_FAILURE);
823 }
824 break;
825 case 't':
826 tty = optarg;
827 break;
828 case 'v':
829 wl.verbose = 1;
830 break;
831 case 'h':
832 help("weston-launch");
833 exit(EXIT_FAILURE);
834 default:
835 exit(EXIT_FAILURE);
836 }
837 }
838
839 if ((argc - optind) > (MAX_ARGV_SIZE - 6)) {
840 fprintf(stderr,
841 "weston: Too many arguments to pass to weston: %s\n",
842 strerror(E2BIG));
843 exit(EXIT_FAILURE);
844 }
845
846 if (tty && !wl.new_user) {
847 fprintf(stderr, "weston: -t/--tty option requires -u/--user option as well\n");
848 exit(EXIT_FAILURE);
849 }
850
851 if (wl.new_user)
852 wl.pw = getpwnam(wl.new_user);
853 else
854 wl.pw = getpwuid(getuid());
855 if (wl.pw == NULL) {
856 fprintf(stderr, "weston: failed to get username: %s\n",
857 strerror(errno));
858 exit(EXIT_FAILURE);
859 }
860
861 if (!weston_launch_allowed(&wl)) {
862 fprintf(stderr, "Permission denied. You should either:\n"
863 #ifdef HAVE_SYSTEMD_LOGIN
864 " - run from an active and local (systemd) session.\n"
865 #else
866 " - enable systemd session support for weston-launch.\n"
867 #endif
868 " - or add yourself to the 'weston-launch' group.\n");
869 exit(EXIT_FAILURE);
870 }
871
872 if (setup_tty(&wl, tty) < 0)
873 exit(EXIT_FAILURE);
874
875 if (wl.new_user && setup_pam(&wl) < 0)
876 exit(EXIT_FAILURE);
877
878 if (setup_launcher_socket(&wl) < 0)
879 exit(EXIT_FAILURE);
880
881 if (setup_signals(&wl) < 0)
882 exit(EXIT_FAILURE);
883
884 wl.child = fork();
885 if (wl.child == -1) {
886 fprintf(stderr, "weston: fork failed %s\n", strerror(errno));
887 exit(EXIT_FAILURE);
888 }
889
890 if (wl.child == 0)
891 launch_compositor(&wl, argc - optind, argv + optind);
892
893 close(wl.sock[1]);
894
895 while (1) {
896 struct pollfd fds[2];
897 int n;
898
899 fds[0].fd = wl.sock[0];
900 fds[0].events = POLLIN;
901 fds[1].fd = wl.signalfd;
902 fds[1].events = POLLIN;
903
904 n = poll(fds, 2, -1);
905 if (n < 0) {
906 fprintf(stderr, "poll failed: %s\n", strerror(errno));
907 return -1;
908 }
909 if (fds[0].revents & POLLIN)
910 handle_socket_msg(&wl);
911 if (fds[1].revents)
912 handle_signal(&wl);
913 }
914
915 return 0;
916 }
917