blob: d8364c855cc1191888d1bb220d1bd6e1aaa64b75 [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
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <assert.h>
Kristian Høgsbergf2807702013-07-23 11:43:03 -070029#include <poll.h>
Benjamin Franzkebfeda132012-01-30 14:04:04 +010030#include <errno.h>
31
32#include <error.h>
33#include <getopt.h>
34
35#include <sys/types.h>
36#include <sys/ioctl.h>
37#include <sys/stat.h>
38#include <sys/wait.h>
39#include <sys/socket.h>
Benjamin Franzkebfeda132012-01-30 14:04:04 +010040#include <sys/signalfd.h>
41#include <signal.h>
42#include <unistd.h>
43#include <fcntl.h>
44
Benjamin Franzkebfeda132012-01-30 14:04:04 +010045#include <linux/vt.h>
46#include <linux/major.h>
Kristian Høgsberg81b49632013-09-17 22:43:22 -070047#include <linux/kd.h>
Benjamin Franzkebfeda132012-01-30 14:04:04 +010048
49#include <pwd.h>
50#include <grp.h>
51#include <security/pam_appl.h>
52
53#include <xf86drm.h>
54
55#ifdef HAVE_SYSTEMD_LOGIN
56#include <systemd/sd-login.h>
57#endif
58
59#include "weston-launch.h"
60
Kristian Høgsberg1ff51092013-09-17 14:03:42 -070061#define DRM_MAJOR 226
62
Kristian Høgsberg3f495872013-09-18 23:00:17 -070063#ifndef KDSKBMUTE
64#define KDSKBMUTE 0x4B51
65#endif
66
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -070067#ifndef EVIOCREVOKE
68#define EVIOCREVOKE _IOW('E', 0x91, int)
69#endif
70
Quentin Glidicff323092013-05-17 16:20:37 +020071#define MAX_ARGV_SIZE 256
72
Benjamin Franzkebfeda132012-01-30 14:04:04 +010073struct weston_launch {
74 struct pam_conv pc;
75 pam_handle_t *ph;
76 int tty;
77 int ttynr;
78 int sock[2];
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -070079 int drm_fd;
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -070080 int last_input_fd;
Kristian Høgsberg81b49632013-09-17 22:43:22 -070081 int kb_mode;
Benjamin Franzkebfeda132012-01-30 14:04:04 +010082 struct passwd *pw;
83
Benjamin Franzkebfeda132012-01-30 14:04:04 +010084 int signalfd;
85
86 pid_t child;
87 int verbose;
Kristian Høgsberg636156d2013-07-22 10:35:47 -070088 char *new_user;
Benjamin Franzkebfeda132012-01-30 14:04:04 +010089};
90
Kristian Høgsberg9e140912012-04-10 01:26:18 -040091union cmsg_data { unsigned char b[4]; int fd; };
92
Benjamin Franzkebfeda132012-01-30 14:04:04 +010093static gid_t *
94read_groups(void)
95{
96 int n;
97 gid_t *groups;
98
99 n = getgroups(0, NULL);
Rob Bradford40be7b42012-12-05 18:47:11 +0000100
101 if (n < 0) {
102 fprintf(stderr, "Unable to retrieve groups: %m\n");
103 return NULL;
104 }
105
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100106 groups = malloc(n * sizeof(gid_t));
107 if (!groups)
108 return NULL;
109
110 if (getgroups(n, groups) < 0) {
Rob Bradford40be7b42012-12-05 18:47:11 +0000111 fprintf(stderr, "Unable to retrieve groups: %m\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100112 free(groups);
113 return NULL;
114 }
115 return groups;
116}
117
118static int
119weston_launch_allowed(struct weston_launch *wl)
120{
121 struct group *gr;
122 gid_t *groups;
123 int i;
124#ifdef HAVE_SYSTEMD_LOGIN
125 char *session, *seat;
126 int err;
127#endif
128
129 if (getuid() == 0)
130 return 1;
131
132 gr = getgrnam("weston-launch");
133 if (gr) {
134 groups = read_groups();
135 if (groups) {
136 for (i = 0; groups[i]; ++i) {
137 if (groups[i] == gr->gr_gid) {
138 free(groups);
139 return 1;
140 }
141 }
142 free(groups);
143 }
144 }
145
146#ifdef HAVE_SYSTEMD_LOGIN
147 err = sd_pid_get_session(getpid(), &session);
148 if (err == 0 && session) {
149 if (sd_session_is_active(session) &&
150 sd_session_get_seat(session, &seat) == 0) {
151 free(seat);
152 free(session);
153 return 1;
154 }
155 free(session);
156 }
157#endif
158
159 return 0;
160}
161
162static int
163pam_conversation_fn(int msg_count,
164 const struct pam_message **messages,
165 struct pam_response **responses,
166 void *user_data)
167{
168 return PAM_SUCCESS;
169}
170
171static int
172setup_pam(struct weston_launch *wl)
173{
174 int err;
175
176 wl->pc.conv = pam_conversation_fn;
177 wl->pc.appdata_ptr = wl;
178
179 err = pam_start("login", wl->pw->pw_name, &wl->pc, &wl->ph);
John Kåre Alsaker5b90d8f2012-10-12 12:25:05 +0200180 if (err != PAM_SUCCESS) {
181 fprintf(stderr, "failed to start pam transaction: %d: %s\n",
182 err, pam_strerror(wl->ph, err));
183 return -1;
184 }
185
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100186 err = pam_set_item(wl->ph, PAM_TTY, ttyname(wl->tty));
187 if (err != PAM_SUCCESS) {
188 fprintf(stderr, "failed to set PAM_TTY item: %d: %s\n",
189 err, pam_strerror(wl->ph, err));
190 return -1;
191 }
192
193 err = pam_open_session(wl->ph, 0);
194 if (err != PAM_SUCCESS) {
195 fprintf(stderr, "failed to open pam session: %d: %s\n",
196 err, pam_strerror(wl->ph, err));
197 return -1;
198 }
199
200 return 0;
201}
202
203static int
204setup_launcher_socket(struct weston_launch *wl)
205{
Kristian Høgsbergbf3c3742013-09-18 11:01:48 -0700206 if (socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, wl->sock) < 0)
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100207 error(1, errno, "socketpair failed");
208
Kristian Høgsbergf45b1e82013-09-18 11:00:56 -0700209 if (fcntl(wl->sock[0], F_SETFD, FD_CLOEXEC) < 0)
210 error(1, errno, "fcntl failed");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100211
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100212 return 0;
213}
214
215static int
216setup_signals(struct weston_launch *wl)
217{
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100218 int ret;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100219 sigset_t mask;
220 struct sigaction sa;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100221
222 memset(&sa, 0, sizeof sa);
223 sa.sa_handler = SIG_DFL;
224 sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100225 ret = sigaction(SIGCHLD, &sa, NULL);
226 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100227
Kristian Høgsberg18684d42013-07-22 11:59:18 -0700228 sa.sa_handler = SIG_IGN;
229 sa.sa_flags = 0;
230 sigaction(SIGHUP, &sa, NULL);
231
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100232 ret = sigemptyset(&mask);
233 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100234 sigaddset(&mask, SIGCHLD);
235 sigaddset(&mask, SIGINT);
236 sigaddset(&mask, SIGTERM);
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700237 sigaddset(&mask, SIGUSR1);
238 sigaddset(&mask, SIGUSR2);
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100239 ret = sigprocmask(SIG_BLOCK, &mask, NULL);
240 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100241
242 wl->signalfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
243 if (wl->signalfd < 0)
244 return -errno;
245
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100246 return 0;
247}
248
249static void
250setenv_fd(const char *env, int fd)
251{
252 char buf[32];
253
254 snprintf(buf, sizeof buf, "%d", fd);
255 setenv(env, buf, 1);
256}
257
258static int
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700259send_reply(struct weston_launch *wl, int reply)
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100260{
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700261 int len;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100262
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100263 do {
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700264 len = send(wl->sock[0], &reply, sizeof reply, 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100265 } while (len < 0 && errno == EINTR);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100266
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700267 return len;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100268}
269
270static int
271handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
272{
273 int fd = -1, ret = -1;
274 char control[CMSG_SPACE(sizeof(fd))];
275 struct cmsghdr *cmsg;
276 struct stat s;
277 struct msghdr nmsg;
278 struct iovec iov;
279 struct weston_launcher_open *message;
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400280 union cmsg_data *data;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100281
282 message = msg->msg_iov->iov_base;
283 if ((size_t)len < sizeof(*message))
284 goto err0;
285
286 /* Ensure path is null-terminated */
287 ((char *) message)[len-1] = '\0';
288
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100289 fd = open(message->path, message->flags);
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100290 if (fd < 0) {
291 fprintf(stderr, "Error opening device %s: %m\n",
292 message->path);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100293 goto err0;
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100294 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100295
Kristian Høgsberg6a7c8492013-09-18 22:14:09 -0700296 if (fstat(fd, &s) < 0) {
297 close(fd);
298 fd = -1;
299 fprintf(stderr, "Failed to stat %s\n", message->path);
300 goto err0;
301 }
302
Kristian Høgsberg1ff51092013-09-17 14:03:42 -0700303 if (major(s.st_rdev) != INPUT_MAJOR &&
304 major(s.st_rdev) != DRM_MAJOR) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100305 close(fd);
306 fd = -1;
Kristian Høgsberg1ff51092013-09-17 14:03:42 -0700307 fprintf(stderr, "Device %s is not an input or drm device\n",
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100308 message->path);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100309 goto err0;
310 }
311
312err0:
313 memset(&nmsg, 0, sizeof nmsg);
314 nmsg.msg_iov = &iov;
315 nmsg.msg_iovlen = 1;
316 if (fd != -1) {
317 nmsg.msg_control = control;
318 nmsg.msg_controllen = sizeof control;
319 cmsg = CMSG_FIRSTHDR(&nmsg);
320 cmsg->cmsg_level = SOL_SOCKET;
321 cmsg->cmsg_type = SCM_RIGHTS;
322 cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400323 data = (union cmsg_data *) CMSG_DATA(cmsg);
324 data->fd = fd;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100325 nmsg.msg_controllen = cmsg->cmsg_len;
326 ret = 0;
327 }
328 iov.iov_base = &ret;
329 iov.iov_len = sizeof ret;
330
331 if (wl->verbose)
332 fprintf(stderr, "weston-launch: opened %s: ret: %d, fd: %d\n",
333 message->path, ret, fd);
334 do {
335 len = sendmsg(wl->sock[0], &nmsg, 0);
336 } while (len < 0 && errno == EINTR);
337
338 if (len < 0)
339 return -1;
340
Kristian Høgsbergaf393dc2013-10-09 11:25:14 -0700341 if (fd != -1 && major(s.st_rdev) == DRM_MAJOR)
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700342 wl->drm_fd = fd;
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -0700343 if (fd != -1 && major(s.st_rdev) == INPUT_MAJOR &&
344 wl->last_input_fd < fd)
345 wl->last_input_fd = fd;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700346
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100347 return 0;
348}
349
350static int
351handle_socket_msg(struct weston_launch *wl)
352{
353 char control[CMSG_SPACE(sizeof(int))];
354 char buf[BUFSIZ];
355 struct msghdr msg;
356 struct iovec iov;
357 int ret = -1;
358 ssize_t len;
359 struct weston_launcher_message *message;
360
361 memset(&msg, 0, sizeof(msg));
362 iov.iov_base = buf;
363 iov.iov_len = sizeof buf;
364 msg.msg_iov = &iov;
365 msg.msg_iovlen = 1;
366 msg.msg_control = control;
367 msg.msg_controllen = sizeof control;
368
369 do {
370 len = recvmsg(wl->sock[0], &msg, 0);
371 } while (len < 0 && errno == EINTR);
372
373 if (len < 1)
374 return -1;
375
376 message = (void *) buf;
377 switch (message->opcode) {
378 case WESTON_LAUNCHER_OPEN:
379 ret = handle_open(wl, &msg, len);
380 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100381 }
382
383 return ret;
384}
385
386static void
387quit(struct weston_launch *wl, int status)
388{
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700389 struct vt_mode mode = { 0 };
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100390 int err;
391
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100392 close(wl->signalfd);
393 close(wl->sock[0]);
394
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700395 if (wl->new_user) {
396 err = pam_close_session(wl->ph, 0);
397 if (err)
398 fprintf(stderr, "pam_close_session failed: %d: %s\n",
399 err, pam_strerror(wl->ph, err));
400 pam_end(wl->ph, err);
401 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100402
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700403 if (ioctl(wl->tty, KDSKBMUTE, 0) &&
404 ioctl(wl->tty, KDSKBMODE, wl->kb_mode))
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700405 fprintf(stderr, "failed to restore keyboard mode: %m\n");
406
407 if (ioctl(wl->tty, KDSETMODE, KD_TEXT))
408 fprintf(stderr, "failed to set KD_TEXT mode on tty: %m\n");
409
Kristian Høgsberga28ba552013-10-30 16:27:16 -0700410 /* We have to drop master before we switch the VT back in
411 * VT_AUTO, so we don't risk switching to a VT with another
412 * display server, that will then fail to set drm master. */
413 drmDropMaster(wl->drm_fd);
414
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700415 mode.mode = VT_AUTO;
416 if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
417 fprintf(stderr, "could not reset vt handling\n");
418
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100419 exit(status);
420}
421
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -0700422static void
423close_input_fds(struct weston_launch *wl)
424{
425 struct stat s;
426 int fd;
427
428 for (fd = 3; fd <= wl->last_input_fd; fd++) {
429 if (fstat(fd, &s) == 0 && major(s.st_rdev) == INPUT_MAJOR) {
430 /* EVIOCREVOKE may fail if the kernel doesn't
431 * support it, but all we can do is ignore it. */
432 ioctl(fd, EVIOCREVOKE, 0);
433 close(fd);
434 }
435 }
436}
437
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100438static int
439handle_signal(struct weston_launch *wl)
440{
441 struct signalfd_siginfo sig;
Philipp Brüschweiler7a3ec742013-03-10 15:14:01 +0100442 int pid, status, ret;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100443
444 if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) {
445 error(0, errno, "reading signalfd failed");
446 return -1;
447 }
448
449 switch (sig.ssi_signo) {
450 case SIGCHLD:
451 pid = waitpid(-1, &status, 0);
452 if (pid == wl->child) {
453 wl->child = 0;
Philipp Brüschweiler7a3ec742013-03-10 15:14:01 +0100454 if (WIFEXITED(status))
455 ret = WEXITSTATUS(status);
456 else if (WIFSIGNALED(status))
457 /*
458 * If weston dies because of signal N, we
459 * return 10+N. This is distinct from
460 * weston-launch dying because of a signal
461 * (128+N).
462 */
463 ret = 10 + WTERMSIG(status);
464 else
465 ret = 0;
466 quit(wl, ret);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100467 }
468 break;
469 case SIGTERM:
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100470 case SIGINT:
471 if (wl->child)
Kristian Høgsberg1a81abb2013-06-17 15:23:20 -0400472 kill(wl->child, sig.ssi_signo);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100473 break;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700474 case SIGUSR1:
475 send_reply(wl, WESTON_LAUNCHER_DEACTIVATE);
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -0700476 close_input_fds(wl);
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700477 drmDropMaster(wl->drm_fd);
478 ioctl(wl->tty, VT_RELDISP, 1);
479 break;
480 case SIGUSR2:
481 ioctl(wl->tty, VT_RELDISP, VT_ACKACQ);
482 drmSetMaster(wl->drm_fd);
483 send_reply(wl, WESTON_LAUNCHER_ACTIVATE);
484 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100485 default:
486 return -1;
487 }
488
489 return 0;
490}
491
492static int
493setup_tty(struct weston_launch *wl, const char *tty)
494{
495 struct stat buf;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700496 struct vt_mode mode = { 0 };
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100497 char *t;
498
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700499 if (!wl->new_user) {
500 wl->tty = STDIN_FILENO;
501 } else if (tty) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100502 t = ttyname(STDIN_FILENO);
503 if (t && strcmp(t, tty) == 0)
504 wl->tty = STDIN_FILENO;
505 else
506 wl->tty = open(tty, O_RDWR | O_NOCTTY);
507 } else {
508 int tty0 = open("/dev/tty0", O_WRONLY | O_CLOEXEC);
509 char filename[16];
510
511 if (tty0 < 0)
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300512 error(1, errno, "could not open tty0");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100513
514 if (ioctl(tty0, VT_OPENQRY, &wl->ttynr) < 0 || wl->ttynr == -1)
515 error(1, errno, "failed to find non-opened console");
516
517 snprintf(filename, sizeof filename, "/dev/tty%d", wl->ttynr);
518 wl->tty = open(filename, O_RDWR | O_NOCTTY);
519 close(tty0);
520 }
521
522 if (wl->tty < 0)
523 error(1, errno, "failed to open tty");
524
Kristian Høgsberge05f2282013-10-02 13:06:02 -0700525 if (fstat(wl->tty, &buf) == -1 ||
526 major(buf.st_rdev) != TTY_MAJOR || minor(buf.st_rdev) == 0)
527 error(1, 0, "weston-launch must be run from a virtual terminal");
528
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100529 if (tty) {
530 if (fstat(wl->tty, &buf) < 0)
531 error(1, errno, "stat %s failed", tty);
532
533 if (major(buf.st_rdev) != TTY_MAJOR)
534 error(1, 0, "invalid tty device: %s", tty);
535
536 wl->ttynr = minor(buf.st_rdev);
537 }
538
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700539 if (ioctl(wl->tty, KDGKBMODE, &wl->kb_mode))
540 error(1, errno, "failed to get current keyboard mode: %m\n");
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700541
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700542 if (ioctl(wl->tty, KDSKBMUTE, 1) &&
543 ioctl(wl->tty, KDSKBMODE, K_OFF))
544 error(1, errno, "failed to set K_OFF keyboard mode: %m\n");
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700545
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700546 if (ioctl(wl->tty, KDSETMODE, KD_GRAPHICS))
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700547 error(1, errno, "failed to set KD_GRAPHICS mode on tty: %m\n");
548
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700549 mode.mode = VT_PROCESS;
550 mode.relsig = SIGUSR1;
551 mode.acqsig = SIGUSR2;
552 if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
553 error(1, errno, "failed to take control of vt handling\n");
554
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100555 return 0;
556}
557
558static void
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700559setup_session(struct weston_launch *wl)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700560{
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700561 char **env;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700562 char *term;
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700563 int i;
564
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700565 if (wl->tty != STDIN_FILENO) {
566 if (setsid() < 0)
567 error(1, errno, "setsid failed");
568 if (ioctl(wl->tty, TIOCSCTTY, 0) < 0)
569 error(1, errno, "TIOCSCTTY failed - tty is in use");
570 }
571
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700572 term = getenv("TERM");
573 clearenv();
Rob Bradford7ac9f732013-08-09 11:30:38 +0100574 if (term)
575 setenv("TERM", term, 1);
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700576 setenv("USER", wl->pw->pw_name, 1);
577 setenv("LOGNAME", wl->pw->pw_name, 1);
578 setenv("HOME", wl->pw->pw_dir, 1);
579 setenv("SHELL", wl->pw->pw_shell, 1);
580
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700581 env = pam_getenvlist(wl->ph);
582 if (env) {
583 for (i = 0; env[i]; ++i) {
584 if (putenv(env[i]) < 0)
585 error(0, 0, "putenv %s failed", env[i]);
586 }
587 free(env);
588 }
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700589}
590
591static void
Peter Hutterer34be0602013-08-06 12:10:09 +1000592drop_privileges(struct weston_launch *wl)
593{
594 if (setgid(wl->pw->pw_gid) < 0 ||
595#ifdef HAVE_INITGROUPS
596 initgroups(wl->pw->pw_name, wl->pw->pw_gid) < 0 ||
597#endif
598 setuid(wl->pw->pw_uid) < 0)
599 error(1, errno, "dropping privileges failed");
600}
601
602static void
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700603launch_compositor(struct weston_launch *wl, int argc, char *argv[])
604{
605 char *child_argv[MAX_ARGV_SIZE];
Eduardo Limad0357bb2013-07-30 10:43:41 -0700606 sigset_t mask;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700607 int i;
608
609 if (wl->verbose)
610 printf("weston-launch: spawned weston with pid: %d\n", getpid());
611 if (wl->new_user)
612 setup_session(wl);
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700613
Tomeu Vizosod7865b22013-10-01 12:20:29 +0200614 if (geteuid() == 0)
615 drop_privileges(wl);
Peter Hutterer34be0602013-08-06 12:10:09 +1000616
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700617 setenv_fd("WESTON_TTY_FD", wl->tty);
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700618 setenv_fd("WESTON_LAUNCHER_SOCK", wl->sock[1]);
619
620 unsetenv("DISPLAY");
621
Kristian Høgsberg73c60ab2013-07-30 09:45:04 -0700622 /* Do not give our signal mask to the new process. */
623 sigemptyset(&mask);
624 sigaddset(&mask, SIGTERM);
625 sigaddset(&mask, SIGCHLD);
626 sigaddset(&mask, SIGINT);
627 sigprocmask(SIG_UNBLOCK, &mask, NULL);
628
Kristian Høgsbergfb08e4b2013-10-21 15:14:44 -0700629 child_argv[0] = "/bin/sh";
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700630 child_argv[1] = "-l";
631 child_argv[2] = "-c";
632 child_argv[3] = BINDIR "/weston \"$@\"";
633 child_argv[4] = "weston";
634 for (i = 0; i < argc; ++i)
635 child_argv[5 + i] = argv[i];
636 child_argv[5 + i] = NULL;
637
638 execv(child_argv[0], child_argv);
639 error(1, errno, "exec failed");
640}
641
642static void
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100643help(const char *name)
644{
645 fprintf(stderr, "Usage: %s [args...] [-- [weston args..]]\n", name);
646 fprintf(stderr, " -u, --user Start session as specified username\n");
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300647 fprintf(stderr, " -t, --tty Start session on alternative tty\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100648 fprintf(stderr, " -v, --verbose Be verbose\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100649 fprintf(stderr, " -h, --help Display this help message\n");
650}
651
652int
653main(int argc, char *argv[])
654{
655 struct weston_launch wl;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100656 int i, c;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700657 char *tty = NULL;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100658 struct option opts[] = {
659 { "user", required_argument, NULL, 'u' },
660 { "tty", required_argument, NULL, 't' },
661 { "verbose", no_argument, NULL, 'v' },
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100662 { "help", no_argument, NULL, 'h' },
663 { 0, 0, NULL, 0 }
664 };
665
666 memset(&wl, 0, sizeof wl);
667
Kristian Høgsbergab499942013-07-19 21:26:24 -0700668 while ((c = getopt_long(argc, argv, "u:t::vh", opts, &i)) != -1) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100669 switch (c) {
670 case 'u':
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700671 wl.new_user = optarg;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100672 if (getuid() != 0)
673 error(1, 0, "Permission denied. -u allowed for root only");
674 break;
675 case 't':
676 tty = optarg;
677 break;
678 case 'v':
679 wl.verbose = 1;
680 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100681 case 'h':
Scott Moreaucc9acfc2013-01-21 23:40:59 -0700682 help("weston-launch");
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530683 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100684 }
685 }
686
Ander Conselvan de Oliveira9bdfc482013-05-22 22:55:33 +0300687 if ((argc - optind) > (MAX_ARGV_SIZE - 6))
Quentin Glidicff323092013-05-17 16:20:37 +0200688 error(1, E2BIG, "Too many arguments to pass to weston");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100689
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700690 if (wl.new_user)
691 wl.pw = getpwnam(wl.new_user);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100692 else
693 wl.pw = getpwuid(getuid());
694 if (wl.pw == NULL)
695 error(1, errno, "failed to get username");
696
697 if (!weston_launch_allowed(&wl))
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300698 error(1, 0, "Permission denied. You should either:\n"
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100699#ifdef HAVE_SYSTEMD_LOGIN
700 " - run from an active and local (systemd) session.\n"
701#else
702 " - enable systemd session support for weston-launch.\n"
703#endif
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300704 " - or add yourself to the 'weston-launch' group.");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100705
706 if (setup_tty(&wl, tty) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530707 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100708
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700709 if (wl.new_user && setup_pam(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530710 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100711
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100712 if (setup_launcher_socket(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530713 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100714
715 if (setup_signals(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530716 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100717
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700718 wl.child = fork();
719 if (wl.child == -1) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100720 error(1, errno, "fork failed");
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700721 exit(EXIT_FAILURE);
722 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100723
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700724 if (wl.child == 0)
725 launch_compositor(&wl, argc - optind, argv + optind);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100726
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700727 close(wl.sock[1]);
728 if (wl.tty != STDIN_FILENO)
729 close(wl.tty);
Quentin Glidic735302e2013-06-19 15:27:11 +0200730
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700731 while (1) {
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700732 struct pollfd fds[2];
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700733 int n;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100734
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700735 fds[0].fd = wl.sock[0];
736 fds[0].events = POLLIN;
737 fds[1].fd = wl.signalfd;
738 fds[1].events = POLLIN;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100739
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700740 n = poll(fds, 2, -1);
741 if (n < 0)
742 error(0, errno, "poll failed");
743 if (fds[0].revents & POLLIN)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700744 handle_socket_msg(&wl);
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700745 if (fds[1].revents)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700746 handle_signal(&wl);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100747 }
748
749 return 0;
750}