blob: 52c89d37066542a77495b4862b0772c11ea66177 [file] [log] [blame]
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001/*
2 * Copyright © 2012 Benjamin Franzke
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and
5 * its documentation for any purpose is hereby granted without fee, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of the copyright holders not be used in
9 * advertising or publicity pertaining to distribution of the software
10 * without specific, written prior permission. The copyright holders make
11 * no representations about the suitability of this software for any
12 * purpose. It is provided "as is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 */
22
Benjamin Franzkebfeda132012-01-30 14:04:04 +010023#include "config.h"
24
Derek Foreman280e7dd2014-10-03 13:13:42 -050025#include <stdbool.h>
Benjamin Franzkebfeda132012-01-30 14:04:04 +010026#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <assert.h>
Kristian Høgsbergf2807702013-07-23 11:43:03 -070030#include <poll.h>
Benjamin Franzkebfeda132012-01-30 14:04:04 +010031#include <errno.h>
32
33#include <error.h>
34#include <getopt.h>
35
36#include <sys/types.h>
37#include <sys/ioctl.h>
38#include <sys/stat.h>
39#include <sys/wait.h>
40#include <sys/socket.h>
Benjamin Franzkebfeda132012-01-30 14:04:04 +010041#include <sys/signalfd.h>
42#include <signal.h>
43#include <unistd.h>
44#include <fcntl.h>
45
Benjamin Franzkebfeda132012-01-30 14:04:04 +010046#include <linux/vt.h>
47#include <linux/major.h>
Kristian Høgsberg81b49632013-09-17 22:43:22 -070048#include <linux/kd.h>
Benjamin Franzkebfeda132012-01-30 14:04:04 +010049
50#include <pwd.h>
51#include <grp.h>
52#include <security/pam_appl.h>
53
Benjamin Franzkebfeda132012-01-30 14:04:04 +010054#ifdef HAVE_SYSTEMD_LOGIN
55#include <systemd/sd-login.h>
56#endif
57
58#include "weston-launch.h"
59
Kristian Høgsberg1ff51092013-09-17 14:03:42 -070060#define DRM_MAJOR 226
61
Kristian Høgsberg3f495872013-09-18 23:00:17 -070062#ifndef KDSKBMUTE
63#define KDSKBMUTE 0x4B51
64#endif
65
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -070066#ifndef EVIOCREVOKE
67#define EVIOCREVOKE _IOW('E', 0x91, int)
68#endif
69
Quentin Glidicff323092013-05-17 16:20:37 +020070#define MAX_ARGV_SIZE 256
71
Kristian Høgsbergd2c9d8a2013-11-24 14:37:07 -080072#ifdef HAVE_LIBDRM
73
74#include <xf86drm.h>
75
76#else
77
78static inline int
79drmDropMaster(int drm_fd)
80{
81 return 0;
82}
83
84static inline int
85drmSetMaster(int drm_fd)
86{
87 return 0;
88}
89
90#endif
91
Benjamin Franzkebfeda132012-01-30 14:04:04 +010092struct weston_launch {
93 struct pam_conv pc;
94 pam_handle_t *ph;
95 int tty;
96 int ttynr;
97 int sock[2];
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -070098 int drm_fd;
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -070099 int last_input_fd;
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700100 int kb_mode;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100101 struct passwd *pw;
102
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100103 int signalfd;
104
105 pid_t child;
106 int verbose;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700107 char *new_user;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100108};
109
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400110union cmsg_data { unsigned char b[4]; int fd; };
111
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100112static gid_t *
113read_groups(void)
114{
115 int n;
116 gid_t *groups;
Murray Calavera883ac022015-06-06 13:02:22 +0000117
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100118 n = getgroups(0, NULL);
Rob Bradford40be7b42012-12-05 18:47:11 +0000119
120 if (n < 0) {
121 fprintf(stderr, "Unable to retrieve groups: %m\n");
122 return NULL;
123 }
124
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100125 groups = malloc(n * sizeof(gid_t));
126 if (!groups)
127 return NULL;
128
129 if (getgroups(n, groups) < 0) {
Rob Bradford40be7b42012-12-05 18:47:11 +0000130 fprintf(stderr, "Unable to retrieve groups: %m\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100131 free(groups);
132 return NULL;
133 }
134 return groups;
135}
136
Derek Foreman280e7dd2014-10-03 13:13:42 -0500137static bool
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100138weston_launch_allowed(struct weston_launch *wl)
139{
140 struct group *gr;
141 gid_t *groups;
142 int i;
143#ifdef HAVE_SYSTEMD_LOGIN
144 char *session, *seat;
145 int err;
146#endif
147
148 if (getuid() == 0)
Derek Foreman280e7dd2014-10-03 13:13:42 -0500149 return true;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100150
151 gr = getgrnam("weston-launch");
152 if (gr) {
153 groups = read_groups();
154 if (groups) {
155 for (i = 0; groups[i]; ++i) {
156 if (groups[i] == gr->gr_gid) {
157 free(groups);
Derek Foreman280e7dd2014-10-03 13:13:42 -0500158 return true;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100159 }
160 }
161 free(groups);
162 }
163 }
164
165#ifdef HAVE_SYSTEMD_LOGIN
166 err = sd_pid_get_session(getpid(), &session);
167 if (err == 0 && session) {
168 if (sd_session_is_active(session) &&
169 sd_session_get_seat(session, &seat) == 0) {
170 free(seat);
171 free(session);
Derek Foreman280e7dd2014-10-03 13:13:42 -0500172 return true;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100173 }
174 free(session);
175 }
176#endif
Murray Calavera883ac022015-06-06 13:02:22 +0000177
Derek Foreman280e7dd2014-10-03 13:13:42 -0500178 return false;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100179}
180
181static int
182pam_conversation_fn(int msg_count,
183 const struct pam_message **messages,
184 struct pam_response **responses,
185 void *user_data)
186{
187 return PAM_SUCCESS;
188}
189
190static int
191setup_pam(struct weston_launch *wl)
192{
193 int err;
194
195 wl->pc.conv = pam_conversation_fn;
196 wl->pc.appdata_ptr = wl;
197
198 err = pam_start("login", wl->pw->pw_name, &wl->pc, &wl->ph);
John Kåre Alsaker5b90d8f2012-10-12 12:25:05 +0200199 if (err != PAM_SUCCESS) {
200 fprintf(stderr, "failed to start pam transaction: %d: %s\n",
201 err, pam_strerror(wl->ph, err));
202 return -1;
203 }
204
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100205 err = pam_set_item(wl->ph, PAM_TTY, ttyname(wl->tty));
206 if (err != PAM_SUCCESS) {
207 fprintf(stderr, "failed to set PAM_TTY item: %d: %s\n",
208 err, pam_strerror(wl->ph, err));
209 return -1;
210 }
211
212 err = pam_open_session(wl->ph, 0);
213 if (err != PAM_SUCCESS) {
214 fprintf(stderr, "failed to open pam session: %d: %s\n",
215 err, pam_strerror(wl->ph, err));
216 return -1;
217 }
218
219 return 0;
220}
221
222static int
223setup_launcher_socket(struct weston_launch *wl)
224{
Kristian Høgsbergbf3c3742013-09-18 11:01:48 -0700225 if (socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, wl->sock) < 0)
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100226 error(1, errno, "socketpair failed");
Murray Calavera883ac022015-06-06 13:02:22 +0000227
Kristian Høgsbergf45b1e82013-09-18 11:00:56 -0700228 if (fcntl(wl->sock[0], F_SETFD, FD_CLOEXEC) < 0)
229 error(1, errno, "fcntl failed");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100230
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100231 return 0;
232}
233
234static int
235setup_signals(struct weston_launch *wl)
236{
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100237 int ret;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100238 sigset_t mask;
239 struct sigaction sa;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100240
241 memset(&sa, 0, sizeof sa);
242 sa.sa_handler = SIG_DFL;
243 sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100244 ret = sigaction(SIGCHLD, &sa, NULL);
245 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100246
Kristian Høgsberg18684d42013-07-22 11:59:18 -0700247 sa.sa_handler = SIG_IGN;
248 sa.sa_flags = 0;
249 sigaction(SIGHUP, &sa, NULL);
250
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100251 ret = sigemptyset(&mask);
252 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100253 sigaddset(&mask, SIGCHLD);
254 sigaddset(&mask, SIGINT);
255 sigaddset(&mask, SIGTERM);
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700256 sigaddset(&mask, SIGUSR1);
257 sigaddset(&mask, SIGUSR2);
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100258 ret = sigprocmask(SIG_BLOCK, &mask, NULL);
259 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100260
261 wl->signalfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
262 if (wl->signalfd < 0)
263 return -errno;
264
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100265 return 0;
266}
267
268static void
269setenv_fd(const char *env, int fd)
270{
271 char buf[32];
272
273 snprintf(buf, sizeof buf, "%d", fd);
274 setenv(env, buf, 1);
275}
276
277static int
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700278send_reply(struct weston_launch *wl, int reply)
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100279{
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700280 int len;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100281
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100282 do {
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700283 len = send(wl->sock[0], &reply, sizeof reply, 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100284 } while (len < 0 && errno == EINTR);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100285
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700286 return len;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100287}
288
289static int
290handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
291{
292 int fd = -1, ret = -1;
293 char control[CMSG_SPACE(sizeof(fd))];
294 struct cmsghdr *cmsg;
295 struct stat s;
296 struct msghdr nmsg;
297 struct iovec iov;
298 struct weston_launcher_open *message;
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400299 union cmsg_data *data;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100300
301 message = msg->msg_iov->iov_base;
302 if ((size_t)len < sizeof(*message))
303 goto err0;
304
305 /* Ensure path is null-terminated */
306 ((char *) message)[len-1] = '\0';
307
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100308 fd = open(message->path, message->flags);
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100309 if (fd < 0) {
310 fprintf(stderr, "Error opening device %s: %m\n",
311 message->path);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100312 goto err0;
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100313 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100314
Kristian Høgsberg6a7c8492013-09-18 22:14:09 -0700315 if (fstat(fd, &s) < 0) {
316 close(fd);
317 fd = -1;
318 fprintf(stderr, "Failed to stat %s\n", message->path);
319 goto err0;
320 }
321
Kristian Høgsberg1ff51092013-09-17 14:03:42 -0700322 if (major(s.st_rdev) != INPUT_MAJOR &&
323 major(s.st_rdev) != DRM_MAJOR) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100324 close(fd);
325 fd = -1;
Kristian Høgsberg1ff51092013-09-17 14:03:42 -0700326 fprintf(stderr, "Device %s is not an input or drm device\n",
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100327 message->path);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100328 goto err0;
329 }
330
331err0:
332 memset(&nmsg, 0, sizeof nmsg);
333 nmsg.msg_iov = &iov;
334 nmsg.msg_iovlen = 1;
335 if (fd != -1) {
336 nmsg.msg_control = control;
337 nmsg.msg_controllen = sizeof control;
338 cmsg = CMSG_FIRSTHDR(&nmsg);
339 cmsg->cmsg_level = SOL_SOCKET;
340 cmsg->cmsg_type = SCM_RIGHTS;
341 cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400342 data = (union cmsg_data *) CMSG_DATA(cmsg);
343 data->fd = fd;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100344 nmsg.msg_controllen = cmsg->cmsg_len;
345 ret = 0;
346 }
347 iov.iov_base = &ret;
348 iov.iov_len = sizeof ret;
349
350 if (wl->verbose)
351 fprintf(stderr, "weston-launch: opened %s: ret: %d, fd: %d\n",
352 message->path, ret, fd);
353 do {
354 len = sendmsg(wl->sock[0], &nmsg, 0);
355 } while (len < 0 && errno == EINTR);
356
357 if (len < 0)
358 return -1;
359
Kristian Høgsbergaf393dc2013-10-09 11:25:14 -0700360 if (fd != -1 && major(s.st_rdev) == DRM_MAJOR)
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700361 wl->drm_fd = fd;
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -0700362 if (fd != -1 && major(s.st_rdev) == INPUT_MAJOR &&
363 wl->last_input_fd < fd)
364 wl->last_input_fd = fd;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700365
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100366 return 0;
367}
368
369static int
370handle_socket_msg(struct weston_launch *wl)
371{
372 char control[CMSG_SPACE(sizeof(int))];
373 char buf[BUFSIZ];
374 struct msghdr msg;
375 struct iovec iov;
376 int ret = -1;
377 ssize_t len;
378 struct weston_launcher_message *message;
379
380 memset(&msg, 0, sizeof(msg));
381 iov.iov_base = buf;
382 iov.iov_len = sizeof buf;
383 msg.msg_iov = &iov;
384 msg.msg_iovlen = 1;
385 msg.msg_control = control;
386 msg.msg_controllen = sizeof control;
387
388 do {
389 len = recvmsg(wl->sock[0], &msg, 0);
390 } while (len < 0 && errno == EINTR);
391
392 if (len < 1)
393 return -1;
394
395 message = (void *) buf;
396 switch (message->opcode) {
397 case WESTON_LAUNCHER_OPEN:
398 ret = handle_open(wl, &msg, len);
399 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100400 }
401
402 return ret;
403}
404
405static void
406quit(struct weston_launch *wl, int status)
407{
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700408 struct vt_mode mode = { 0 };
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100409 int err;
410
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100411 close(wl->signalfd);
412 close(wl->sock[0]);
413
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700414 if (wl->new_user) {
415 err = pam_close_session(wl->ph, 0);
416 if (err)
417 fprintf(stderr, "pam_close_session failed: %d: %s\n",
418 err, pam_strerror(wl->ph, err));
419 pam_end(wl->ph, err);
420 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100421
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700422 if (ioctl(wl->tty, KDSKBMUTE, 0) &&
423 ioctl(wl->tty, KDSKBMODE, wl->kb_mode))
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700424 fprintf(stderr, "failed to restore keyboard mode: %m\n");
425
426 if (ioctl(wl->tty, KDSETMODE, KD_TEXT))
427 fprintf(stderr, "failed to set KD_TEXT mode on tty: %m\n");
428
Kristian Høgsberga28ba552013-10-30 16:27:16 -0700429 /* We have to drop master before we switch the VT back in
430 * VT_AUTO, so we don't risk switching to a VT with another
431 * display server, that will then fail to set drm master. */
432 drmDropMaster(wl->drm_fd);
433
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700434 mode.mode = VT_AUTO;
435 if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
436 fprintf(stderr, "could not reset vt handling\n");
437
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100438 exit(status);
439}
440
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -0700441static void
442close_input_fds(struct weston_launch *wl)
443{
444 struct stat s;
445 int fd;
446
447 for (fd = 3; fd <= wl->last_input_fd; fd++) {
448 if (fstat(fd, &s) == 0 && major(s.st_rdev) == INPUT_MAJOR) {
449 /* EVIOCREVOKE may fail if the kernel doesn't
450 * support it, but all we can do is ignore it. */
451 ioctl(fd, EVIOCREVOKE, 0);
452 close(fd);
453 }
454 }
455}
456
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100457static int
458handle_signal(struct weston_launch *wl)
459{
460 struct signalfd_siginfo sig;
Philipp Brüschweiler7a3ec742013-03-10 15:14:01 +0100461 int pid, status, ret;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100462
463 if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) {
464 error(0, errno, "reading signalfd failed");
465 return -1;
466 }
467
468 switch (sig.ssi_signo) {
469 case SIGCHLD:
470 pid = waitpid(-1, &status, 0);
471 if (pid == wl->child) {
472 wl->child = 0;
Philipp Brüschweiler7a3ec742013-03-10 15:14:01 +0100473 if (WIFEXITED(status))
474 ret = WEXITSTATUS(status);
475 else if (WIFSIGNALED(status))
476 /*
477 * If weston dies because of signal N, we
478 * return 10+N. This is distinct from
479 * weston-launch dying because of a signal
480 * (128+N).
481 */
482 ret = 10 + WTERMSIG(status);
483 else
484 ret = 0;
485 quit(wl, ret);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100486 }
487 break;
488 case SIGTERM:
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100489 case SIGINT:
490 if (wl->child)
Kristian Høgsberg1a81abb2013-06-17 15:23:20 -0400491 kill(wl->child, sig.ssi_signo);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100492 break;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700493 case SIGUSR1:
494 send_reply(wl, WESTON_LAUNCHER_DEACTIVATE);
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -0700495 close_input_fds(wl);
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700496 drmDropMaster(wl->drm_fd);
497 ioctl(wl->tty, VT_RELDISP, 1);
498 break;
499 case SIGUSR2:
500 ioctl(wl->tty, VT_RELDISP, VT_ACKACQ);
501 drmSetMaster(wl->drm_fd);
502 send_reply(wl, WESTON_LAUNCHER_ACTIVATE);
503 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100504 default:
505 return -1;
506 }
507
508 return 0;
509}
510
511static int
512setup_tty(struct weston_launch *wl, const char *tty)
513{
514 struct stat buf;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700515 struct vt_mode mode = { 0 };
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100516 char *t;
517
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700518 if (!wl->new_user) {
519 wl->tty = STDIN_FILENO;
520 } else if (tty) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100521 t = ttyname(STDIN_FILENO);
522 if (t && strcmp(t, tty) == 0)
523 wl->tty = STDIN_FILENO;
524 else
525 wl->tty = open(tty, O_RDWR | O_NOCTTY);
526 } else {
527 int tty0 = open("/dev/tty0", O_WRONLY | O_CLOEXEC);
528 char filename[16];
529
530 if (tty0 < 0)
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300531 error(1, errno, "could not open tty0");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100532
533 if (ioctl(tty0, VT_OPENQRY, &wl->ttynr) < 0 || wl->ttynr == -1)
Murray Calavera883ac022015-06-06 13:02:22 +0000534 error(1, errno, "failed to find non-opened console");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100535
536 snprintf(filename, sizeof filename, "/dev/tty%d", wl->ttynr);
537 wl->tty = open(filename, O_RDWR | O_NOCTTY);
538 close(tty0);
539 }
540
541 if (wl->tty < 0)
542 error(1, errno, "failed to open tty");
543
Kristian Høgsberge05f2282013-10-02 13:06:02 -0700544 if (fstat(wl->tty, &buf) == -1 ||
545 major(buf.st_rdev) != TTY_MAJOR || minor(buf.st_rdev) == 0)
546 error(1, 0, "weston-launch must be run from a virtual terminal");
547
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100548 if (tty) {
549 if (fstat(wl->tty, &buf) < 0)
550 error(1, errno, "stat %s failed", tty);
551
552 if (major(buf.st_rdev) != TTY_MAJOR)
553 error(1, 0, "invalid tty device: %s", tty);
554
555 wl->ttynr = minor(buf.st_rdev);
556 }
557
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700558 if (ioctl(wl->tty, KDGKBMODE, &wl->kb_mode))
559 error(1, errno, "failed to get current keyboard mode: %m\n");
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700560
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700561 if (ioctl(wl->tty, KDSKBMUTE, 1) &&
562 ioctl(wl->tty, KDSKBMODE, K_OFF))
563 error(1, errno, "failed to set K_OFF 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, KDSETMODE, KD_GRAPHICS))
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700566 error(1, errno, "failed to set KD_GRAPHICS mode on tty: %m\n");
567
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700568 mode.mode = VT_PROCESS;
569 mode.relsig = SIGUSR1;
570 mode.acqsig = SIGUSR2;
571 if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
572 error(1, errno, "failed to take control of vt handling\n");
573
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100574 return 0;
575}
576
577static void
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700578setup_session(struct weston_launch *wl)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700579{
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700580 char **env;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700581 char *term;
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700582 int i;
583
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700584 if (wl->tty != STDIN_FILENO) {
585 if (setsid() < 0)
586 error(1, errno, "setsid failed");
587 if (ioctl(wl->tty, TIOCSCTTY, 0) < 0)
588 error(1, errno, "TIOCSCTTY failed - tty is in use");
589 }
590
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700591 term = getenv("TERM");
592 clearenv();
Rob Bradford7ac9f732013-08-09 11:30:38 +0100593 if (term)
594 setenv("TERM", term, 1);
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700595 setenv("USER", wl->pw->pw_name, 1);
596 setenv("LOGNAME", wl->pw->pw_name, 1);
597 setenv("HOME", wl->pw->pw_dir, 1);
598 setenv("SHELL", wl->pw->pw_shell, 1);
599
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700600 env = pam_getenvlist(wl->ph);
601 if (env) {
602 for (i = 0; env[i]; ++i) {
603 if (putenv(env[i]) < 0)
604 error(0, 0, "putenv %s failed", env[i]);
605 }
606 free(env);
607 }
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700608}
609
610static void
Peter Hutterer34be0602013-08-06 12:10:09 +1000611drop_privileges(struct weston_launch *wl)
612{
613 if (setgid(wl->pw->pw_gid) < 0 ||
614#ifdef HAVE_INITGROUPS
615 initgroups(wl->pw->pw_name, wl->pw->pw_gid) < 0 ||
616#endif
617 setuid(wl->pw->pw_uid) < 0)
618 error(1, errno, "dropping privileges failed");
619}
620
621static void
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700622launch_compositor(struct weston_launch *wl, int argc, char *argv[])
623{
624 char *child_argv[MAX_ARGV_SIZE];
Eduardo Limad0357bb2013-07-30 10:43:41 -0700625 sigset_t mask;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700626 int i;
627
628 if (wl->verbose)
629 printf("weston-launch: spawned weston with pid: %d\n", getpid());
630 if (wl->new_user)
631 setup_session(wl);
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700632
Tomeu Vizosod7865b22013-10-01 12:20:29 +0200633 if (geteuid() == 0)
634 drop_privileges(wl);
Peter Hutterer34be0602013-08-06 12:10:09 +1000635
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700636 setenv_fd("WESTON_TTY_FD", wl->tty);
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700637 setenv_fd("WESTON_LAUNCHER_SOCK", wl->sock[1]);
638
639 unsetenv("DISPLAY");
640
Kristian Høgsberg73c60ab2013-07-30 09:45:04 -0700641 /* Do not give our signal mask to the new process. */
642 sigemptyset(&mask);
643 sigaddset(&mask, SIGTERM);
644 sigaddset(&mask, SIGCHLD);
645 sigaddset(&mask, SIGINT);
646 sigprocmask(SIG_UNBLOCK, &mask, NULL);
647
Kristian Høgsbergfb08e4b2013-10-21 15:14:44 -0700648 child_argv[0] = "/bin/sh";
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700649 child_argv[1] = "-l";
650 child_argv[2] = "-c";
651 child_argv[3] = BINDIR "/weston \"$@\"";
652 child_argv[4] = "weston";
653 for (i = 0; i < argc; ++i)
654 child_argv[5 + i] = argv[i];
655 child_argv[5 + i] = NULL;
656
657 execv(child_argv[0], child_argv);
658 error(1, errno, "exec failed");
659}
660
661static void
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100662help(const char *name)
663{
664 fprintf(stderr, "Usage: %s [args...] [-- [weston args..]]\n", name);
665 fprintf(stderr, " -u, --user Start session as specified username\n");
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300666 fprintf(stderr, " -t, --tty Start session on alternative tty\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100667 fprintf(stderr, " -v, --verbose Be verbose\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100668 fprintf(stderr, " -h, --help Display this help message\n");
669}
670
671int
672main(int argc, char *argv[])
673{
674 struct weston_launch wl;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100675 int i, c;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700676 char *tty = NULL;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100677 struct option opts[] = {
678 { "user", required_argument, NULL, 'u' },
679 { "tty", required_argument, NULL, 't' },
680 { "verbose", no_argument, NULL, 'v' },
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100681 { "help", no_argument, NULL, 'h' },
682 { 0, 0, NULL, 0 }
Murray Calavera883ac022015-06-06 13:02:22 +0000683 };
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100684
685 memset(&wl, 0, sizeof wl);
686
Kristian Høgsbergab499942013-07-19 21:26:24 -0700687 while ((c = getopt_long(argc, argv, "u:t::vh", opts, &i)) != -1) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100688 switch (c) {
689 case 'u':
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700690 wl.new_user = optarg;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100691 if (getuid() != 0)
692 error(1, 0, "Permission denied. -u allowed for root only");
693 break;
694 case 't':
695 tty = optarg;
696 break;
697 case 'v':
698 wl.verbose = 1;
699 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100700 case 'h':
Scott Moreaucc9acfc2013-01-21 23:40:59 -0700701 help("weston-launch");
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530702 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100703 }
704 }
705
Ander Conselvan de Oliveira9bdfc482013-05-22 22:55:33 +0300706 if ((argc - optind) > (MAX_ARGV_SIZE - 6))
Quentin Glidicff323092013-05-17 16:20:37 +0200707 error(1, E2BIG, "Too many arguments to pass to weston");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100708
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700709 if (wl.new_user)
710 wl.pw = getpwnam(wl.new_user);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100711 else
712 wl.pw = getpwuid(getuid());
713 if (wl.pw == NULL)
714 error(1, errno, "failed to get username");
715
716 if (!weston_launch_allowed(&wl))
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300717 error(1, 0, "Permission denied. You should either:\n"
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100718#ifdef HAVE_SYSTEMD_LOGIN
719 " - run from an active and local (systemd) session.\n"
720#else
721 " - enable systemd session support for weston-launch.\n"
722#endif
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300723 " - or add yourself to the 'weston-launch' group.");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100724
725 if (setup_tty(&wl, tty) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530726 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100727
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700728 if (wl.new_user && setup_pam(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530729 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100730
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100731 if (setup_launcher_socket(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530732 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100733
734 if (setup_signals(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530735 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100736
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700737 wl.child = fork();
738 if (wl.child == -1) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100739 error(1, errno, "fork failed");
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700740 exit(EXIT_FAILURE);
741 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100742
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700743 if (wl.child == 0)
744 launch_compositor(&wl, argc - optind, argv + optind);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100745
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700746 close(wl.sock[1]);
747 if (wl.tty != STDIN_FILENO)
748 close(wl.tty);
Quentin Glidic735302e2013-06-19 15:27:11 +0200749
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700750 while (1) {
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700751 struct pollfd fds[2];
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700752 int n;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100753
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700754 fds[0].fd = wl.sock[0];
755 fds[0].events = POLLIN;
756 fds[1].fd = wl.signalfd;
757 fds[1].events = POLLIN;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100758
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700759 n = poll(fds, 2, -1);
760 if (n < 0)
761 error(0, errno, "poll failed");
762 if (fds[0].revents & POLLIN)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700763 handle_socket_msg(&wl);
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700764 if (fds[1].revents)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700765 handle_signal(&wl);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100766 }
767
768 return 0;
769}