blob: 56e22b100d8344cea20e8fb18fcacda829c1cb76 [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
Benjamin Franzkebfeda132012-01-30 14:04:04 +010053#ifdef HAVE_SYSTEMD_LOGIN
54#include <systemd/sd-login.h>
55#endif
56
57#include "weston-launch.h"
58
Kristian Høgsberg1ff51092013-09-17 14:03:42 -070059#define DRM_MAJOR 226
60
Kristian Høgsberg3f495872013-09-18 23:00:17 -070061#ifndef KDSKBMUTE
62#define KDSKBMUTE 0x4B51
63#endif
64
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -070065#ifndef EVIOCREVOKE
66#define EVIOCREVOKE _IOW('E', 0x91, int)
67#endif
68
Quentin Glidicff323092013-05-17 16:20:37 +020069#define MAX_ARGV_SIZE 256
70
Kristian Høgsbergd2c9d8a2013-11-24 14:37:07 -080071#ifdef HAVE_LIBDRM
72
73#include <xf86drm.h>
74
75#else
76
77static inline int
78drmDropMaster(int drm_fd)
79{
80 return 0;
81}
82
83static inline int
84drmSetMaster(int drm_fd)
85{
86 return 0;
87}
88
89#endif
90
Benjamin Franzkebfeda132012-01-30 14:04:04 +010091struct weston_launch {
92 struct pam_conv pc;
93 pam_handle_t *ph;
94 int tty;
95 int ttynr;
96 int sock[2];
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -070097 int drm_fd;
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -070098 int last_input_fd;
Kristian Høgsberg81b49632013-09-17 22:43:22 -070099 int kb_mode;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100100 struct passwd *pw;
101
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100102 int signalfd;
103
104 pid_t child;
105 int verbose;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700106 char *new_user;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100107};
108
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400109union cmsg_data { unsigned char b[4]; int fd; };
110
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100111static gid_t *
112read_groups(void)
113{
114 int n;
115 gid_t *groups;
116
117 n = getgroups(0, NULL);
Rob Bradford40be7b42012-12-05 18:47:11 +0000118
119 if (n < 0) {
120 fprintf(stderr, "Unable to retrieve groups: %m\n");
121 return NULL;
122 }
123
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100124 groups = malloc(n * sizeof(gid_t));
125 if (!groups)
126 return NULL;
127
128 if (getgroups(n, groups) < 0) {
Rob Bradford40be7b42012-12-05 18:47:11 +0000129 fprintf(stderr, "Unable to retrieve groups: %m\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100130 free(groups);
131 return NULL;
132 }
133 return groups;
134}
135
136static int
137weston_launch_allowed(struct weston_launch *wl)
138{
139 struct group *gr;
140 gid_t *groups;
141 int i;
142#ifdef HAVE_SYSTEMD_LOGIN
143 char *session, *seat;
144 int err;
145#endif
146
147 if (getuid() == 0)
148 return 1;
149
150 gr = getgrnam("weston-launch");
151 if (gr) {
152 groups = read_groups();
153 if (groups) {
154 for (i = 0; groups[i]; ++i) {
155 if (groups[i] == gr->gr_gid) {
156 free(groups);
157 return 1;
158 }
159 }
160 free(groups);
161 }
162 }
163
164#ifdef HAVE_SYSTEMD_LOGIN
165 err = sd_pid_get_session(getpid(), &session);
166 if (err == 0 && session) {
167 if (sd_session_is_active(session) &&
168 sd_session_get_seat(session, &seat) == 0) {
169 free(seat);
170 free(session);
171 return 1;
172 }
173 free(session);
174 }
175#endif
176
177 return 0;
178}
179
180static int
181pam_conversation_fn(int msg_count,
182 const struct pam_message **messages,
183 struct pam_response **responses,
184 void *user_data)
185{
186 return PAM_SUCCESS;
187}
188
189static int
190setup_pam(struct weston_launch *wl)
191{
192 int err;
193
194 wl->pc.conv = pam_conversation_fn;
195 wl->pc.appdata_ptr = wl;
196
197 err = pam_start("login", wl->pw->pw_name, &wl->pc, &wl->ph);
John Kåre Alsaker5b90d8f2012-10-12 12:25:05 +0200198 if (err != PAM_SUCCESS) {
199 fprintf(stderr, "failed to start pam transaction: %d: %s\n",
200 err, pam_strerror(wl->ph, err));
201 return -1;
202 }
203
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100204 err = pam_set_item(wl->ph, PAM_TTY, ttyname(wl->tty));
205 if (err != PAM_SUCCESS) {
206 fprintf(stderr, "failed to set PAM_TTY item: %d: %s\n",
207 err, pam_strerror(wl->ph, err));
208 return -1;
209 }
210
211 err = pam_open_session(wl->ph, 0);
212 if (err != PAM_SUCCESS) {
213 fprintf(stderr, "failed to open pam session: %d: %s\n",
214 err, pam_strerror(wl->ph, err));
215 return -1;
216 }
217
218 return 0;
219}
220
221static int
222setup_launcher_socket(struct weston_launch *wl)
223{
Kristian Høgsbergbf3c3742013-09-18 11:01:48 -0700224 if (socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, wl->sock) < 0)
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100225 error(1, errno, "socketpair failed");
226
Kristian Høgsbergf45b1e82013-09-18 11:00:56 -0700227 if (fcntl(wl->sock[0], F_SETFD, FD_CLOEXEC) < 0)
228 error(1, errno, "fcntl failed");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100229
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100230 return 0;
231}
232
233static int
234setup_signals(struct weston_launch *wl)
235{
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100236 int ret;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100237 sigset_t mask;
238 struct sigaction sa;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100239
240 memset(&sa, 0, sizeof sa);
241 sa.sa_handler = SIG_DFL;
242 sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100243 ret = sigaction(SIGCHLD, &sa, NULL);
244 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100245
Kristian Høgsberg18684d42013-07-22 11:59:18 -0700246 sa.sa_handler = SIG_IGN;
247 sa.sa_flags = 0;
248 sigaction(SIGHUP, &sa, NULL);
249
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100250 ret = sigemptyset(&mask);
251 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100252 sigaddset(&mask, SIGCHLD);
253 sigaddset(&mask, SIGINT);
254 sigaddset(&mask, SIGTERM);
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700255 sigaddset(&mask, SIGUSR1);
256 sigaddset(&mask, SIGUSR2);
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100257 ret = sigprocmask(SIG_BLOCK, &mask, NULL);
258 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100259
260 wl->signalfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
261 if (wl->signalfd < 0)
262 return -errno;
263
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100264 return 0;
265}
266
267static void
268setenv_fd(const char *env, int fd)
269{
270 char buf[32];
271
272 snprintf(buf, sizeof buf, "%d", fd);
273 setenv(env, buf, 1);
274}
275
276static int
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700277send_reply(struct weston_launch *wl, int reply)
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100278{
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700279 int len;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100280
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100281 do {
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700282 len = send(wl->sock[0], &reply, sizeof reply, 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100283 } while (len < 0 && errno == EINTR);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100284
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700285 return len;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100286}
287
288static int
289handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
290{
291 int fd = -1, ret = -1;
292 char control[CMSG_SPACE(sizeof(fd))];
293 struct cmsghdr *cmsg;
294 struct stat s;
295 struct msghdr nmsg;
296 struct iovec iov;
297 struct weston_launcher_open *message;
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400298 union cmsg_data *data;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100299
300 message = msg->msg_iov->iov_base;
301 if ((size_t)len < sizeof(*message))
302 goto err0;
303
304 /* Ensure path is null-terminated */
305 ((char *) message)[len-1] = '\0';
306
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100307 fd = open(message->path, message->flags);
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100308 if (fd < 0) {
309 fprintf(stderr, "Error opening device %s: %m\n",
310 message->path);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100311 goto err0;
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100312 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100313
Kristian Høgsberg6a7c8492013-09-18 22:14:09 -0700314 if (fstat(fd, &s) < 0) {
315 close(fd);
316 fd = -1;
317 fprintf(stderr, "Failed to stat %s\n", message->path);
318 goto err0;
319 }
320
Kristian Høgsberg1ff51092013-09-17 14:03:42 -0700321 if (major(s.st_rdev) != INPUT_MAJOR &&
322 major(s.st_rdev) != DRM_MAJOR) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100323 close(fd);
324 fd = -1;
Kristian Høgsberg1ff51092013-09-17 14:03:42 -0700325 fprintf(stderr, "Device %s is not an input or drm device\n",
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100326 message->path);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100327 goto err0;
328 }
329
330err0:
331 memset(&nmsg, 0, sizeof nmsg);
332 nmsg.msg_iov = &iov;
333 nmsg.msg_iovlen = 1;
334 if (fd != -1) {
335 nmsg.msg_control = control;
336 nmsg.msg_controllen = sizeof control;
337 cmsg = CMSG_FIRSTHDR(&nmsg);
338 cmsg->cmsg_level = SOL_SOCKET;
339 cmsg->cmsg_type = SCM_RIGHTS;
340 cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400341 data = (union cmsg_data *) CMSG_DATA(cmsg);
342 data->fd = fd;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100343 nmsg.msg_controllen = cmsg->cmsg_len;
344 ret = 0;
345 }
346 iov.iov_base = &ret;
347 iov.iov_len = sizeof ret;
348
349 if (wl->verbose)
350 fprintf(stderr, "weston-launch: opened %s: ret: %d, fd: %d\n",
351 message->path, ret, fd);
352 do {
353 len = sendmsg(wl->sock[0], &nmsg, 0);
354 } while (len < 0 && errno == EINTR);
355
356 if (len < 0)
357 return -1;
358
Kristian Høgsbergaf393dc2013-10-09 11:25:14 -0700359 if (fd != -1 && major(s.st_rdev) == DRM_MAJOR)
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700360 wl->drm_fd = fd;
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -0700361 if (fd != -1 && major(s.st_rdev) == INPUT_MAJOR &&
362 wl->last_input_fd < fd)
363 wl->last_input_fd = fd;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700364
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100365 return 0;
366}
367
368static int
369handle_socket_msg(struct weston_launch *wl)
370{
371 char control[CMSG_SPACE(sizeof(int))];
372 char buf[BUFSIZ];
373 struct msghdr msg;
374 struct iovec iov;
375 int ret = -1;
376 ssize_t len;
377 struct weston_launcher_message *message;
378
379 memset(&msg, 0, sizeof(msg));
380 iov.iov_base = buf;
381 iov.iov_len = sizeof buf;
382 msg.msg_iov = &iov;
383 msg.msg_iovlen = 1;
384 msg.msg_control = control;
385 msg.msg_controllen = sizeof control;
386
387 do {
388 len = recvmsg(wl->sock[0], &msg, 0);
389 } while (len < 0 && errno == EINTR);
390
391 if (len < 1)
392 return -1;
393
394 message = (void *) buf;
395 switch (message->opcode) {
396 case WESTON_LAUNCHER_OPEN:
397 ret = handle_open(wl, &msg, len);
398 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100399 }
400
401 return ret;
402}
403
404static void
405quit(struct weston_launch *wl, int status)
406{
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700407 struct vt_mode mode = { 0 };
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100408 int err;
409
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100410 close(wl->signalfd);
411 close(wl->sock[0]);
412
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700413 if (wl->new_user) {
414 err = pam_close_session(wl->ph, 0);
415 if (err)
416 fprintf(stderr, "pam_close_session failed: %d: %s\n",
417 err, pam_strerror(wl->ph, err));
418 pam_end(wl->ph, err);
419 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100420
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700421 if (ioctl(wl->tty, KDSKBMUTE, 0) &&
422 ioctl(wl->tty, KDSKBMODE, wl->kb_mode))
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700423 fprintf(stderr, "failed to restore keyboard mode: %m\n");
424
425 if (ioctl(wl->tty, KDSETMODE, KD_TEXT))
426 fprintf(stderr, "failed to set KD_TEXT mode on tty: %m\n");
427
Kristian Høgsberga28ba552013-10-30 16:27:16 -0700428 /* We have to drop master before we switch the VT back in
429 * VT_AUTO, so we don't risk switching to a VT with another
430 * display server, that will then fail to set drm master. */
431 drmDropMaster(wl->drm_fd);
432
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700433 mode.mode = VT_AUTO;
434 if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
435 fprintf(stderr, "could not reset vt handling\n");
436
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100437 exit(status);
438}
439
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -0700440static void
441close_input_fds(struct weston_launch *wl)
442{
443 struct stat s;
444 int fd;
445
446 for (fd = 3; fd <= wl->last_input_fd; fd++) {
447 if (fstat(fd, &s) == 0 && major(s.st_rdev) == INPUT_MAJOR) {
448 /* EVIOCREVOKE may fail if the kernel doesn't
449 * support it, but all we can do is ignore it. */
450 ioctl(fd, EVIOCREVOKE, 0);
451 close(fd);
452 }
453 }
454}
455
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100456static int
457handle_signal(struct weston_launch *wl)
458{
459 struct signalfd_siginfo sig;
Philipp Brüschweiler7a3ec742013-03-10 15:14:01 +0100460 int pid, status, ret;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100461
462 if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) {
463 error(0, errno, "reading signalfd failed");
464 return -1;
465 }
466
467 switch (sig.ssi_signo) {
468 case SIGCHLD:
469 pid = waitpid(-1, &status, 0);
470 if (pid == wl->child) {
471 wl->child = 0;
Philipp Brüschweiler7a3ec742013-03-10 15:14:01 +0100472 if (WIFEXITED(status))
473 ret = WEXITSTATUS(status);
474 else if (WIFSIGNALED(status))
475 /*
476 * If weston dies because of signal N, we
477 * return 10+N. This is distinct from
478 * weston-launch dying because of a signal
479 * (128+N).
480 */
481 ret = 10 + WTERMSIG(status);
482 else
483 ret = 0;
484 quit(wl, ret);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100485 }
486 break;
487 case SIGTERM:
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100488 case SIGINT:
489 if (wl->child)
Kristian Høgsberg1a81abb2013-06-17 15:23:20 -0400490 kill(wl->child, sig.ssi_signo);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100491 break;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700492 case SIGUSR1:
493 send_reply(wl, WESTON_LAUNCHER_DEACTIVATE);
Kristian Høgsberg0eee0a22013-10-25 13:34:58 -0700494 close_input_fds(wl);
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700495 drmDropMaster(wl->drm_fd);
496 ioctl(wl->tty, VT_RELDISP, 1);
497 break;
498 case SIGUSR2:
499 ioctl(wl->tty, VT_RELDISP, VT_ACKACQ);
500 drmSetMaster(wl->drm_fd);
501 send_reply(wl, WESTON_LAUNCHER_ACTIVATE);
502 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100503 default:
504 return -1;
505 }
506
507 return 0;
508}
509
510static int
511setup_tty(struct weston_launch *wl, const char *tty)
512{
513 struct stat buf;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700514 struct vt_mode mode = { 0 };
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100515 char *t;
516
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700517 if (!wl->new_user) {
518 wl->tty = STDIN_FILENO;
519 } else if (tty) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100520 t = ttyname(STDIN_FILENO);
521 if (t && strcmp(t, tty) == 0)
522 wl->tty = STDIN_FILENO;
523 else
524 wl->tty = open(tty, O_RDWR | O_NOCTTY);
525 } else {
526 int tty0 = open("/dev/tty0", O_WRONLY | O_CLOEXEC);
527 char filename[16];
528
529 if (tty0 < 0)
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300530 error(1, errno, "could not open tty0");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100531
532 if (ioctl(tty0, VT_OPENQRY, &wl->ttynr) < 0 || wl->ttynr == -1)
533 error(1, errno, "failed to find non-opened console");
534
535 snprintf(filename, sizeof filename, "/dev/tty%d", wl->ttynr);
536 wl->tty = open(filename, O_RDWR | O_NOCTTY);
537 close(tty0);
538 }
539
540 if (wl->tty < 0)
541 error(1, errno, "failed to open tty");
542
Kristian Høgsberge05f2282013-10-02 13:06:02 -0700543 if (fstat(wl->tty, &buf) == -1 ||
544 major(buf.st_rdev) != TTY_MAJOR || minor(buf.st_rdev) == 0)
545 error(1, 0, "weston-launch must be run from a virtual terminal");
546
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100547 if (tty) {
548 if (fstat(wl->tty, &buf) < 0)
549 error(1, errno, "stat %s failed", tty);
550
551 if (major(buf.st_rdev) != TTY_MAJOR)
552 error(1, 0, "invalid tty device: %s", tty);
553
554 wl->ttynr = minor(buf.st_rdev);
555 }
556
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700557 if (ioctl(wl->tty, KDGKBMODE, &wl->kb_mode))
558 error(1, errno, "failed to get current keyboard mode: %m\n");
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700559
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700560 if (ioctl(wl->tty, KDSKBMUTE, 1) &&
561 ioctl(wl->tty, KDSKBMODE, K_OFF))
562 error(1, errno, "failed to set K_OFF 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, KDSETMODE, KD_GRAPHICS))
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700565 error(1, errno, "failed to set KD_GRAPHICS mode on tty: %m\n");
566
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700567 mode.mode = VT_PROCESS;
568 mode.relsig = SIGUSR1;
569 mode.acqsig = SIGUSR2;
570 if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
571 error(1, errno, "failed to take control of vt handling\n");
572
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100573 return 0;
574}
575
576static void
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700577setup_session(struct weston_launch *wl)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700578{
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700579 char **env;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700580 char *term;
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700581 int i;
582
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700583 if (wl->tty != STDIN_FILENO) {
584 if (setsid() < 0)
585 error(1, errno, "setsid failed");
586 if (ioctl(wl->tty, TIOCSCTTY, 0) < 0)
587 error(1, errno, "TIOCSCTTY failed - tty is in use");
588 }
589
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700590 term = getenv("TERM");
591 clearenv();
Rob Bradford7ac9f732013-08-09 11:30:38 +0100592 if (term)
593 setenv("TERM", term, 1);
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700594 setenv("USER", wl->pw->pw_name, 1);
595 setenv("LOGNAME", wl->pw->pw_name, 1);
596 setenv("HOME", wl->pw->pw_dir, 1);
597 setenv("SHELL", wl->pw->pw_shell, 1);
598
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700599 env = pam_getenvlist(wl->ph);
600 if (env) {
601 for (i = 0; env[i]; ++i) {
602 if (putenv(env[i]) < 0)
603 error(0, 0, "putenv %s failed", env[i]);
604 }
605 free(env);
606 }
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700607}
608
609static void
Peter Hutterer34be0602013-08-06 12:10:09 +1000610drop_privileges(struct weston_launch *wl)
611{
612 if (setgid(wl->pw->pw_gid) < 0 ||
613#ifdef HAVE_INITGROUPS
614 initgroups(wl->pw->pw_name, wl->pw->pw_gid) < 0 ||
615#endif
616 setuid(wl->pw->pw_uid) < 0)
617 error(1, errno, "dropping privileges failed");
618}
619
620static void
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700621launch_compositor(struct weston_launch *wl, int argc, char *argv[])
622{
623 char *child_argv[MAX_ARGV_SIZE];
Eduardo Limad0357bb2013-07-30 10:43:41 -0700624 sigset_t mask;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700625 int i;
626
627 if (wl->verbose)
628 printf("weston-launch: spawned weston with pid: %d\n", getpid());
629 if (wl->new_user)
630 setup_session(wl);
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700631
Tomeu Vizosod7865b22013-10-01 12:20:29 +0200632 if (geteuid() == 0)
633 drop_privileges(wl);
Peter Hutterer34be0602013-08-06 12:10:09 +1000634
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700635 setenv_fd("WESTON_TTY_FD", wl->tty);
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700636 setenv_fd("WESTON_LAUNCHER_SOCK", wl->sock[1]);
637
638 unsetenv("DISPLAY");
639
Kristian Høgsberg73c60ab2013-07-30 09:45:04 -0700640 /* Do not give our signal mask to the new process. */
641 sigemptyset(&mask);
642 sigaddset(&mask, SIGTERM);
643 sigaddset(&mask, SIGCHLD);
644 sigaddset(&mask, SIGINT);
645 sigprocmask(SIG_UNBLOCK, &mask, NULL);
646
Kristian Høgsbergfb08e4b2013-10-21 15:14:44 -0700647 child_argv[0] = "/bin/sh";
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700648 child_argv[1] = "-l";
649 child_argv[2] = "-c";
650 child_argv[3] = BINDIR "/weston \"$@\"";
651 child_argv[4] = "weston";
652 for (i = 0; i < argc; ++i)
653 child_argv[5 + i] = argv[i];
654 child_argv[5 + i] = NULL;
655
656 execv(child_argv[0], child_argv);
657 error(1, errno, "exec failed");
658}
659
660static void
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100661help(const char *name)
662{
663 fprintf(stderr, "Usage: %s [args...] [-- [weston args..]]\n", name);
664 fprintf(stderr, " -u, --user Start session as specified username\n");
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300665 fprintf(stderr, " -t, --tty Start session on alternative tty\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100666 fprintf(stderr, " -v, --verbose Be verbose\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100667 fprintf(stderr, " -h, --help Display this help message\n");
668}
669
670int
671main(int argc, char *argv[])
672{
673 struct weston_launch wl;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100674 int i, c;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700675 char *tty = NULL;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100676 struct option opts[] = {
677 { "user", required_argument, NULL, 'u' },
678 { "tty", required_argument, NULL, 't' },
679 { "verbose", no_argument, NULL, 'v' },
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100680 { "help", no_argument, NULL, 'h' },
681 { 0, 0, NULL, 0 }
682 };
683
684 memset(&wl, 0, sizeof wl);
685
Kristian Høgsbergab499942013-07-19 21:26:24 -0700686 while ((c = getopt_long(argc, argv, "u:t::vh", opts, &i)) != -1) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100687 switch (c) {
688 case 'u':
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700689 wl.new_user = optarg;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100690 if (getuid() != 0)
691 error(1, 0, "Permission denied. -u allowed for root only");
692 break;
693 case 't':
694 tty = optarg;
695 break;
696 case 'v':
697 wl.verbose = 1;
698 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100699 case 'h':
Scott Moreaucc9acfc2013-01-21 23:40:59 -0700700 help("weston-launch");
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530701 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100702 }
703 }
704
Ander Conselvan de Oliveira9bdfc482013-05-22 22:55:33 +0300705 if ((argc - optind) > (MAX_ARGV_SIZE - 6))
Quentin Glidicff323092013-05-17 16:20:37 +0200706 error(1, E2BIG, "Too many arguments to pass to weston");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100707
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700708 if (wl.new_user)
709 wl.pw = getpwnam(wl.new_user);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100710 else
711 wl.pw = getpwuid(getuid());
712 if (wl.pw == NULL)
713 error(1, errno, "failed to get username");
714
715 if (!weston_launch_allowed(&wl))
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300716 error(1, 0, "Permission denied. You should either:\n"
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100717#ifdef HAVE_SYSTEMD_LOGIN
718 " - run from an active and local (systemd) session.\n"
719#else
720 " - enable systemd session support for weston-launch.\n"
721#endif
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300722 " - or add yourself to the 'weston-launch' group.");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100723
724 if (setup_tty(&wl, tty) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530725 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100726
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700727 if (wl.new_user && setup_pam(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530728 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100729
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100730 if (setup_launcher_socket(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530731 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100732
733 if (setup_signals(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530734 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100735
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700736 wl.child = fork();
737 if (wl.child == -1) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100738 error(1, errno, "fork failed");
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700739 exit(EXIT_FAILURE);
740 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100741
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700742 if (wl.child == 0)
743 launch_compositor(&wl, argc - optind, argv + optind);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100744
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700745 close(wl.sock[1]);
746 if (wl.tty != STDIN_FILENO)
747 close(wl.tty);
Quentin Glidic735302e2013-06-19 15:27:11 +0200748
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700749 while (1) {
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700750 struct pollfd fds[2];
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700751 int n;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100752
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700753 fds[0].fd = wl.sock[0];
754 fds[0].events = POLLIN;
755 fds[1].fd = wl.signalfd;
756 fds[1].events = POLLIN;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100757
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700758 n = poll(fds, 2, -1);
759 if (n < 0)
760 error(0, errno, "poll failed");
761 if (fds[0].revents & POLLIN)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700762 handle_socket_msg(&wl);
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700763 if (fds[1].revents)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700764 handle_signal(&wl);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100765 }
766
767 return 0;
768}