blob: f67aaaf05fd58f44880d8995040626d741127971 [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>
45#include <signal.h>
46#include <unistd.h>
47#include <fcntl.h>
48
Benjamin Franzkebfeda132012-01-30 14:04:04 +010049#include <linux/vt.h>
50#include <linux/major.h>
Kristian Høgsberg81b49632013-09-17 22:43:22 -070051#include <linux/kd.h>
Benjamin Franzkebfeda132012-01-30 14:04:04 +010052
53#include <pwd.h>
54#include <grp.h>
55#include <security/pam_appl.h>
56
Benjamin Franzkebfeda132012-01-30 14:04:04 +010057#ifdef HAVE_SYSTEMD_LOGIN
58#include <systemd/sd-login.h>
59#endif
60
61#include "weston-launch.h"
62
Kristian Høgsberg1ff51092013-09-17 14:03:42 -070063#define DRM_MAJOR 226
64
Kristian Høgsberg3f495872013-09-18 23:00:17 -070065#ifndef KDSKBMUTE
66#define KDSKBMUTE 0x4B51
67#endif
68
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -070069#ifndef EVIOCREVOKE
70#define EVIOCREVOKE _IOW('E', 0x91, int)
71#endif
72
Quentin Glidicff323092013-05-17 16:20:37 +020073#define MAX_ARGV_SIZE 256
74
Kristian Høgsbergd2c9d8a2013-11-24 14:37:07 -080075#ifdef HAVE_LIBDRM
76
77#include <xf86drm.h>
78
79#else
80
81static inline int
82drmDropMaster(int drm_fd)
83{
84 return 0;
85}
86
87static inline int
88drmSetMaster(int drm_fd)
89{
90 return 0;
91}
92
93#endif
94
Benjamin Franzkebfeda132012-01-30 14:04:04 +010095struct weston_launch {
96 struct pam_conv pc;
97 pam_handle_t *ph;
98 int tty;
99 int ttynr;
100 int sock[2];
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700101 int drm_fd;
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -0700102 int last_input_fd;
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700103 int kb_mode;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100104 struct passwd *pw;
105
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100106 int signalfd;
107
108 pid_t child;
109 int verbose;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700110 char *new_user;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100111};
112
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400113union cmsg_data { unsigned char b[4]; int fd; };
114
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100115static gid_t *
116read_groups(void)
117{
118 int n;
119 gid_t *groups;
Murray Calavera883ac022015-06-06 13:02:22 +0000120
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100121 n = getgroups(0, NULL);
Rob Bradford40be7b42012-12-05 18:47:11 +0000122
123 if (n < 0) {
124 fprintf(stderr, "Unable to retrieve groups: %m\n");
125 return NULL;
126 }
127
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100128 groups = malloc(n * sizeof(gid_t));
129 if (!groups)
130 return NULL;
131
132 if (getgroups(n, groups) < 0) {
Rob Bradford40be7b42012-12-05 18:47:11 +0000133 fprintf(stderr, "Unable to retrieve groups: %m\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100134 free(groups);
135 return NULL;
136 }
137 return groups;
138}
139
Derek Foreman280e7dd2014-10-03 13:13:42 -0500140static bool
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100141weston_launch_allowed(struct weston_launch *wl)
142{
143 struct group *gr;
144 gid_t *groups;
145 int i;
146#ifdef HAVE_SYSTEMD_LOGIN
147 char *session, *seat;
148 int err;
149#endif
150
151 if (getuid() == 0)
Derek Foreman280e7dd2014-10-03 13:13:42 -0500152 return true;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100153
154 gr = getgrnam("weston-launch");
155 if (gr) {
156 groups = read_groups();
157 if (groups) {
158 for (i = 0; groups[i]; ++i) {
159 if (groups[i] == gr->gr_gid) {
160 free(groups);
Derek Foreman280e7dd2014-10-03 13:13:42 -0500161 return true;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100162 }
163 }
164 free(groups);
165 }
166 }
167
168#ifdef HAVE_SYSTEMD_LOGIN
169 err = sd_pid_get_session(getpid(), &session);
170 if (err == 0 && session) {
171 if (sd_session_is_active(session) &&
172 sd_session_get_seat(session, &seat) == 0) {
173 free(seat);
174 free(session);
Derek Foreman280e7dd2014-10-03 13:13:42 -0500175 return true;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100176 }
177 free(session);
178 }
179#endif
Murray Calavera883ac022015-06-06 13:02:22 +0000180
Derek Foreman280e7dd2014-10-03 13:13:42 -0500181 return false;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100182}
183
184static int
185pam_conversation_fn(int msg_count,
186 const struct pam_message **messages,
187 struct pam_response **responses,
188 void *user_data)
189{
190 return PAM_SUCCESS;
191}
192
193static int
194setup_pam(struct weston_launch *wl)
195{
196 int err;
197
198 wl->pc.conv = pam_conversation_fn;
199 wl->pc.appdata_ptr = wl;
200
201 err = pam_start("login", wl->pw->pw_name, &wl->pc, &wl->ph);
John Kåre Alsaker5b90d8f2012-10-12 12:25:05 +0200202 if (err != PAM_SUCCESS) {
203 fprintf(stderr, "failed to start pam transaction: %d: %s\n",
204 err, pam_strerror(wl->ph, err));
205 return -1;
206 }
207
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100208 err = pam_set_item(wl->ph, PAM_TTY, ttyname(wl->tty));
209 if (err != PAM_SUCCESS) {
210 fprintf(stderr, "failed to set PAM_TTY item: %d: %s\n",
211 err, pam_strerror(wl->ph, err));
212 return -1;
213 }
214
215 err = pam_open_session(wl->ph, 0);
216 if (err != PAM_SUCCESS) {
217 fprintf(stderr, "failed to open pam session: %d: %s\n",
218 err, pam_strerror(wl->ph, err));
219 return -1;
220 }
221
222 return 0;
223}
224
225static int
226setup_launcher_socket(struct weston_launch *wl)
227{
Kristian Høgsbergbf3c3742013-09-18 11:01:48 -0700228 if (socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, wl->sock) < 0)
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100229 error(1, errno, "socketpair failed");
Murray Calavera883ac022015-06-06 13:02:22 +0000230
Kristian Høgsbergf45b1e82013-09-18 11:00:56 -0700231 if (fcntl(wl->sock[0], F_SETFD, FD_CLOEXEC) < 0)
232 error(1, errno, "fcntl failed");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100233
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100234 return 0;
235}
236
237static int
238setup_signals(struct weston_launch *wl)
239{
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100240 int ret;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100241 sigset_t mask;
242 struct sigaction sa;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100243
244 memset(&sa, 0, sizeof sa);
245 sa.sa_handler = SIG_DFL;
246 sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100247 ret = sigaction(SIGCHLD, &sa, NULL);
248 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100249
Kristian Høgsberg18684d42013-07-22 11:59:18 -0700250 sa.sa_handler = SIG_IGN;
251 sa.sa_flags = 0;
252 sigaction(SIGHUP, &sa, NULL);
253
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100254 ret = sigemptyset(&mask);
255 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100256 sigaddset(&mask, SIGCHLD);
257 sigaddset(&mask, SIGINT);
258 sigaddset(&mask, SIGTERM);
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700259 sigaddset(&mask, SIGUSR1);
260 sigaddset(&mask, SIGUSR2);
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100261 ret = sigprocmask(SIG_BLOCK, &mask, NULL);
262 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100263
264 wl->signalfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
265 if (wl->signalfd < 0)
266 return -errno;
267
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100268 return 0;
269}
270
271static void
272setenv_fd(const char *env, int fd)
273{
274 char buf[32];
275
276 snprintf(buf, sizeof buf, "%d", fd);
277 setenv(env, buf, 1);
278}
279
280static int
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700281send_reply(struct weston_launch *wl, int reply)
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100282{
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700283 int len;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100284
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100285 do {
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700286 len = send(wl->sock[0], &reply, sizeof reply, 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100287 } while (len < 0 && errno == EINTR);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100288
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700289 return len;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100290}
291
292static int
293handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
294{
295 int fd = -1, ret = -1;
296 char control[CMSG_SPACE(sizeof(fd))];
297 struct cmsghdr *cmsg;
298 struct stat s;
299 struct msghdr nmsg;
300 struct iovec iov;
301 struct weston_launcher_open *message;
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400302 union cmsg_data *data;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100303
304 message = msg->msg_iov->iov_base;
305 if ((size_t)len < sizeof(*message))
306 goto err0;
307
308 /* Ensure path is null-terminated */
309 ((char *) message)[len-1] = '\0';
310
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100311 fd = open(message->path, message->flags);
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100312 if (fd < 0) {
313 fprintf(stderr, "Error opening device %s: %m\n",
314 message->path);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100315 goto err0;
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100316 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100317
Kristian Høgsberg6a7c8492013-09-18 22:14:09 -0700318 if (fstat(fd, &s) < 0) {
319 close(fd);
320 fd = -1;
321 fprintf(stderr, "Failed to stat %s\n", message->path);
322 goto err0;
323 }
324
Kristian Høgsberg1ff51092013-09-17 14:03:42 -0700325 if (major(s.st_rdev) != INPUT_MAJOR &&
326 major(s.st_rdev) != DRM_MAJOR) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100327 close(fd);
328 fd = -1;
Kristian Høgsberg1ff51092013-09-17 14:03:42 -0700329 fprintf(stderr, "Device %s is not an input or drm device\n",
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100330 message->path);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100331 goto err0;
332 }
333
334err0:
335 memset(&nmsg, 0, sizeof nmsg);
336 nmsg.msg_iov = &iov;
337 nmsg.msg_iovlen = 1;
338 if (fd != -1) {
339 nmsg.msg_control = control;
340 nmsg.msg_controllen = sizeof control;
341 cmsg = CMSG_FIRSTHDR(&nmsg);
342 cmsg->cmsg_level = SOL_SOCKET;
343 cmsg->cmsg_type = SCM_RIGHTS;
344 cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400345 data = (union cmsg_data *) CMSG_DATA(cmsg);
346 data->fd = fd;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100347 nmsg.msg_controllen = cmsg->cmsg_len;
348 ret = 0;
349 }
350 iov.iov_base = &ret;
351 iov.iov_len = sizeof ret;
352
353 if (wl->verbose)
354 fprintf(stderr, "weston-launch: opened %s: ret: %d, fd: %d\n",
355 message->path, ret, fd);
356 do {
357 len = sendmsg(wl->sock[0], &nmsg, 0);
358 } while (len < 0 && errno == EINTR);
359
360 if (len < 0)
361 return -1;
362
Kristian Høgsbergaf393dc2013-10-09 11:25:14 -0700363 if (fd != -1 && major(s.st_rdev) == DRM_MAJOR)
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700364 wl->drm_fd = fd;
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -0700365 if (fd != -1 && major(s.st_rdev) == INPUT_MAJOR &&
366 wl->last_input_fd < fd)
367 wl->last_input_fd = fd;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700368
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100369 return 0;
370}
371
372static int
373handle_socket_msg(struct weston_launch *wl)
374{
375 char control[CMSG_SPACE(sizeof(int))];
376 char buf[BUFSIZ];
377 struct msghdr msg;
378 struct iovec iov;
379 int ret = -1;
380 ssize_t len;
381 struct weston_launcher_message *message;
382
383 memset(&msg, 0, sizeof(msg));
384 iov.iov_base = buf;
385 iov.iov_len = sizeof buf;
386 msg.msg_iov = &iov;
387 msg.msg_iovlen = 1;
388 msg.msg_control = control;
389 msg.msg_controllen = sizeof control;
390
391 do {
392 len = recvmsg(wl->sock[0], &msg, 0);
393 } while (len < 0 && errno == EINTR);
394
395 if (len < 1)
396 return -1;
397
398 message = (void *) buf;
399 switch (message->opcode) {
400 case WESTON_LAUNCHER_OPEN:
401 ret = handle_open(wl, &msg, len);
402 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100403 }
404
405 return ret;
406}
407
408static void
409quit(struct weston_launch *wl, int status)
410{
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700411 struct vt_mode mode = { 0 };
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100412 int err;
413
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100414 close(wl->signalfd);
415 close(wl->sock[0]);
416
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700417 if (wl->new_user) {
418 err = pam_close_session(wl->ph, 0);
419 if (err)
420 fprintf(stderr, "pam_close_session failed: %d: %s\n",
421 err, pam_strerror(wl->ph, err));
422 pam_end(wl->ph, err);
423 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100424
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700425 if (ioctl(wl->tty, KDSKBMUTE, 0) &&
426 ioctl(wl->tty, KDSKBMODE, wl->kb_mode))
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700427 fprintf(stderr, "failed to restore keyboard mode: %m\n");
428
429 if (ioctl(wl->tty, KDSETMODE, KD_TEXT))
430 fprintf(stderr, "failed to set KD_TEXT mode on tty: %m\n");
431
Kristian Høgsberga28ba552013-10-30 16:27:16 -0700432 /* We have to drop master before we switch the VT back in
433 * VT_AUTO, so we don't risk switching to a VT with another
434 * display server, that will then fail to set drm master. */
435 drmDropMaster(wl->drm_fd);
436
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700437 mode.mode = VT_AUTO;
438 if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
439 fprintf(stderr, "could not reset vt handling\n");
440
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100441 exit(status);
442}
443
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -0700444static void
445close_input_fds(struct weston_launch *wl)
446{
447 struct stat s;
448 int fd;
449
450 for (fd = 3; fd <= wl->last_input_fd; fd++) {
451 if (fstat(fd, &s) == 0 && major(s.st_rdev) == INPUT_MAJOR) {
452 /* EVIOCREVOKE may fail if the kernel doesn't
453 * support it, but all we can do is ignore it. */
454 ioctl(fd, EVIOCREVOKE, 0);
455 close(fd);
456 }
457 }
458}
459
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100460static int
461handle_signal(struct weston_launch *wl)
462{
463 struct signalfd_siginfo sig;
Philipp Brüschweiler7a3ec742013-03-10 15:14:01 +0100464 int pid, status, ret;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100465
466 if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) {
467 error(0, errno, "reading signalfd failed");
468 return -1;
469 }
470
471 switch (sig.ssi_signo) {
472 case SIGCHLD:
473 pid = waitpid(-1, &status, 0);
474 if (pid == wl->child) {
475 wl->child = 0;
Philipp Brüschweiler7a3ec742013-03-10 15:14:01 +0100476 if (WIFEXITED(status))
477 ret = WEXITSTATUS(status);
478 else if (WIFSIGNALED(status))
479 /*
480 * If weston dies because of signal N, we
481 * return 10+N. This is distinct from
482 * weston-launch dying because of a signal
483 * (128+N).
484 */
485 ret = 10 + WTERMSIG(status);
486 else
487 ret = 0;
488 quit(wl, ret);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100489 }
490 break;
491 case SIGTERM:
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100492 case SIGINT:
493 if (wl->child)
Kristian Høgsberg1a81abb2013-06-17 15:23:20 -0400494 kill(wl->child, sig.ssi_signo);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100495 break;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700496 case SIGUSR1:
497 send_reply(wl, WESTON_LAUNCHER_DEACTIVATE);
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -0700498 close_input_fds(wl);
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700499 drmDropMaster(wl->drm_fd);
500 ioctl(wl->tty, VT_RELDISP, 1);
501 break;
502 case SIGUSR2:
503 ioctl(wl->tty, VT_RELDISP, VT_ACKACQ);
504 drmSetMaster(wl->drm_fd);
505 send_reply(wl, WESTON_LAUNCHER_ACTIVATE);
506 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100507 default:
508 return -1;
509 }
510
511 return 0;
512}
513
514static int
515setup_tty(struct weston_launch *wl, const char *tty)
516{
517 struct stat buf;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700518 struct vt_mode mode = { 0 };
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100519 char *t;
520
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700521 if (!wl->new_user) {
522 wl->tty = STDIN_FILENO;
523 } else if (tty) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100524 t = ttyname(STDIN_FILENO);
525 if (t && strcmp(t, tty) == 0)
526 wl->tty = STDIN_FILENO;
527 else
528 wl->tty = open(tty, O_RDWR | O_NOCTTY);
529 } else {
530 int tty0 = open("/dev/tty0", O_WRONLY | O_CLOEXEC);
531 char filename[16];
532
533 if (tty0 < 0)
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300534 error(1, errno, "could not open tty0");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100535
536 if (ioctl(tty0, VT_OPENQRY, &wl->ttynr) < 0 || wl->ttynr == -1)
Murray Calavera883ac022015-06-06 13:02:22 +0000537 error(1, errno, "failed to find non-opened console");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100538
539 snprintf(filename, sizeof filename, "/dev/tty%d", wl->ttynr);
540 wl->tty = open(filename, O_RDWR | O_NOCTTY);
541 close(tty0);
542 }
543
544 if (wl->tty < 0)
545 error(1, errno, "failed to open tty");
546
Kristian Høgsberge05f2282013-10-02 13:06:02 -0700547 if (fstat(wl->tty, &buf) == -1 ||
548 major(buf.st_rdev) != TTY_MAJOR || minor(buf.st_rdev) == 0)
549 error(1, 0, "weston-launch must be run from a virtual terminal");
550
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100551 if (tty) {
552 if (fstat(wl->tty, &buf) < 0)
553 error(1, errno, "stat %s failed", tty);
554
555 if (major(buf.st_rdev) != TTY_MAJOR)
556 error(1, 0, "invalid tty device: %s", tty);
557
558 wl->ttynr = minor(buf.st_rdev);
559 }
560
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700561 if (ioctl(wl->tty, KDGKBMODE, &wl->kb_mode))
562 error(1, errno, "failed to get current keyboard mode: %m\n");
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700563
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700564 if (ioctl(wl->tty, KDSKBMUTE, 1) &&
565 ioctl(wl->tty, KDSKBMODE, K_OFF))
566 error(1, errno, "failed to set K_OFF keyboard mode: %m\n");
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700567
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700568 if (ioctl(wl->tty, KDSETMODE, KD_GRAPHICS))
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700569 error(1, errno, "failed to set KD_GRAPHICS mode on tty: %m\n");
570
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700571 mode.mode = VT_PROCESS;
572 mode.relsig = SIGUSR1;
573 mode.acqsig = SIGUSR2;
574 if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
575 error(1, errno, "failed to take control of vt handling\n");
576
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100577 return 0;
578}
579
580static void
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700581setup_session(struct weston_launch *wl)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700582{
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700583 char **env;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700584 char *term;
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700585 int i;
586
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700587 if (wl->tty != STDIN_FILENO) {
588 if (setsid() < 0)
589 error(1, errno, "setsid failed");
590 if (ioctl(wl->tty, TIOCSCTTY, 0) < 0)
591 error(1, errno, "TIOCSCTTY failed - tty is in use");
592 }
593
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700594 term = getenv("TERM");
595 clearenv();
Rob Bradford7ac9f732013-08-09 11:30:38 +0100596 if (term)
597 setenv("TERM", term, 1);
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700598 setenv("USER", wl->pw->pw_name, 1);
599 setenv("LOGNAME", wl->pw->pw_name, 1);
600 setenv("HOME", wl->pw->pw_dir, 1);
601 setenv("SHELL", wl->pw->pw_shell, 1);
602
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700603 env = pam_getenvlist(wl->ph);
604 if (env) {
605 for (i = 0; env[i]; ++i) {
606 if (putenv(env[i]) < 0)
607 error(0, 0, "putenv %s failed", env[i]);
608 }
609 free(env);
610 }
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700611}
612
613static void
Peter Hutterer34be0602013-08-06 12:10:09 +1000614drop_privileges(struct weston_launch *wl)
615{
616 if (setgid(wl->pw->pw_gid) < 0 ||
617#ifdef HAVE_INITGROUPS
618 initgroups(wl->pw->pw_name, wl->pw->pw_gid) < 0 ||
619#endif
620 setuid(wl->pw->pw_uid) < 0)
621 error(1, errno, "dropping privileges failed");
622}
623
624static void
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700625launch_compositor(struct weston_launch *wl, int argc, char *argv[])
626{
627 char *child_argv[MAX_ARGV_SIZE];
Eduardo Limad0357bb2013-07-30 10:43:41 -0700628 sigset_t mask;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700629 int i;
630
631 if (wl->verbose)
632 printf("weston-launch: spawned weston with pid: %d\n", getpid());
633 if (wl->new_user)
634 setup_session(wl);
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700635
Tomeu Vizosod7865b22013-10-01 12:20:29 +0200636 if (geteuid() == 0)
637 drop_privileges(wl);
Peter Hutterer34be0602013-08-06 12:10:09 +1000638
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700639 setenv_fd("WESTON_TTY_FD", wl->tty);
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700640 setenv_fd("WESTON_LAUNCHER_SOCK", wl->sock[1]);
641
642 unsetenv("DISPLAY");
643
Kristian Høgsberg73c60ab2013-07-30 09:45:04 -0700644 /* Do not give our signal mask to the new process. */
645 sigemptyset(&mask);
646 sigaddset(&mask, SIGTERM);
647 sigaddset(&mask, SIGCHLD);
648 sigaddset(&mask, SIGINT);
649 sigprocmask(SIG_UNBLOCK, &mask, NULL);
650
Kristian Høgsbergfb08e4b2013-10-21 15:14:44 -0700651 child_argv[0] = "/bin/sh";
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700652 child_argv[1] = "-l";
653 child_argv[2] = "-c";
654 child_argv[3] = BINDIR "/weston \"$@\"";
655 child_argv[4] = "weston";
656 for (i = 0; i < argc; ++i)
657 child_argv[5 + i] = argv[i];
658 child_argv[5 + i] = NULL;
659
660 execv(child_argv[0], child_argv);
661 error(1, errno, "exec failed");
662}
663
664static void
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100665help(const char *name)
666{
667 fprintf(stderr, "Usage: %s [args...] [-- [weston args..]]\n", name);
668 fprintf(stderr, " -u, --user Start session as specified username\n");
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300669 fprintf(stderr, " -t, --tty Start session on alternative tty\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100670 fprintf(stderr, " -v, --verbose Be verbose\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100671 fprintf(stderr, " -h, --help Display this help message\n");
672}
673
674int
675main(int argc, char *argv[])
676{
677 struct weston_launch wl;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100678 int i, c;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700679 char *tty = NULL;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100680 struct option opts[] = {
681 { "user", required_argument, NULL, 'u' },
682 { "tty", required_argument, NULL, 't' },
683 { "verbose", no_argument, NULL, 'v' },
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100684 { "help", no_argument, NULL, 'h' },
685 { 0, 0, NULL, 0 }
Murray Calavera883ac022015-06-06 13:02:22 +0000686 };
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100687
688 memset(&wl, 0, sizeof wl);
689
Kristian Høgsbergab499942013-07-19 21:26:24 -0700690 while ((c = getopt_long(argc, argv, "u:t::vh", opts, &i)) != -1) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100691 switch (c) {
692 case 'u':
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700693 wl.new_user = optarg;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100694 if (getuid() != 0)
695 error(1, 0, "Permission denied. -u allowed for root only");
696 break;
697 case 't':
698 tty = optarg;
699 break;
700 case 'v':
701 wl.verbose = 1;
702 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100703 case 'h':
Scott Moreaucc9acfc2013-01-21 23:40:59 -0700704 help("weston-launch");
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530705 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100706 }
707 }
708
Ander Conselvan de Oliveira9bdfc482013-05-22 22:55:33 +0300709 if ((argc - optind) > (MAX_ARGV_SIZE - 6))
Quentin Glidicff323092013-05-17 16:20:37 +0200710 error(1, E2BIG, "Too many arguments to pass to weston");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100711
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700712 if (wl.new_user)
713 wl.pw = getpwnam(wl.new_user);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100714 else
715 wl.pw = getpwuid(getuid());
716 if (wl.pw == NULL)
717 error(1, errno, "failed to get username");
718
719 if (!weston_launch_allowed(&wl))
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300720 error(1, 0, "Permission denied. You should either:\n"
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100721#ifdef HAVE_SYSTEMD_LOGIN
722 " - run from an active and local (systemd) session.\n"
723#else
724 " - enable systemd session support for weston-launch.\n"
725#endif
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300726 " - or add yourself to the 'weston-launch' group.");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100727
728 if (setup_tty(&wl, tty) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530729 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100730
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700731 if (wl.new_user && setup_pam(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530732 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100733
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100734 if (setup_launcher_socket(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530735 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100736
737 if (setup_signals(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530738 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100739
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700740 wl.child = fork();
741 if (wl.child == -1) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100742 error(1, errno, "fork failed");
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700743 exit(EXIT_FAILURE);
744 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100745
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700746 if (wl.child == 0)
747 launch_compositor(&wl, argc - optind, argv + optind);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100748
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700749 close(wl.sock[1]);
750 if (wl.tty != STDIN_FILENO)
751 close(wl.tty);
Quentin Glidic735302e2013-06-19 15:27:11 +0200752
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700753 while (1) {
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700754 struct pollfd fds[2];
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700755 int n;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100756
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700757 fds[0].fd = wl.sock[0];
758 fds[0].events = POLLIN;
759 fds[1].fd = wl.signalfd;
760 fds[1].events = POLLIN;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100761
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700762 n = poll(fds, 2, -1);
763 if (n < 0)
764 error(0, errno, "poll failed");
765 if (fds[0].revents & POLLIN)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700766 handle_socket_msg(&wl);
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700767 if (fds[1].revents)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700768 handle_signal(&wl);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100769 }
770
771 return 0;
772}