blob: 9e5c942974da2420c92eaddb50d0a3ffd25a9d83 [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
Benjamin Franzkebfeda132012-01-30 14:04:04 +010036#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>
Benjamin Franzkebfeda132012-01-30 14:04:04 +010043#include <sys/signalfd.h>
44#include <signal.h>
45#include <unistd.h>
46#include <fcntl.h>
47
Benjamin Franzkebfeda132012-01-30 14:04:04 +010048#include <linux/vt.h>
49#include <linux/major.h>
Kristian Høgsberg81b49632013-09-17 22:43:22 -070050#include <linux/kd.h>
Benjamin Franzkebfeda132012-01-30 14:04:04 +010051
52#include <pwd.h>
53#include <grp.h>
54#include <security/pam_appl.h>
55
Benjamin Franzkebfeda132012-01-30 14:04:04 +010056#ifdef HAVE_SYSTEMD_LOGIN
57#include <systemd/sd-login.h>
58#endif
59
60#include "weston-launch.h"
61
Kristian Høgsberg1ff51092013-09-17 14:03:42 -070062#define DRM_MAJOR 226
63
Kristian Høgsberg3f495872013-09-18 23:00:17 -070064#ifndef KDSKBMUTE
65#define KDSKBMUTE 0x4B51
66#endif
67
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -070068#ifndef EVIOCREVOKE
69#define EVIOCREVOKE _IOW('E', 0x91, int)
70#endif
71
Quentin Glidicff323092013-05-17 16:20:37 +020072#define MAX_ARGV_SIZE 256
73
Pekka Paalanen2667e9e2017-04-06 13:18:59 +030074#ifdef BUILD_DRM_COMPOSITOR
Kristian Høgsbergd2c9d8a2013-11-24 14:37:07 -080075
76#include <xf86drm.h>
77
78#else
79
80static inline int
81drmDropMaster(int drm_fd)
82{
83 return 0;
84}
85
86static inline int
87drmSetMaster(int drm_fd)
88{
89 return 0;
90}
91
92#endif
93
Sergei Trofimovich43c5a652017-05-31 22:17:50 +010094/* 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
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100102struct weston_launch {
103 struct pam_conv pc;
104 pam_handle_t *ph;
105 int tty;
106 int ttynr;
107 int sock[2];
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700108 int drm_fd;
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -0700109 int last_input_fd;
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700110 int kb_mode;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100111 struct passwd *pw;
112
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100113 int signalfd;
114
115 pid_t child;
116 int verbose;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700117 char *new_user;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100118};
119
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400120union cmsg_data { unsigned char b[4]; int fd; };
121
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100122static gid_t *
Peter Hutterer84bc4032018-06-11 09:57:04 +1000123read_groups(int *ngroups)
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100124{
125 int n;
126 gid_t *groups;
Murray Calavera883ac022015-06-06 13:02:22 +0000127
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100128 n = getgroups(0, NULL);
Rob Bradford40be7b42012-12-05 18:47:11 +0000129
130 if (n < 0) {
131 fprintf(stderr, "Unable to retrieve groups: %m\n");
132 return NULL;
133 }
134
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100135 groups = malloc(n * sizeof(gid_t));
136 if (!groups)
137 return NULL;
138
139 if (getgroups(n, groups) < 0) {
Rob Bradford40be7b42012-12-05 18:47:11 +0000140 fprintf(stderr, "Unable to retrieve groups: %m\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100141 free(groups);
142 return NULL;
143 }
Peter Hutterer84bc4032018-06-11 09:57:04 +1000144
145 *ngroups = n;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100146 return groups;
147}
148
Derek Foreman280e7dd2014-10-03 13:13:42 -0500149static bool
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100150weston_launch_allowed(struct weston_launch *wl)
151{
152 struct group *gr;
153 gid_t *groups;
Peter Hutterer84bc4032018-06-11 09:57:04 +1000154 int ngroups;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100155#ifdef HAVE_SYSTEMD_LOGIN
156 char *session, *seat;
157 int err;
158#endif
159
160 if (getuid() == 0)
Derek Foreman280e7dd2014-10-03 13:13:42 -0500161 return true;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100162
163 gr = getgrnam("weston-launch");
164 if (gr) {
Peter Hutterer84bc4032018-06-11 09:57:04 +1000165 groups = read_groups(&ngroups);
166 if (groups && ngroups > 0) {
167 while (ngroups--) {
168 if (groups[ngroups] == gr->gr_gid) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100169 free(groups);
Derek Foreman280e7dd2014-10-03 13:13:42 -0500170 return true;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100171 }
172 }
173 free(groups);
174 }
175 }
176
177#ifdef HAVE_SYSTEMD_LOGIN
178 err = sd_pid_get_session(getpid(), &session);
179 if (err == 0 && session) {
180 if (sd_session_is_active(session) &&
181 sd_session_get_seat(session, &seat) == 0) {
182 free(seat);
183 free(session);
Derek Foreman280e7dd2014-10-03 13:13:42 -0500184 return true;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100185 }
186 free(session);
187 }
188#endif
Murray Calavera883ac022015-06-06 13:02:22 +0000189
Derek Foreman280e7dd2014-10-03 13:13:42 -0500190 return false;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100191}
192
193static int
194pam_conversation_fn(int msg_count,
195 const struct pam_message **messages,
196 struct pam_response **responses,
197 void *user_data)
198{
199 return PAM_SUCCESS;
200}
201
202static int
203setup_pam(struct weston_launch *wl)
204{
205 int err;
206
207 wl->pc.conv = pam_conversation_fn;
208 wl->pc.appdata_ptr = wl;
209
210 err = pam_start("login", wl->pw->pw_name, &wl->pc, &wl->ph);
John Kåre Alsaker5b90d8f2012-10-12 12:25:05 +0200211 if (err != PAM_SUCCESS) {
212 fprintf(stderr, "failed to start pam transaction: %d: %s\n",
213 err, pam_strerror(wl->ph, err));
214 return -1;
215 }
216
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100217 err = pam_set_item(wl->ph, PAM_TTY, ttyname(wl->tty));
218 if (err != PAM_SUCCESS) {
219 fprintf(stderr, "failed to set PAM_TTY item: %d: %s\n",
220 err, pam_strerror(wl->ph, err));
221 return -1;
222 }
223
224 err = pam_open_session(wl->ph, 0);
225 if (err != PAM_SUCCESS) {
226 fprintf(stderr, "failed to open pam session: %d: %s\n",
227 err, pam_strerror(wl->ph, err));
228 return -1;
229 }
230
231 return 0;
232}
233
234static int
235setup_launcher_socket(struct weston_launch *wl)
236{
Randy Lia1450a82019-04-18 11:37:12 +0800237 if (socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, wl->sock) < 0) {
238 fprintf(stderr, "weston: socketpair failed: %s\n",
239 strerror(errno));
240 return -1;
241 }
Murray Calavera883ac022015-06-06 13:02:22 +0000242
Randy Lia1450a82019-04-18 11:37:12 +0800243 if (fcntl(wl->sock[0], F_SETFD, FD_CLOEXEC) < 0) {
244 fprintf(stderr, "weston: fcntl failed: %s\n",
245 strerror(errno));
246 return -1;
247 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100248
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100249 return 0;
250}
251
252static int
253setup_signals(struct weston_launch *wl)
254{
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100255 int ret;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100256 sigset_t mask;
257 struct sigaction sa;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100258
259 memset(&sa, 0, sizeof sa);
260 sa.sa_handler = SIG_DFL;
261 sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100262 ret = sigaction(SIGCHLD, &sa, NULL);
263 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100264
Kristian Høgsberg18684d42013-07-22 11:59:18 -0700265 sa.sa_handler = SIG_IGN;
266 sa.sa_flags = 0;
267 sigaction(SIGHUP, &sa, NULL);
268
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100269 ret = sigemptyset(&mask);
270 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100271 sigaddset(&mask, SIGCHLD);
272 sigaddset(&mask, SIGINT);
273 sigaddset(&mask, SIGTERM);
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700274 sigaddset(&mask, SIGUSR1);
275 sigaddset(&mask, SIGUSR2);
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100276 ret = sigprocmask(SIG_BLOCK, &mask, NULL);
277 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100278
279 wl->signalfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
280 if (wl->signalfd < 0)
281 return -errno;
282
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100283 return 0;
284}
285
286static void
287setenv_fd(const char *env, int fd)
288{
289 char buf[32];
290
291 snprintf(buf, sizeof buf, "%d", fd);
292 setenv(env, buf, 1);
293}
294
295static int
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700296send_reply(struct weston_launch *wl, int reply)
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100297{
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700298 int len;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100299
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100300 do {
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700301 len = send(wl->sock[0], &reply, sizeof reply, 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100302 } while (len < 0 && errno == EINTR);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100303
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700304 return len;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100305}
306
307static int
308handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
309{
310 int fd = -1, ret = -1;
311 char control[CMSG_SPACE(sizeof(fd))];
312 struct cmsghdr *cmsg;
313 struct stat s;
314 struct msghdr nmsg;
315 struct iovec iov;
316 struct weston_launcher_open *message;
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400317 union cmsg_data *data;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100318
319 message = msg->msg_iov->iov_base;
320 if ((size_t)len < sizeof(*message))
321 goto err0;
322
323 /* Ensure path is null-terminated */
324 ((char *) message)[len-1] = '\0';
325
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100326 fd = open(message->path, message->flags);
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100327 if (fd < 0) {
328 fprintf(stderr, "Error opening device %s: %m\n",
329 message->path);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100330 goto err0;
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100331 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100332
Kristian Høgsberg6a7c8492013-09-18 22:14:09 -0700333 if (fstat(fd, &s) < 0) {
334 close(fd);
335 fd = -1;
336 fprintf(stderr, "Failed to stat %s\n", message->path);
337 goto err0;
338 }
339
Kristian Høgsberg1ff51092013-09-17 14:03:42 -0700340 if (major(s.st_rdev) != INPUT_MAJOR &&
341 major(s.st_rdev) != DRM_MAJOR) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100342 close(fd);
343 fd = -1;
Kristian Høgsberg1ff51092013-09-17 14:03:42 -0700344 fprintf(stderr, "Device %s is not an input or drm device\n",
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100345 message->path);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100346 goto err0;
347 }
348
349err0:
350 memset(&nmsg, 0, sizeof nmsg);
351 nmsg.msg_iov = &iov;
352 nmsg.msg_iovlen = 1;
353 if (fd != -1) {
354 nmsg.msg_control = control;
355 nmsg.msg_controllen = sizeof control;
356 cmsg = CMSG_FIRSTHDR(&nmsg);
357 cmsg->cmsg_level = SOL_SOCKET;
358 cmsg->cmsg_type = SCM_RIGHTS;
359 cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400360 data = (union cmsg_data *) CMSG_DATA(cmsg);
361 data->fd = fd;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100362 nmsg.msg_controllen = cmsg->cmsg_len;
363 ret = 0;
364 }
365 iov.iov_base = &ret;
366 iov.iov_len = sizeof ret;
367
368 if (wl->verbose)
369 fprintf(stderr, "weston-launch: opened %s: ret: %d, fd: %d\n",
370 message->path, ret, fd);
371 do {
372 len = sendmsg(wl->sock[0], &nmsg, 0);
373 } while (len < 0 && errno == EINTR);
374
375 if (len < 0)
376 return -1;
377
Kristian Høgsbergaf393dc2013-10-09 11:25:14 -0700378 if (fd != -1 && major(s.st_rdev) == DRM_MAJOR)
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700379 wl->drm_fd = fd;
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -0700380 if (fd != -1 && major(s.st_rdev) == INPUT_MAJOR &&
381 wl->last_input_fd < fd)
382 wl->last_input_fd = fd;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700383
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100384 return 0;
385}
386
387static int
388handle_socket_msg(struct weston_launch *wl)
389{
390 char control[CMSG_SPACE(sizeof(int))];
391 char buf[BUFSIZ];
392 struct msghdr msg;
393 struct iovec iov;
394 int ret = -1;
395 ssize_t len;
396 struct weston_launcher_message *message;
397
398 memset(&msg, 0, sizeof(msg));
399 iov.iov_base = buf;
400 iov.iov_len = sizeof buf;
401 msg.msg_iov = &iov;
402 msg.msg_iovlen = 1;
403 msg.msg_control = control;
404 msg.msg_controllen = sizeof control;
405
406 do {
407 len = recvmsg(wl->sock[0], &msg, 0);
408 } while (len < 0 && errno == EINTR);
409
410 if (len < 1)
411 return -1;
412
413 message = (void *) buf;
414 switch (message->opcode) {
415 case WESTON_LAUNCHER_OPEN:
416 ret = handle_open(wl, &msg, len);
417 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100418 }
419
420 return ret;
421}
422
423static void
424quit(struct weston_launch *wl, int status)
425{
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700426 struct vt_mode mode = { 0 };
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100427 int err;
428
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100429 close(wl->signalfd);
430 close(wl->sock[0]);
431
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700432 if (wl->new_user) {
433 err = pam_close_session(wl->ph, 0);
434 if (err)
435 fprintf(stderr, "pam_close_session failed: %d: %s\n",
436 err, pam_strerror(wl->ph, err));
437 pam_end(wl->ph, err);
438 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100439
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700440 if (ioctl(wl->tty, KDSKBMUTE, 0) &&
441 ioctl(wl->tty, KDSKBMODE, wl->kb_mode))
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700442 fprintf(stderr, "failed to restore keyboard mode: %m\n");
443
444 if (ioctl(wl->tty, KDSETMODE, KD_TEXT))
445 fprintf(stderr, "failed to set KD_TEXT mode on tty: %m\n");
446
Kristian Høgsberga28ba552013-10-30 16:27:16 -0700447 /* We have to drop master before we switch the VT back in
448 * VT_AUTO, so we don't risk switching to a VT with another
449 * display server, that will then fail to set drm master. */
450 drmDropMaster(wl->drm_fd);
451
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700452 mode.mode = VT_AUTO;
453 if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
454 fprintf(stderr, "could not reset vt handling\n");
455
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100456 exit(status);
457}
458
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -0700459static void
460close_input_fds(struct weston_launch *wl)
461{
462 struct stat s;
463 int fd;
464
465 for (fd = 3; fd <= wl->last_input_fd; fd++) {
466 if (fstat(fd, &s) == 0 && major(s.st_rdev) == INPUT_MAJOR) {
467 /* EVIOCREVOKE may fail if the kernel doesn't
468 * support it, but all we can do is ignore it. */
469 ioctl(fd, EVIOCREVOKE, 0);
470 close(fd);
471 }
472 }
473}
474
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100475static int
476handle_signal(struct weston_launch *wl)
477{
478 struct signalfd_siginfo sig;
Philipp Brüschweiler7a3ec742013-03-10 15:14:01 +0100479 int pid, status, ret;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100480
481 if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) {
Randy Lia1450a82019-04-18 11:37:12 +0800482 fprintf(stderr, "weston: reading signalfd failed: %s\n",
483 strerror(errno));
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100484 return -1;
485 }
486
487 switch (sig.ssi_signo) {
488 case SIGCHLD:
489 pid = waitpid(-1, &status, 0);
490 if (pid == wl->child) {
491 wl->child = 0;
Philipp Brüschweiler7a3ec742013-03-10 15:14:01 +0100492 if (WIFEXITED(status))
493 ret = WEXITSTATUS(status);
494 else if (WIFSIGNALED(status))
495 /*
496 * If weston dies because of signal N, we
497 * return 10+N. This is distinct from
498 * weston-launch dying because of a signal
499 * (128+N).
500 */
501 ret = 10 + WTERMSIG(status);
502 else
503 ret = 0;
504 quit(wl, ret);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100505 }
506 break;
507 case SIGTERM:
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100508 case SIGINT:
509 if (wl->child)
Kristian Høgsberg1a81abb2013-06-17 15:23:20 -0400510 kill(wl->child, sig.ssi_signo);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100511 break;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700512 case SIGUSR1:
513 send_reply(wl, WESTON_LAUNCHER_DEACTIVATE);
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -0700514 close_input_fds(wl);
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700515 drmDropMaster(wl->drm_fd);
516 ioctl(wl->tty, VT_RELDISP, 1);
517 break;
518 case SIGUSR2:
519 ioctl(wl->tty, VT_RELDISP, VT_ACKACQ);
520 drmSetMaster(wl->drm_fd);
521 send_reply(wl, WESTON_LAUNCHER_ACTIVATE);
522 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100523 default:
524 return -1;
525 }
526
527 return 0;
528}
529
530static int
531setup_tty(struct weston_launch *wl, const char *tty)
532{
533 struct stat buf;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700534 struct vt_mode mode = { 0 };
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100535 char *t;
536
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700537 if (!wl->new_user) {
538 wl->tty = STDIN_FILENO;
539 } else if (tty) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100540 t = ttyname(STDIN_FILENO);
541 if (t && strcmp(t, tty) == 0)
542 wl->tty = STDIN_FILENO;
543 else
544 wl->tty = open(tty, O_RDWR | O_NOCTTY);
545 } else {
546 int tty0 = open("/dev/tty0", O_WRONLY | O_CLOEXEC);
547 char filename[16];
548
Randy Lia1450a82019-04-18 11:37:12 +0800549 if (tty0 < 0) {
550 fprintf(stderr, "weston: could not open tty0: %s\n",
551 strerror(errno));
552 return -1;
553 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100554
555 if (ioctl(tty0, VT_OPENQRY, &wl->ttynr) < 0 || wl->ttynr == -1)
Randy Lia1450a82019-04-18 11:37:12 +0800556 {
557 fprintf(stderr, "weston: failed to find non-opened console: %s\n",
558 strerror(errno));
559 return -1;
560 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100561
562 snprintf(filename, sizeof filename, "/dev/tty%d", wl->ttynr);
563 wl->tty = open(filename, O_RDWR | O_NOCTTY);
564 close(tty0);
565 }
566
Randy Lia1450a82019-04-18 11:37:12 +0800567 if (wl->tty < 0) {
568 fprintf(stderr, "weston: failed to open tty: %s\n",
569 strerror(errno));
570 return -1;
571 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100572
Kristian Høgsberge05f2282013-10-02 13:06:02 -0700573 if (fstat(wl->tty, &buf) == -1 ||
Randy Lia1450a82019-04-18 11:37:12 +0800574 major(buf.st_rdev) != TTY_MAJOR || minor(buf.st_rdev) == 0) {
575 fprintf(stderr, "weston: weston-launch must be run from a virtual terminal\n");
576 return -1;
577 }
Kristian Høgsberge05f2282013-10-02 13:06:02 -0700578
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100579 if (tty) {
Randy Lia1450a82019-04-18 11:37:12 +0800580 if (fstat(wl->tty, &buf) < 0) {
581 fprintf(stderr, "weston: stat %s failed: %s\n", tty,
582 strerror(errno));
583 return -1;
584 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100585
Randy Lia1450a82019-04-18 11:37:12 +0800586 if (major(buf.st_rdev) != TTY_MAJOR) {
587 fprintf(stderr,
588 "weston: invalid tty device: %s\n", tty);
589 return -1;
590 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100591
592 wl->ttynr = minor(buf.st_rdev);
593 }
594
Randy Lia1450a82019-04-18 11:37:12 +0800595 if (ioctl(wl->tty, KDGKBMODE, &wl->kb_mode)) {
596 fprintf(stderr,
597 "weston: failed to get current keyboard mode: %s",
598 strerror(errno));
599 return -1;
600 }
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700601
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700602 if (ioctl(wl->tty, KDSKBMUTE, 1) &&
Randy Lia1450a82019-04-18 11:37:12 +0800603 ioctl(wl->tty, KDSKBMODE, K_OFF)) {
604 fprintf(stderr,
605 "weston: failed to set K_OFF keyboard mode: %s\n",
606 strerror(errno));
607 return -1;
608 }
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700609
Randy Lia1450a82019-04-18 11:37:12 +0800610 if (ioctl(wl->tty, KDSETMODE, KD_GRAPHICS)) {
611 fprintf(stderr,
612 "weston: failed to set KD_GRAPHICS mode on tty: %s\n",
613 strerror(errno));
614 return -1;
615 }
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700616
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700617 mode.mode = VT_PROCESS;
618 mode.relsig = SIGUSR1;
619 mode.acqsig = SIGUSR2;
Randy Lia1450a82019-04-18 11:37:12 +0800620 if (ioctl(wl->tty, VT_SETMODE, &mode) < 0) {
621 fprintf(stderr,
622 "weston: failed to take control of vt handling %s\n",
623 strerror(errno));
624 return -1;
625 }
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700626
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100627 return 0;
628}
629
Quentin Glidic056889a2016-05-29 13:39:26 +0200630static int
631setup_session(struct weston_launch *wl, char **child_argv)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700632{
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700633 char **env;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700634 char *term;
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700635 int i;
636
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700637 if (wl->tty != STDIN_FILENO) {
Randy Lia1450a82019-04-18 11:37:12 +0800638 if (setsid() < 0) {
639 fprintf(stderr, "weston: setsid failed %s\n",
640 strerror(errno));
641 exit(EXIT_FAILURE);
642 }
643 if (ioctl(wl->tty, TIOCSCTTY, 0) < 0) {
644 fprintf(stderr, "TIOCSCTTY failed - tty is in use %s\n",
645 strerror(errno));
646 exit(EXIT_FAILURE);
647 }
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700648 }
649
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700650 term = getenv("TERM");
651 clearenv();
Rob Bradford7ac9f732013-08-09 11:30:38 +0100652 if (term)
653 setenv("TERM", term, 1);
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700654 setenv("USER", wl->pw->pw_name, 1);
655 setenv("LOGNAME", wl->pw->pw_name, 1);
656 setenv("HOME", wl->pw->pw_dir, 1);
657 setenv("SHELL", wl->pw->pw_shell, 1);
658
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700659 env = pam_getenvlist(wl->ph);
660 if (env) {
661 for (i = 0; env[i]; ++i) {
Dawid Gajownikf3c83362015-08-09 12:50:40 -0300662 if (putenv(env[i]) != 0)
Randy Lia1450a82019-04-18 11:37:12 +0800663 fprintf(stderr, "putenv %s failed\n", env[i]);
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700664 }
665 free(env);
666 }
Quentin Glidic056889a2016-05-29 13:39:26 +0200667
668 /*
669 * We open a new session, so it makes sense
670 * to run a new login shell
671 */
672 child_argv[0] = "/bin/sh";
673 child_argv[1] = "-l";
674 child_argv[2] = "-c";
675 child_argv[3] = BINDIR "/weston \"$@\"";
676 child_argv[4] = "weston";
677 return 5;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700678}
679
680static void
Peter Hutterer34be0602013-08-06 12:10:09 +1000681drop_privileges(struct weston_launch *wl)
682{
683 if (setgid(wl->pw->pw_gid) < 0 ||
684#ifdef HAVE_INITGROUPS
685 initgroups(wl->pw->pw_name, wl->pw->pw_gid) < 0 ||
686#endif
Randy Lia1450a82019-04-18 11:37:12 +0800687 setuid(wl->pw->pw_uid) < 0) {
688 fprintf(stderr, "weston: dropping privileges failed %s\n",
689 strerror(errno));
690 exit(EXIT_FAILURE);
691 }
Peter Hutterer34be0602013-08-06 12:10:09 +1000692}
693
694static void
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700695launch_compositor(struct weston_launch *wl, int argc, char *argv[])
696{
697 char *child_argv[MAX_ARGV_SIZE];
Eduardo Limad0357bb2013-07-30 10:43:41 -0700698 sigset_t mask;
Quentin Glidic056889a2016-05-29 13:39:26 +0200699 int o, i;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700700
701 if (wl->verbose)
702 printf("weston-launch: spawned weston with pid: %d\n", getpid());
Quentin Glidic056889a2016-05-29 13:39:26 +0200703 if (wl->new_user) {
704 o = setup_session(wl, child_argv);
705 } else {
706 child_argv[0] = BINDIR "/weston";
707 o = 1;
708 }
709 for (i = 0; i < argc; ++i)
710 child_argv[o + i] = argv[i];
711 child_argv[o + i] = NULL;
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700712
Tomeu Vizosod7865b22013-10-01 12:20:29 +0200713 if (geteuid() == 0)
714 drop_privileges(wl);
Peter Hutterer34be0602013-08-06 12:10:09 +1000715
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700716 setenv_fd("WESTON_TTY_FD", wl->tty);
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700717 setenv_fd("WESTON_LAUNCHER_SOCK", wl->sock[1]);
718
719 unsetenv("DISPLAY");
720
Kristian Høgsberg73c60ab2013-07-30 09:45:04 -0700721 /* Do not give our signal mask to the new process. */
722 sigemptyset(&mask);
723 sigaddset(&mask, SIGTERM);
724 sigaddset(&mask, SIGCHLD);
725 sigaddset(&mask, SIGINT);
726 sigprocmask(SIG_UNBLOCK, &mask, NULL);
727
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700728
729 execv(child_argv[0], child_argv);
Randy Lia1450a82019-04-18 11:37:12 +0800730 fprintf(stderr, "weston: exec failed: %s\n", strerror(errno));
731 exit(EXIT_FAILURE);
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700732}
733
734static void
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100735help(const char *name)
736{
737 fprintf(stderr, "Usage: %s [args...] [-- [weston args..]]\n", name);
Pekka Paalanen1a2adfe2017-11-01 12:20:24 +0200738 fprintf(stderr, " -u, --user Start session as specified username,\n"
739 " e.g. -u joe, requires root.\n");
740 fprintf(stderr, " -t, --tty Start session on alternative tty,\n"
741 " e.g. -t /dev/tty4, requires -u option.\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100742 fprintf(stderr, " -v, --verbose Be verbose\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100743 fprintf(stderr, " -h, --help Display this help message\n");
744}
745
746int
747main(int argc, char *argv[])
748{
749 struct weston_launch wl;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100750 int i, c;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700751 char *tty = NULL;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100752 struct option opts[] = {
753 { "user", required_argument, NULL, 'u' },
754 { "tty", required_argument, NULL, 't' },
755 { "verbose", no_argument, NULL, 'v' },
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100756 { "help", no_argument, NULL, 'h' },
757 { 0, 0, NULL, 0 }
Murray Calavera883ac022015-06-06 13:02:22 +0000758 };
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100759
760 memset(&wl, 0, sizeof wl);
761
Pekka Paalanen625f56f2017-11-01 13:20:03 +0200762 while ((c = getopt_long(argc, argv, "u:t:vh", opts, &i)) != -1) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100763 switch (c) {
764 case 'u':
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700765 wl.new_user = optarg;
Randy Lia1450a82019-04-18 11:37:12 +0800766 if (getuid() != 0) {
767 fprintf(stderr, "weston: Permission denied. -u allowed for root only\n");
768 exit(EXIT_FAILURE);
769 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100770 break;
771 case 't':
772 tty = optarg;
773 break;
774 case 'v':
775 wl.verbose = 1;
776 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100777 case 'h':
Scott Moreaucc9acfc2013-01-21 23:40:59 -0700778 help("weston-launch");
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530779 exit(EXIT_FAILURE);
Tom Hochsteine57056f2016-05-07 08:57:40 -0300780 default:
781 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100782 }
783 }
784
Randy Lia1450a82019-04-18 11:37:12 +0800785 if ((argc - optind) > (MAX_ARGV_SIZE - 6)) {
786 fprintf(stderr,
787 "weston: Too many arguments to pass to weston: %s\n",
788 strerror(E2BIG));
789 exit(EXIT_FAILURE);
790 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100791
Randy Lia1450a82019-04-18 11:37:12 +0800792 if (tty && !wl.new_user) {
793 fprintf(stderr, "weston: -t/--tty option requires -u/--user option as well\n");
794 exit(EXIT_FAILURE);
795 }
Pekka Paalanen5949e482017-11-01 12:12:17 +0200796
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700797 if (wl.new_user)
798 wl.pw = getpwnam(wl.new_user);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100799 else
800 wl.pw = getpwuid(getuid());
Randy Lia1450a82019-04-18 11:37:12 +0800801 if (wl.pw == NULL) {
802 fprintf(stderr, "weston: failed to get username: %s\n",
803 strerror(errno));
804 exit(EXIT_FAILURE);
805 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100806
Randy Lia1450a82019-04-18 11:37:12 +0800807 if (!weston_launch_allowed(&wl)) {
808 fprintf(stderr, "Permission denied. You should either:\n"
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100809#ifdef HAVE_SYSTEMD_LOGIN
810 " - run from an active and local (systemd) session.\n"
811#else
812 " - enable systemd session support for weston-launch.\n"
813#endif
Randy Lia1450a82019-04-18 11:37:12 +0800814 " - or add yourself to the 'weston-launch' group.\n");
815 exit(EXIT_FAILURE);
816 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100817
818 if (setup_tty(&wl, tty) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530819 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100820
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700821 if (wl.new_user && setup_pam(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530822 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100823
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100824 if (setup_launcher_socket(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530825 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100826
827 if (setup_signals(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530828 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100829
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700830 wl.child = fork();
Randy Lia1450a82019-04-18 11:37:12 +0800831 if (wl.child == -1) {
832 fprintf(stderr, "weston: fork failed %s\n", strerror(errno));
833 exit(EXIT_FAILURE);
834 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100835
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700836 if (wl.child == 0)
837 launch_compositor(&wl, argc - optind, argv + optind);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100838
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700839 close(wl.sock[1]);
840 if (wl.tty != STDIN_FILENO)
841 close(wl.tty);
Quentin Glidic735302e2013-06-19 15:27:11 +0200842
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700843 while (1) {
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700844 struct pollfd fds[2];
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700845 int n;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100846
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700847 fds[0].fd = wl.sock[0];
848 fds[0].events = POLLIN;
849 fds[1].fd = wl.signalfd;
850 fds[1].events = POLLIN;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100851
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700852 n = poll(fds, 2, -1);
853 if (n < 0)
854 error(0, errno, "poll failed");
855 if (fds[0].revents & POLLIN)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700856 handle_socket_msg(&wl);
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700857 if (fds[1].revents)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700858 handle_signal(&wl);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100859 }
860
861 return 0;
862}