blob: 05f15c1d1841357f26e76abe43e2fdf034a26e89 [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>
Kristian Høgsberg81b49632013-09-17 22:43:22 -070031#include <termios.h>
Benjamin Franzkebfeda132012-01-30 14:04:04 +010032
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
46#include <termios.h>
47#include <linux/vt.h>
48#include <linux/major.h>
Kristian Høgsberg81b49632013-09-17 22:43:22 -070049#include <linux/kd.h>
Benjamin Franzkebfeda132012-01-30 14:04:04 +010050
51#include <pwd.h>
52#include <grp.h>
53#include <security/pam_appl.h>
54
55#include <xf86drm.h>
56
57#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
Quentin Glidicff323092013-05-17 16:20:37 +020065#define MAX_ARGV_SIZE 256
66
Benjamin Franzkebfeda132012-01-30 14:04:04 +010067struct weston_launch {
68 struct pam_conv pc;
69 pam_handle_t *ph;
70 int tty;
71 int ttynr;
72 int sock[2];
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -070073 int drm_fd;
Kristian Høgsberg81b49632013-09-17 22:43:22 -070074 struct termios terminal_attributes;
75 int kb_mode;
Benjamin Franzkebfeda132012-01-30 14:04:04 +010076 struct passwd *pw;
77
Benjamin Franzkebfeda132012-01-30 14:04:04 +010078 int signalfd;
79
80 pid_t child;
81 int verbose;
Kristian Høgsberg636156d2013-07-22 10:35:47 -070082 char *new_user;
Benjamin Franzkebfeda132012-01-30 14:04:04 +010083};
84
Kristian Høgsberg9e140912012-04-10 01:26:18 -040085union cmsg_data { unsigned char b[4]; int fd; };
86
Benjamin Franzkebfeda132012-01-30 14:04:04 +010087static gid_t *
88read_groups(void)
89{
90 int n;
91 gid_t *groups;
92
93 n = getgroups(0, NULL);
Rob Bradford40be7b42012-12-05 18:47:11 +000094
95 if (n < 0) {
96 fprintf(stderr, "Unable to retrieve groups: %m\n");
97 return NULL;
98 }
99
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100100 groups = malloc(n * sizeof(gid_t));
101 if (!groups)
102 return NULL;
103
104 if (getgroups(n, groups) < 0) {
Rob Bradford40be7b42012-12-05 18:47:11 +0000105 fprintf(stderr, "Unable to retrieve groups: %m\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100106 free(groups);
107 return NULL;
108 }
109 return groups;
110}
111
112static int
113weston_launch_allowed(struct weston_launch *wl)
114{
115 struct group *gr;
116 gid_t *groups;
117 int i;
118#ifdef HAVE_SYSTEMD_LOGIN
119 char *session, *seat;
120 int err;
121#endif
122
123 if (getuid() == 0)
124 return 1;
125
126 gr = getgrnam("weston-launch");
127 if (gr) {
128 groups = read_groups();
129 if (groups) {
130 for (i = 0; groups[i]; ++i) {
131 if (groups[i] == gr->gr_gid) {
132 free(groups);
133 return 1;
134 }
135 }
136 free(groups);
137 }
138 }
139
140#ifdef HAVE_SYSTEMD_LOGIN
141 err = sd_pid_get_session(getpid(), &session);
142 if (err == 0 && session) {
143 if (sd_session_is_active(session) &&
144 sd_session_get_seat(session, &seat) == 0) {
145 free(seat);
146 free(session);
147 return 1;
148 }
149 free(session);
150 }
151#endif
152
153 return 0;
154}
155
156static int
157pam_conversation_fn(int msg_count,
158 const struct pam_message **messages,
159 struct pam_response **responses,
160 void *user_data)
161{
162 return PAM_SUCCESS;
163}
164
165static int
166setup_pam(struct weston_launch *wl)
167{
168 int err;
169
170 wl->pc.conv = pam_conversation_fn;
171 wl->pc.appdata_ptr = wl;
172
173 err = pam_start("login", wl->pw->pw_name, &wl->pc, &wl->ph);
John Kåre Alsaker5b90d8f2012-10-12 12:25:05 +0200174 if (err != PAM_SUCCESS) {
175 fprintf(stderr, "failed to start pam transaction: %d: %s\n",
176 err, pam_strerror(wl->ph, err));
177 return -1;
178 }
179
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100180 err = pam_set_item(wl->ph, PAM_TTY, ttyname(wl->tty));
181 if (err != PAM_SUCCESS) {
182 fprintf(stderr, "failed to set PAM_TTY item: %d: %s\n",
183 err, pam_strerror(wl->ph, err));
184 return -1;
185 }
186
187 err = pam_open_session(wl->ph, 0);
188 if (err != PAM_SUCCESS) {
189 fprintf(stderr, "failed to open pam session: %d: %s\n",
190 err, pam_strerror(wl->ph, err));
191 return -1;
192 }
193
194 return 0;
195}
196
197static int
198setup_launcher_socket(struct weston_launch *wl)
199{
Kristian Høgsbergbf3c3742013-09-18 11:01:48 -0700200 if (socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, wl->sock) < 0)
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100201 error(1, errno, "socketpair failed");
202
Kristian Høgsbergf45b1e82013-09-18 11:00:56 -0700203 if (fcntl(wl->sock[0], F_SETFD, FD_CLOEXEC) < 0)
204 error(1, errno, "fcntl failed");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100205
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100206 return 0;
207}
208
209static int
210setup_signals(struct weston_launch *wl)
211{
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100212 int ret;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100213 sigset_t mask;
214 struct sigaction sa;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100215
216 memset(&sa, 0, sizeof sa);
217 sa.sa_handler = SIG_DFL;
218 sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100219 ret = sigaction(SIGCHLD, &sa, NULL);
220 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100221
Kristian Høgsberg18684d42013-07-22 11:59:18 -0700222 sa.sa_handler = SIG_IGN;
223 sa.sa_flags = 0;
224 sigaction(SIGHUP, &sa, NULL);
225
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100226 ret = sigemptyset(&mask);
227 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100228 sigaddset(&mask, SIGCHLD);
229 sigaddset(&mask, SIGINT);
230 sigaddset(&mask, SIGTERM);
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700231 sigaddset(&mask, SIGUSR1);
232 sigaddset(&mask, SIGUSR2);
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100233 ret = sigprocmask(SIG_BLOCK, &mask, NULL);
234 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100235
236 wl->signalfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
237 if (wl->signalfd < 0)
238 return -errno;
239
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100240 return 0;
241}
242
243static void
244setenv_fd(const char *env, int fd)
245{
246 char buf[32];
247
248 snprintf(buf, sizeof buf, "%d", fd);
249 setenv(env, buf, 1);
250}
251
252static int
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700253send_reply(struct weston_launch *wl, int reply)
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100254{
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700255 int len;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100256
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100257 do {
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700258 len = send(wl->sock[0], &reply, sizeof reply, 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100259 } while (len < 0 && errno == EINTR);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100260
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700261 return len;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100262}
263
264static int
265handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
266{
267 int fd = -1, ret = -1;
268 char control[CMSG_SPACE(sizeof(fd))];
269 struct cmsghdr *cmsg;
270 struct stat s;
271 struct msghdr nmsg;
272 struct iovec iov;
273 struct weston_launcher_open *message;
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400274 union cmsg_data *data;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100275
276 message = msg->msg_iov->iov_base;
277 if ((size_t)len < sizeof(*message))
278 goto err0;
279
280 /* Ensure path is null-terminated */
281 ((char *) message)[len-1] = '\0';
282
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100283 fd = open(message->path, message->flags);
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100284 if (fd < 0) {
285 fprintf(stderr, "Error opening device %s: %m\n",
286 message->path);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100287 goto err0;
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100288 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100289
Kristian Høgsberg6a7c8492013-09-18 22:14:09 -0700290 if (fstat(fd, &s) < 0) {
291 close(fd);
292 fd = -1;
293 fprintf(stderr, "Failed to stat %s\n", message->path);
294 goto err0;
295 }
296
Kristian Høgsberg1ff51092013-09-17 14:03:42 -0700297 if (major(s.st_rdev) != INPUT_MAJOR &&
298 major(s.st_rdev) != DRM_MAJOR) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100299 close(fd);
300 fd = -1;
Kristian Høgsberg1ff51092013-09-17 14:03:42 -0700301 fprintf(stderr, "Device %s is not an input or drm device\n",
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100302 message->path);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100303 goto err0;
304 }
305
306err0:
307 memset(&nmsg, 0, sizeof nmsg);
308 nmsg.msg_iov = &iov;
309 nmsg.msg_iovlen = 1;
310 if (fd != -1) {
311 nmsg.msg_control = control;
312 nmsg.msg_controllen = sizeof control;
313 cmsg = CMSG_FIRSTHDR(&nmsg);
314 cmsg->cmsg_level = SOL_SOCKET;
315 cmsg->cmsg_type = SCM_RIGHTS;
316 cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400317 data = (union cmsg_data *) CMSG_DATA(cmsg);
318 data->fd = fd;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100319 nmsg.msg_controllen = cmsg->cmsg_len;
320 ret = 0;
321 }
322 iov.iov_base = &ret;
323 iov.iov_len = sizeof ret;
324
325 if (wl->verbose)
326 fprintf(stderr, "weston-launch: opened %s: ret: %d, fd: %d\n",
327 message->path, ret, fd);
328 do {
329 len = sendmsg(wl->sock[0], &nmsg, 0);
330 } while (len < 0 && errno == EINTR);
331
332 if (len < 0)
333 return -1;
334
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700335 if (major(s.st_rdev) == DRM_MAJOR)
336 wl->drm_fd = fd;
337
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100338 return 0;
339}
340
341static int
342handle_socket_msg(struct weston_launch *wl)
343{
344 char control[CMSG_SPACE(sizeof(int))];
345 char buf[BUFSIZ];
346 struct msghdr msg;
347 struct iovec iov;
348 int ret = -1;
349 ssize_t len;
350 struct weston_launcher_message *message;
351
352 memset(&msg, 0, sizeof(msg));
353 iov.iov_base = buf;
354 iov.iov_len = sizeof buf;
355 msg.msg_iov = &iov;
356 msg.msg_iovlen = 1;
357 msg.msg_control = control;
358 msg.msg_controllen = sizeof control;
359
360 do {
361 len = recvmsg(wl->sock[0], &msg, 0);
362 } while (len < 0 && errno == EINTR);
363
364 if (len < 1)
365 return -1;
366
367 message = (void *) buf;
368 switch (message->opcode) {
369 case WESTON_LAUNCHER_OPEN:
370 ret = handle_open(wl, &msg, len);
371 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100372 }
373
374 return ret;
375}
376
377static void
378quit(struct weston_launch *wl, int status)
379{
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700380 struct vt_mode mode = { 0 };
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100381 int err;
382
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100383 close(wl->signalfd);
384 close(wl->sock[0]);
385
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700386 if (wl->new_user) {
387 err = pam_close_session(wl->ph, 0);
388 if (err)
389 fprintf(stderr, "pam_close_session failed: %d: %s\n",
390 err, pam_strerror(wl->ph, err));
391 pam_end(wl->ph, err);
392 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100393
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700394 if (ioctl(wl->tty, KDSKBMODE, wl->kb_mode))
395 fprintf(stderr, "failed to restore keyboard mode: %m\n");
396
397 if (ioctl(wl->tty, KDSETMODE, KD_TEXT))
398 fprintf(stderr, "failed to set KD_TEXT mode on tty: %m\n");
399
400 if (tcsetattr(wl->tty, TCSANOW, &wl->terminal_attributes) < 0)
401 fprintf(stderr,
402 "could not restore terminal to canonical mode\n");
403
404 mode.mode = VT_AUTO;
405 if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
406 fprintf(stderr, "could not reset vt handling\n");
407
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100408 exit(status);
409}
410
411static int
412handle_signal(struct weston_launch *wl)
413{
414 struct signalfd_siginfo sig;
Philipp Brüschweiler7a3ec742013-03-10 15:14:01 +0100415 int pid, status, ret;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100416
417 if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) {
418 error(0, errno, "reading signalfd failed");
419 return -1;
420 }
421
422 switch (sig.ssi_signo) {
423 case SIGCHLD:
424 pid = waitpid(-1, &status, 0);
425 if (pid == wl->child) {
426 wl->child = 0;
Philipp Brüschweiler7a3ec742013-03-10 15:14:01 +0100427 if (WIFEXITED(status))
428 ret = WEXITSTATUS(status);
429 else if (WIFSIGNALED(status))
430 /*
431 * If weston dies because of signal N, we
432 * return 10+N. This is distinct from
433 * weston-launch dying because of a signal
434 * (128+N).
435 */
436 ret = 10 + WTERMSIG(status);
437 else
438 ret = 0;
439 quit(wl, ret);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100440 }
441 break;
442 case SIGTERM:
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100443 case SIGINT:
444 if (wl->child)
Kristian Høgsberg1a81abb2013-06-17 15:23:20 -0400445 kill(wl->child, sig.ssi_signo);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100446 break;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700447 case SIGUSR1:
448 send_reply(wl, WESTON_LAUNCHER_DEACTIVATE);
449 drmDropMaster(wl->drm_fd);
450 ioctl(wl->tty, VT_RELDISP, 1);
451 break;
452 case SIGUSR2:
453 ioctl(wl->tty, VT_RELDISP, VT_ACKACQ);
454 drmSetMaster(wl->drm_fd);
455 send_reply(wl, WESTON_LAUNCHER_ACTIVATE);
456 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100457 default:
458 return -1;
459 }
460
461 return 0;
462}
463
464static int
465setup_tty(struct weston_launch *wl, const char *tty)
466{
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700467 struct termios raw_attributes;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100468 struct stat buf;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700469 struct vt_mode mode = { 0 };
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100470 char *t;
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700471 int ret;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100472
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700473 if (!wl->new_user) {
474 wl->tty = STDIN_FILENO;
475 } else if (tty) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100476 t = ttyname(STDIN_FILENO);
477 if (t && strcmp(t, tty) == 0)
478 wl->tty = STDIN_FILENO;
479 else
480 wl->tty = open(tty, O_RDWR | O_NOCTTY);
481 } else {
482 int tty0 = open("/dev/tty0", O_WRONLY | O_CLOEXEC);
483 char filename[16];
484
485 if (tty0 < 0)
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300486 error(1, errno, "could not open tty0");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100487
488 if (ioctl(tty0, VT_OPENQRY, &wl->ttynr) < 0 || wl->ttynr == -1)
489 error(1, errno, "failed to find non-opened console");
490
491 snprintf(filename, sizeof filename, "/dev/tty%d", wl->ttynr);
492 wl->tty = open(filename, O_RDWR | O_NOCTTY);
493 close(tty0);
494 }
495
496 if (wl->tty < 0)
497 error(1, errno, "failed to open tty");
498
499 if (tty) {
500 if (fstat(wl->tty, &buf) < 0)
501 error(1, errno, "stat %s failed", tty);
502
503 if (major(buf.st_rdev) != TTY_MAJOR)
504 error(1, 0, "invalid tty device: %s", tty);
505
506 wl->ttynr = minor(buf.st_rdev);
507 }
508
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700509 if (tcgetattr(wl->tty, &wl->terminal_attributes) < 0)
510 error(1, errno, "could not get terminal attributes: %m\n");
511
512 /* Ignore control characters and disable echo */
513 raw_attributes = wl->terminal_attributes;
514 cfmakeraw(&raw_attributes);
515
516 /* Fix up line endings to be normal (cfmakeraw hoses them) */
517 raw_attributes.c_oflag |= OPOST | OCRNL;
518
519 if (tcsetattr(wl->tty, TCSANOW, &raw_attributes) < 0)
520 error(1, errno, "could not put terminal into raw mode: %m\n");
521
522 ioctl(wl->tty, KDGKBMODE, &wl->kb_mode);
523 ret = ioctl(wl->tty, KDSKBMODE, K_OFF);
524 if (ret)
525 ret = ioctl(wl->tty, KDSKBMODE, K_RAW);
526 if (ret)
527 error(1, errno, "failed to set keyboard mode on tty: %m\n");
528
529 ret = ioctl(wl->tty, KDSETMODE, KD_GRAPHICS);
530 if (ret)
531 error(1, errno, "failed to set KD_GRAPHICS mode on tty: %m\n");
532
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700533 mode.mode = VT_PROCESS;
534 mode.relsig = SIGUSR1;
535 mode.acqsig = SIGUSR2;
536 if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
537 error(1, errno, "failed to take control of vt handling\n");
538
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100539 return 0;
540}
541
542static void
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700543setup_session(struct weston_launch *wl)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700544{
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700545 char **env;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700546 char *term;
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700547 int i;
548
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700549 if (wl->tty != STDIN_FILENO) {
550 if (setsid() < 0)
551 error(1, errno, "setsid failed");
552 if (ioctl(wl->tty, TIOCSCTTY, 0) < 0)
553 error(1, errno, "TIOCSCTTY failed - tty is in use");
554 }
555
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700556 term = getenv("TERM");
557 clearenv();
Rob Bradford7ac9f732013-08-09 11:30:38 +0100558 if (term)
559 setenv("TERM", term, 1);
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700560 setenv("USER", wl->pw->pw_name, 1);
561 setenv("LOGNAME", wl->pw->pw_name, 1);
562 setenv("HOME", wl->pw->pw_dir, 1);
563 setenv("SHELL", wl->pw->pw_shell, 1);
564
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700565 env = pam_getenvlist(wl->ph);
566 if (env) {
567 for (i = 0; env[i]; ++i) {
568 if (putenv(env[i]) < 0)
569 error(0, 0, "putenv %s failed", env[i]);
570 }
571 free(env);
572 }
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700573}
574
575static void
Peter Hutterer34be0602013-08-06 12:10:09 +1000576drop_privileges(struct weston_launch *wl)
577{
578 if (setgid(wl->pw->pw_gid) < 0 ||
579#ifdef HAVE_INITGROUPS
580 initgroups(wl->pw->pw_name, wl->pw->pw_gid) < 0 ||
581#endif
582 setuid(wl->pw->pw_uid) < 0)
583 error(1, errno, "dropping privileges failed");
584}
585
586static void
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700587launch_compositor(struct weston_launch *wl, int argc, char *argv[])
588{
589 char *child_argv[MAX_ARGV_SIZE];
Eduardo Limad0357bb2013-07-30 10:43:41 -0700590 sigset_t mask;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700591 int i;
592
593 if (wl->verbose)
594 printf("weston-launch: spawned weston with pid: %d\n", getpid());
595 if (wl->new_user)
596 setup_session(wl);
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700597
Peter Hutterer34be0602013-08-06 12:10:09 +1000598 drop_privileges(wl);
599
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700600 if (wl->tty != STDIN_FILENO)
601 setenv_fd("WESTON_TTY_FD", wl->tty);
602
603 setenv_fd("WESTON_LAUNCHER_SOCK", wl->sock[1]);
604
605 unsetenv("DISPLAY");
606
Kristian Høgsberg73c60ab2013-07-30 09:45:04 -0700607 /* Do not give our signal mask to the new process. */
608 sigemptyset(&mask);
609 sigaddset(&mask, SIGTERM);
610 sigaddset(&mask, SIGCHLD);
611 sigaddset(&mask, SIGINT);
612 sigprocmask(SIG_UNBLOCK, &mask, NULL);
613
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700614 child_argv[0] = wl->pw->pw_shell;
615 child_argv[1] = "-l";
616 child_argv[2] = "-c";
617 child_argv[3] = BINDIR "/weston \"$@\"";
618 child_argv[4] = "weston";
619 for (i = 0; i < argc; ++i)
620 child_argv[5 + i] = argv[i];
621 child_argv[5 + i] = NULL;
622
623 execv(child_argv[0], child_argv);
624 error(1, errno, "exec failed");
625}
626
627static void
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100628help(const char *name)
629{
630 fprintf(stderr, "Usage: %s [args...] [-- [weston args..]]\n", name);
631 fprintf(stderr, " -u, --user Start session as specified username\n");
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300632 fprintf(stderr, " -t, --tty Start session on alternative tty\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100633 fprintf(stderr, " -v, --verbose Be verbose\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100634 fprintf(stderr, " -h, --help Display this help message\n");
635}
636
637int
638main(int argc, char *argv[])
639{
640 struct weston_launch wl;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100641 int i, c;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700642 char *tty = NULL;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100643 struct option opts[] = {
644 { "user", required_argument, NULL, 'u' },
645 { "tty", required_argument, NULL, 't' },
646 { "verbose", no_argument, NULL, 'v' },
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100647 { "help", no_argument, NULL, 'h' },
648 { 0, 0, NULL, 0 }
649 };
650
651 memset(&wl, 0, sizeof wl);
652
Kristian Høgsbergab499942013-07-19 21:26:24 -0700653 while ((c = getopt_long(argc, argv, "u:t::vh", opts, &i)) != -1) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100654 switch (c) {
655 case 'u':
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700656 wl.new_user = optarg;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100657 if (getuid() != 0)
658 error(1, 0, "Permission denied. -u allowed for root only");
659 break;
660 case 't':
661 tty = optarg;
662 break;
663 case 'v':
664 wl.verbose = 1;
665 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100666 case 'h':
Scott Moreaucc9acfc2013-01-21 23:40:59 -0700667 help("weston-launch");
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530668 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100669 }
670 }
671
Ander Conselvan de Oliveira9bdfc482013-05-22 22:55:33 +0300672 if ((argc - optind) > (MAX_ARGV_SIZE - 6))
Quentin Glidicff323092013-05-17 16:20:37 +0200673 error(1, E2BIG, "Too many arguments to pass to weston");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100674
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700675 if (wl.new_user)
676 wl.pw = getpwnam(wl.new_user);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100677 else
678 wl.pw = getpwuid(getuid());
679 if (wl.pw == NULL)
680 error(1, errno, "failed to get username");
681
682 if (!weston_launch_allowed(&wl))
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300683 error(1, 0, "Permission denied. You should either:\n"
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100684#ifdef HAVE_SYSTEMD_LOGIN
685 " - run from an active and local (systemd) session.\n"
686#else
687 " - enable systemd session support for weston-launch.\n"
688#endif
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300689 " - or add yourself to the 'weston-launch' group.");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100690
691 if (setup_tty(&wl, tty) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530692 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100693
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700694 if (wl.new_user && setup_pam(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530695 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100696
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100697 if (setup_launcher_socket(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530698 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100699
700 if (setup_signals(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530701 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100702
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700703 wl.child = fork();
704 if (wl.child == -1) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100705 error(1, errno, "fork failed");
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700706 exit(EXIT_FAILURE);
707 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100708
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700709 if (wl.child == 0)
710 launch_compositor(&wl, argc - optind, argv + optind);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100711
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700712 close(wl.sock[1]);
713 if (wl.tty != STDIN_FILENO)
714 close(wl.tty);
Quentin Glidic735302e2013-06-19 15:27:11 +0200715
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700716 while (1) {
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700717 struct pollfd fds[2];
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700718 int n;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100719
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700720 fds[0].fd = wl.sock[0];
721 fds[0].events = POLLIN;
722 fds[1].fd = wl.signalfd;
723 fds[1].events = POLLIN;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100724
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700725 n = poll(fds, 2, -1);
726 if (n < 0)
727 error(0, errno, "poll failed");
728 if (fds[0].revents & POLLIN)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700729 handle_socket_msg(&wl);
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700730 if (fds[1].revents)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700731 handle_signal(&wl);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100732 }
733
734 return 0;
735}