blob: eecb911a16893f6bd6fd024e5a2d3f4ae642641c [file] [log] [blame]
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001/*
2 * Copyright © 2012 Benjamin Franzke
3 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -07004 * 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:
Benjamin Franzkebfeda132012-01-30 14:04:04 +010011 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -070012 * 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.
Benjamin Franzkebfeda132012-01-30 14:04:04 +010024 */
25
Benjamin Franzkebfeda132012-01-30 14:04:04 +010026#include "config.h"
27
Derek Foreman280e7dd2014-10-03 13:13:42 -050028#include <stdbool.h>
Benjamin Franzkebfeda132012-01-30 14:04:04 +010029#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <assert.h>
Kristian Høgsbergf2807702013-07-23 11:43:03 -070033#include <poll.h>
Benjamin Franzkebfeda132012-01-30 14:04:04 +010034#include <errno.h>
35
36#include <error.h>
37#include <getopt.h>
38
39#include <sys/types.h>
40#include <sys/ioctl.h>
41#include <sys/stat.h>
42#include <sys/wait.h>
43#include <sys/socket.h>
Benjamin Franzkebfeda132012-01-30 14:04:04 +010044#include <sys/signalfd.h>
Daniel Stone5a313c22017-03-14 17:25:30 +000045#include <sys/sysmacros.h>
Benjamin Franzkebfeda132012-01-30 14:04:04 +010046#include <signal.h>
47#include <unistd.h>
48#include <fcntl.h>
49
Benjamin Franzkebfeda132012-01-30 14:04:04 +010050#include <linux/vt.h>
51#include <linux/major.h>
Kristian Høgsberg81b49632013-09-17 22:43:22 -070052#include <linux/kd.h>
Benjamin Franzkebfeda132012-01-30 14:04:04 +010053
54#include <pwd.h>
55#include <grp.h>
56#include <security/pam_appl.h>
57
Benjamin Franzkebfeda132012-01-30 14:04:04 +010058#ifdef HAVE_SYSTEMD_LOGIN
59#include <systemd/sd-login.h>
60#endif
61
62#include "weston-launch.h"
63
Kristian Høgsberg1ff51092013-09-17 14:03:42 -070064#define DRM_MAJOR 226
65
Kristian Høgsberg3f495872013-09-18 23:00:17 -070066#ifndef KDSKBMUTE
67#define KDSKBMUTE 0x4B51
68#endif
69
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -070070#ifndef EVIOCREVOKE
71#define EVIOCREVOKE _IOW('E', 0x91, int)
72#endif
73
Quentin Glidicff323092013-05-17 16:20:37 +020074#define MAX_ARGV_SIZE 256
75
Kristian Høgsbergd2c9d8a2013-11-24 14:37:07 -080076#ifdef HAVE_LIBDRM
77
78#include <xf86drm.h>
79
80#else
81
82static inline int
83drmDropMaster(int drm_fd)
84{
85 return 0;
86}
87
88static inline int
89drmSetMaster(int drm_fd)
90{
91 return 0;
92}
93
94#endif
95
Benjamin Franzkebfeda132012-01-30 14:04:04 +010096struct weston_launch {
97 struct pam_conv pc;
98 pam_handle_t *ph;
99 int tty;
100 int ttynr;
101 int sock[2];
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700102 int drm_fd;
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -0700103 int last_input_fd;
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700104 int kb_mode;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100105 struct passwd *pw;
106
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100107 int signalfd;
108
109 pid_t child;
110 int verbose;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700111 char *new_user;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100112};
113
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400114union cmsg_data { unsigned char b[4]; int fd; };
115
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100116static gid_t *
117read_groups(void)
118{
119 int n;
120 gid_t *groups;
Murray Calavera883ac022015-06-06 13:02:22 +0000121
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100122 n = getgroups(0, NULL);
Rob Bradford40be7b42012-12-05 18:47:11 +0000123
124 if (n < 0) {
125 fprintf(stderr, "Unable to retrieve groups: %m\n");
126 return NULL;
127 }
128
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100129 groups = malloc(n * sizeof(gid_t));
130 if (!groups)
131 return NULL;
132
133 if (getgroups(n, groups) < 0) {
Rob Bradford40be7b42012-12-05 18:47:11 +0000134 fprintf(stderr, "Unable to retrieve groups: %m\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100135 free(groups);
136 return NULL;
137 }
138 return groups;
139}
140
Derek Foreman280e7dd2014-10-03 13:13:42 -0500141static bool
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100142weston_launch_allowed(struct weston_launch *wl)
143{
144 struct group *gr;
145 gid_t *groups;
146 int i;
147#ifdef HAVE_SYSTEMD_LOGIN
148 char *session, *seat;
149 int err;
150#endif
151
152 if (getuid() == 0)
Derek Foreman280e7dd2014-10-03 13:13:42 -0500153 return true;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100154
155 gr = getgrnam("weston-launch");
156 if (gr) {
157 groups = read_groups();
158 if (groups) {
159 for (i = 0; groups[i]; ++i) {
160 if (groups[i] == gr->gr_gid) {
161 free(groups);
Derek Foreman280e7dd2014-10-03 13:13:42 -0500162 return true;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100163 }
164 }
165 free(groups);
166 }
167 }
168
169#ifdef HAVE_SYSTEMD_LOGIN
170 err = sd_pid_get_session(getpid(), &session);
171 if (err == 0 && session) {
172 if (sd_session_is_active(session) &&
173 sd_session_get_seat(session, &seat) == 0) {
174 free(seat);
175 free(session);
Derek Foreman280e7dd2014-10-03 13:13:42 -0500176 return true;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100177 }
178 free(session);
179 }
180#endif
Murray Calavera883ac022015-06-06 13:02:22 +0000181
Derek Foreman280e7dd2014-10-03 13:13:42 -0500182 return false;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100183}
184
185static int
186pam_conversation_fn(int msg_count,
187 const struct pam_message **messages,
188 struct pam_response **responses,
189 void *user_data)
190{
191 return PAM_SUCCESS;
192}
193
194static int
195setup_pam(struct weston_launch *wl)
196{
197 int err;
198
199 wl->pc.conv = pam_conversation_fn;
200 wl->pc.appdata_ptr = wl;
201
202 err = pam_start("login", wl->pw->pw_name, &wl->pc, &wl->ph);
John Kåre Alsaker5b90d8f2012-10-12 12:25:05 +0200203 if (err != PAM_SUCCESS) {
204 fprintf(stderr, "failed to start pam transaction: %d: %s\n",
205 err, pam_strerror(wl->ph, err));
206 return -1;
207 }
208
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100209 err = pam_set_item(wl->ph, PAM_TTY, ttyname(wl->tty));
210 if (err != PAM_SUCCESS) {
211 fprintf(stderr, "failed to set PAM_TTY item: %d: %s\n",
212 err, pam_strerror(wl->ph, err));
213 return -1;
214 }
215
216 err = pam_open_session(wl->ph, 0);
217 if (err != PAM_SUCCESS) {
218 fprintf(stderr, "failed to open pam session: %d: %s\n",
219 err, pam_strerror(wl->ph, err));
220 return -1;
221 }
222
223 return 0;
224}
225
226static int
227setup_launcher_socket(struct weston_launch *wl)
228{
Kristian Høgsbergbf3c3742013-09-18 11:01:48 -0700229 if (socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, wl->sock) < 0)
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100230 error(1, errno, "socketpair failed");
Murray Calavera883ac022015-06-06 13:02:22 +0000231
Kristian Høgsbergf45b1e82013-09-18 11:00:56 -0700232 if (fcntl(wl->sock[0], F_SETFD, FD_CLOEXEC) < 0)
233 error(1, errno, "fcntl failed");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100234
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100235 return 0;
236}
237
238static int
239setup_signals(struct weston_launch *wl)
240{
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100241 int ret;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100242 sigset_t mask;
243 struct sigaction sa;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100244
245 memset(&sa, 0, sizeof sa);
246 sa.sa_handler = SIG_DFL;
247 sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100248 ret = sigaction(SIGCHLD, &sa, NULL);
249 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100250
Kristian Høgsberg18684d42013-07-22 11:59:18 -0700251 sa.sa_handler = SIG_IGN;
252 sa.sa_flags = 0;
253 sigaction(SIGHUP, &sa, NULL);
254
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100255 ret = sigemptyset(&mask);
256 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100257 sigaddset(&mask, SIGCHLD);
258 sigaddset(&mask, SIGINT);
259 sigaddset(&mask, SIGTERM);
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700260 sigaddset(&mask, SIGUSR1);
261 sigaddset(&mask, SIGUSR2);
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100262 ret = sigprocmask(SIG_BLOCK, &mask, NULL);
263 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100264
265 wl->signalfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
266 if (wl->signalfd < 0)
267 return -errno;
268
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100269 return 0;
270}
271
272static void
273setenv_fd(const char *env, int fd)
274{
275 char buf[32];
276
277 snprintf(buf, sizeof buf, "%d", fd);
278 setenv(env, buf, 1);
279}
280
281static int
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700282send_reply(struct weston_launch *wl, int reply)
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100283{
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700284 int len;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100285
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100286 do {
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700287 len = send(wl->sock[0], &reply, sizeof reply, 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100288 } while (len < 0 && errno == EINTR);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100289
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700290 return len;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100291}
292
293static int
294handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
295{
296 int fd = -1, ret = -1;
297 char control[CMSG_SPACE(sizeof(fd))];
298 struct cmsghdr *cmsg;
299 struct stat s;
300 struct msghdr nmsg;
301 struct iovec iov;
302 struct weston_launcher_open *message;
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400303 union cmsg_data *data;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100304
305 message = msg->msg_iov->iov_base;
306 if ((size_t)len < sizeof(*message))
307 goto err0;
308
309 /* Ensure path is null-terminated */
310 ((char *) message)[len-1] = '\0';
311
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100312 fd = open(message->path, message->flags);
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100313 if (fd < 0) {
314 fprintf(stderr, "Error opening device %s: %m\n",
315 message->path);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100316 goto err0;
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100317 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100318
Kristian Høgsberg6a7c8492013-09-18 22:14:09 -0700319 if (fstat(fd, &s) < 0) {
320 close(fd);
321 fd = -1;
322 fprintf(stderr, "Failed to stat %s\n", message->path);
323 goto err0;
324 }
325
Kristian Høgsberg1ff51092013-09-17 14:03:42 -0700326 if (major(s.st_rdev) != INPUT_MAJOR &&
327 major(s.st_rdev) != DRM_MAJOR) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100328 close(fd);
329 fd = -1;
Kristian Høgsberg1ff51092013-09-17 14:03:42 -0700330 fprintf(stderr, "Device %s is not an input or drm device\n",
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100331 message->path);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100332 goto err0;
333 }
334
335err0:
336 memset(&nmsg, 0, sizeof nmsg);
337 nmsg.msg_iov = &iov;
338 nmsg.msg_iovlen = 1;
339 if (fd != -1) {
340 nmsg.msg_control = control;
341 nmsg.msg_controllen = sizeof control;
342 cmsg = CMSG_FIRSTHDR(&nmsg);
343 cmsg->cmsg_level = SOL_SOCKET;
344 cmsg->cmsg_type = SCM_RIGHTS;
345 cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400346 data = (union cmsg_data *) CMSG_DATA(cmsg);
347 data->fd = fd;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100348 nmsg.msg_controllen = cmsg->cmsg_len;
349 ret = 0;
350 }
351 iov.iov_base = &ret;
352 iov.iov_len = sizeof ret;
353
354 if (wl->verbose)
355 fprintf(stderr, "weston-launch: opened %s: ret: %d, fd: %d\n",
356 message->path, ret, fd);
357 do {
358 len = sendmsg(wl->sock[0], &nmsg, 0);
359 } while (len < 0 && errno == EINTR);
360
361 if (len < 0)
362 return -1;
363
Kristian Høgsbergaf393dc2013-10-09 11:25:14 -0700364 if (fd != -1 && major(s.st_rdev) == DRM_MAJOR)
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700365 wl->drm_fd = fd;
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -0700366 if (fd != -1 && major(s.st_rdev) == INPUT_MAJOR &&
367 wl->last_input_fd < fd)
368 wl->last_input_fd = fd;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700369
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100370 return 0;
371}
372
373static int
374handle_socket_msg(struct weston_launch *wl)
375{
376 char control[CMSG_SPACE(sizeof(int))];
377 char buf[BUFSIZ];
378 struct msghdr msg;
379 struct iovec iov;
380 int ret = -1;
381 ssize_t len;
382 struct weston_launcher_message *message;
383
384 memset(&msg, 0, sizeof(msg));
385 iov.iov_base = buf;
386 iov.iov_len = sizeof buf;
387 msg.msg_iov = &iov;
388 msg.msg_iovlen = 1;
389 msg.msg_control = control;
390 msg.msg_controllen = sizeof control;
391
392 do {
393 len = recvmsg(wl->sock[0], &msg, 0);
394 } while (len < 0 && errno == EINTR);
395
396 if (len < 1)
397 return -1;
398
399 message = (void *) buf;
400 switch (message->opcode) {
401 case WESTON_LAUNCHER_OPEN:
402 ret = handle_open(wl, &msg, len);
403 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100404 }
405
406 return ret;
407}
408
409static void
410quit(struct weston_launch *wl, int status)
411{
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700412 struct vt_mode mode = { 0 };
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100413 int err;
414
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100415 close(wl->signalfd);
416 close(wl->sock[0]);
417
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700418 if (wl->new_user) {
419 err = pam_close_session(wl->ph, 0);
420 if (err)
421 fprintf(stderr, "pam_close_session failed: %d: %s\n",
422 err, pam_strerror(wl->ph, err));
423 pam_end(wl->ph, err);
424 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100425
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700426 if (ioctl(wl->tty, KDSKBMUTE, 0) &&
427 ioctl(wl->tty, KDSKBMODE, wl->kb_mode))
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700428 fprintf(stderr, "failed to restore keyboard mode: %m\n");
429
430 if (ioctl(wl->tty, KDSETMODE, KD_TEXT))
431 fprintf(stderr, "failed to set KD_TEXT mode on tty: %m\n");
432
Kristian Høgsberga28ba552013-10-30 16:27:16 -0700433 /* We have to drop master before we switch the VT back in
434 * VT_AUTO, so we don't risk switching to a VT with another
435 * display server, that will then fail to set drm master. */
436 drmDropMaster(wl->drm_fd);
437
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700438 mode.mode = VT_AUTO;
439 if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
440 fprintf(stderr, "could not reset vt handling\n");
441
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100442 exit(status);
443}
444
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -0700445static void
446close_input_fds(struct weston_launch *wl)
447{
448 struct stat s;
449 int fd;
450
451 for (fd = 3; fd <= wl->last_input_fd; fd++) {
452 if (fstat(fd, &s) == 0 && major(s.st_rdev) == INPUT_MAJOR) {
453 /* EVIOCREVOKE may fail if the kernel doesn't
454 * support it, but all we can do is ignore it. */
455 ioctl(fd, EVIOCREVOKE, 0);
456 close(fd);
457 }
458 }
459}
460
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100461static int
462handle_signal(struct weston_launch *wl)
463{
464 struct signalfd_siginfo sig;
Philipp Brüschweiler7a3ec742013-03-10 15:14:01 +0100465 int pid, status, ret;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100466
467 if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) {
468 error(0, errno, "reading signalfd failed");
469 return -1;
470 }
471
472 switch (sig.ssi_signo) {
473 case SIGCHLD:
474 pid = waitpid(-1, &status, 0);
475 if (pid == wl->child) {
476 wl->child = 0;
Philipp Brüschweiler7a3ec742013-03-10 15:14:01 +0100477 if (WIFEXITED(status))
478 ret = WEXITSTATUS(status);
479 else if (WIFSIGNALED(status))
480 /*
481 * If weston dies because of signal N, we
482 * return 10+N. This is distinct from
483 * weston-launch dying because of a signal
484 * (128+N).
485 */
486 ret = 10 + WTERMSIG(status);
487 else
488 ret = 0;
489 quit(wl, ret);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100490 }
491 break;
492 case SIGTERM:
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100493 case SIGINT:
494 if (wl->child)
Kristian Høgsberg1a81abb2013-06-17 15:23:20 -0400495 kill(wl->child, sig.ssi_signo);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100496 break;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700497 case SIGUSR1:
498 send_reply(wl, WESTON_LAUNCHER_DEACTIVATE);
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -0700499 close_input_fds(wl);
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700500 drmDropMaster(wl->drm_fd);
501 ioctl(wl->tty, VT_RELDISP, 1);
502 break;
503 case SIGUSR2:
504 ioctl(wl->tty, VT_RELDISP, VT_ACKACQ);
505 drmSetMaster(wl->drm_fd);
506 send_reply(wl, WESTON_LAUNCHER_ACTIVATE);
507 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100508 default:
509 return -1;
510 }
511
512 return 0;
513}
514
515static int
516setup_tty(struct weston_launch *wl, const char *tty)
517{
518 struct stat buf;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700519 struct vt_mode mode = { 0 };
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100520 char *t;
521
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700522 if (!wl->new_user) {
523 wl->tty = STDIN_FILENO;
524 } else if (tty) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100525 t = ttyname(STDIN_FILENO);
526 if (t && strcmp(t, tty) == 0)
527 wl->tty = STDIN_FILENO;
528 else
529 wl->tty = open(tty, O_RDWR | O_NOCTTY);
530 } else {
531 int tty0 = open("/dev/tty0", O_WRONLY | O_CLOEXEC);
532 char filename[16];
533
534 if (tty0 < 0)
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300535 error(1, errno, "could not open tty0");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100536
537 if (ioctl(tty0, VT_OPENQRY, &wl->ttynr) < 0 || wl->ttynr == -1)
Murray Calavera883ac022015-06-06 13:02:22 +0000538 error(1, errno, "failed to find non-opened console");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100539
540 snprintf(filename, sizeof filename, "/dev/tty%d", wl->ttynr);
541 wl->tty = open(filename, O_RDWR | O_NOCTTY);
542 close(tty0);
543 }
544
545 if (wl->tty < 0)
546 error(1, errno, "failed to open tty");
547
Kristian Høgsberge05f2282013-10-02 13:06:02 -0700548 if (fstat(wl->tty, &buf) == -1 ||
549 major(buf.st_rdev) != TTY_MAJOR || minor(buf.st_rdev) == 0)
550 error(1, 0, "weston-launch must be run from a virtual terminal");
551
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100552 if (tty) {
553 if (fstat(wl->tty, &buf) < 0)
554 error(1, errno, "stat %s failed", tty);
555
556 if (major(buf.st_rdev) != TTY_MAJOR)
557 error(1, 0, "invalid tty device: %s", tty);
558
559 wl->ttynr = minor(buf.st_rdev);
560 }
561
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700562 if (ioctl(wl->tty, KDGKBMODE, &wl->kb_mode))
563 error(1, errno, "failed to get current keyboard mode: %m\n");
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700564
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700565 if (ioctl(wl->tty, KDSKBMUTE, 1) &&
566 ioctl(wl->tty, KDSKBMODE, K_OFF))
567 error(1, errno, "failed to set K_OFF keyboard mode: %m\n");
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700568
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700569 if (ioctl(wl->tty, KDSETMODE, KD_GRAPHICS))
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700570 error(1, errno, "failed to set KD_GRAPHICS mode on tty: %m\n");
571
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700572 mode.mode = VT_PROCESS;
573 mode.relsig = SIGUSR1;
574 mode.acqsig = SIGUSR2;
575 if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
576 error(1, errno, "failed to take control of vt handling\n");
577
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100578 return 0;
579}
580
Quentin Glidic056889a2016-05-29 13:39:26 +0200581static int
582setup_session(struct weston_launch *wl, char **child_argv)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700583{
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700584 char **env;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700585 char *term;
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700586 int i;
587
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700588 if (wl->tty != STDIN_FILENO) {
589 if (setsid() < 0)
590 error(1, errno, "setsid failed");
591 if (ioctl(wl->tty, TIOCSCTTY, 0) < 0)
592 error(1, errno, "TIOCSCTTY failed - tty is in use");
593 }
594
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700595 term = getenv("TERM");
596 clearenv();
Rob Bradford7ac9f732013-08-09 11:30:38 +0100597 if (term)
598 setenv("TERM", term, 1);
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700599 setenv("USER", wl->pw->pw_name, 1);
600 setenv("LOGNAME", wl->pw->pw_name, 1);
601 setenv("HOME", wl->pw->pw_dir, 1);
602 setenv("SHELL", wl->pw->pw_shell, 1);
603
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700604 env = pam_getenvlist(wl->ph);
605 if (env) {
606 for (i = 0; env[i]; ++i) {
Dawid Gajownikf3c83362015-08-09 12:50:40 -0300607 if (putenv(env[i]) != 0)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700608 error(0, 0, "putenv %s failed", env[i]);
609 }
610 free(env);
611 }
Quentin Glidic056889a2016-05-29 13:39:26 +0200612
613 /*
614 * We open a new session, so it makes sense
615 * to run a new login shell
616 */
617 child_argv[0] = "/bin/sh";
618 child_argv[1] = "-l";
619 child_argv[2] = "-c";
620 child_argv[3] = BINDIR "/weston \"$@\"";
621 child_argv[4] = "weston";
622 return 5;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700623}
624
625static void
Peter Hutterer34be0602013-08-06 12:10:09 +1000626drop_privileges(struct weston_launch *wl)
627{
628 if (setgid(wl->pw->pw_gid) < 0 ||
629#ifdef HAVE_INITGROUPS
630 initgroups(wl->pw->pw_name, wl->pw->pw_gid) < 0 ||
631#endif
632 setuid(wl->pw->pw_uid) < 0)
633 error(1, errno, "dropping privileges failed");
634}
635
636static void
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700637launch_compositor(struct weston_launch *wl, int argc, char *argv[])
638{
639 char *child_argv[MAX_ARGV_SIZE];
Eduardo Limad0357bb2013-07-30 10:43:41 -0700640 sigset_t mask;
Quentin Glidic056889a2016-05-29 13:39:26 +0200641 int o, i;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700642
643 if (wl->verbose)
644 printf("weston-launch: spawned weston with pid: %d\n", getpid());
Quentin Glidic056889a2016-05-29 13:39:26 +0200645 if (wl->new_user) {
646 o = setup_session(wl, child_argv);
647 } else {
648 child_argv[0] = BINDIR "/weston";
649 o = 1;
650 }
651 for (i = 0; i < argc; ++i)
652 child_argv[o + i] = argv[i];
653 child_argv[o + i] = NULL;
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700654
Tomeu Vizosod7865b22013-10-01 12:20:29 +0200655 if (geteuid() == 0)
656 drop_privileges(wl);
Peter Hutterer34be0602013-08-06 12:10:09 +1000657
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700658 setenv_fd("WESTON_TTY_FD", wl->tty);
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700659 setenv_fd("WESTON_LAUNCHER_SOCK", wl->sock[1]);
660
661 unsetenv("DISPLAY");
662
Kristian Høgsberg73c60ab2013-07-30 09:45:04 -0700663 /* Do not give our signal mask to the new process. */
664 sigemptyset(&mask);
665 sigaddset(&mask, SIGTERM);
666 sigaddset(&mask, SIGCHLD);
667 sigaddset(&mask, SIGINT);
668 sigprocmask(SIG_UNBLOCK, &mask, NULL);
669
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700670
671 execv(child_argv[0], child_argv);
672 error(1, errno, "exec failed");
673}
674
675static void
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100676help(const char *name)
677{
678 fprintf(stderr, "Usage: %s [args...] [-- [weston args..]]\n", name);
679 fprintf(stderr, " -u, --user Start session as specified username\n");
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300680 fprintf(stderr, " -t, --tty Start session on alternative tty\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100681 fprintf(stderr, " -v, --verbose Be verbose\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100682 fprintf(stderr, " -h, --help Display this help message\n");
683}
684
685int
686main(int argc, char *argv[])
687{
688 struct weston_launch wl;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100689 int i, c;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700690 char *tty = NULL;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100691 struct option opts[] = {
692 { "user", required_argument, NULL, 'u' },
693 { "tty", required_argument, NULL, 't' },
694 { "verbose", no_argument, NULL, 'v' },
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100695 { "help", no_argument, NULL, 'h' },
696 { 0, 0, NULL, 0 }
Murray Calavera883ac022015-06-06 13:02:22 +0000697 };
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100698
699 memset(&wl, 0, sizeof wl);
700
Kristian Høgsbergab499942013-07-19 21:26:24 -0700701 while ((c = getopt_long(argc, argv, "u:t::vh", opts, &i)) != -1) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100702 switch (c) {
703 case 'u':
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700704 wl.new_user = optarg;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100705 if (getuid() != 0)
706 error(1, 0, "Permission denied. -u allowed for root only");
707 break;
708 case 't':
709 tty = optarg;
710 break;
711 case 'v':
712 wl.verbose = 1;
713 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100714 case 'h':
Scott Moreaucc9acfc2013-01-21 23:40:59 -0700715 help("weston-launch");
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530716 exit(EXIT_FAILURE);
Tom Hochsteine57056f2016-05-07 08:57:40 -0300717 default:
718 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100719 }
720 }
721
Ander Conselvan de Oliveira9bdfc482013-05-22 22:55:33 +0300722 if ((argc - optind) > (MAX_ARGV_SIZE - 6))
Quentin Glidicff323092013-05-17 16:20:37 +0200723 error(1, E2BIG, "Too many arguments to pass to weston");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100724
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700725 if (wl.new_user)
726 wl.pw = getpwnam(wl.new_user);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100727 else
728 wl.pw = getpwuid(getuid());
729 if (wl.pw == NULL)
730 error(1, errno, "failed to get username");
731
732 if (!weston_launch_allowed(&wl))
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300733 error(1, 0, "Permission denied. You should either:\n"
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100734#ifdef HAVE_SYSTEMD_LOGIN
735 " - run from an active and local (systemd) session.\n"
736#else
737 " - enable systemd session support for weston-launch.\n"
738#endif
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300739 " - or add yourself to the 'weston-launch' group.");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100740
741 if (setup_tty(&wl, tty) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530742 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100743
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700744 if (wl.new_user && setup_pam(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530745 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100746
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100747 if (setup_launcher_socket(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530748 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100749
750 if (setup_signals(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530751 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100752
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700753 wl.child = fork();
Bryce Harrington430aee12015-06-19 15:47:40 -0700754 if (wl.child == -1)
755 error(EXIT_FAILURE, errno, "fork failed");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100756
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700757 if (wl.child == 0)
758 launch_compositor(&wl, argc - optind, argv + optind);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100759
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700760 close(wl.sock[1]);
761 if (wl.tty != STDIN_FILENO)
762 close(wl.tty);
Quentin Glidic735302e2013-06-19 15:27:11 +0200763
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700764 while (1) {
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700765 struct pollfd fds[2];
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700766 int n;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100767
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700768 fds[0].fd = wl.sock[0];
769 fds[0].events = POLLIN;
770 fds[1].fd = wl.signalfd;
771 fds[1].events = POLLIN;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100772
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700773 n = poll(fds, 2, -1);
774 if (n < 0)
775 error(0, errno, "poll failed");
776 if (fds[0].revents & POLLIN)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700777 handle_socket_msg(&wl);
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700778 if (fds[1].revents)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700779 handle_signal(&wl);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100780 }
781
782 return 0;
783}