blob: 059010c4eeec7c49d9e43e7edab4d310ca156cd6 [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
283 if (stat(message->path, &s) < 0)
284 goto err0;
285
286 fd = open(message->path, message->flags);
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100287 if (fd < 0) {
288 fprintf(stderr, "Error opening device %s: %m\n",
289 message->path);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100290 goto err0;
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100291 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100292
Kristian Høgsberg1ff51092013-09-17 14:03:42 -0700293 if (major(s.st_rdev) != INPUT_MAJOR &&
294 major(s.st_rdev) != DRM_MAJOR) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100295 close(fd);
296 fd = -1;
Kristian Høgsberg1ff51092013-09-17 14:03:42 -0700297 fprintf(stderr, "Device %s is not an input or drm device\n",
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100298 message->path);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100299 goto err0;
300 }
301
302err0:
303 memset(&nmsg, 0, sizeof nmsg);
304 nmsg.msg_iov = &iov;
305 nmsg.msg_iovlen = 1;
306 if (fd != -1) {
307 nmsg.msg_control = control;
308 nmsg.msg_controllen = sizeof control;
309 cmsg = CMSG_FIRSTHDR(&nmsg);
310 cmsg->cmsg_level = SOL_SOCKET;
311 cmsg->cmsg_type = SCM_RIGHTS;
312 cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400313 data = (union cmsg_data *) CMSG_DATA(cmsg);
314 data->fd = fd;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100315 nmsg.msg_controllen = cmsg->cmsg_len;
316 ret = 0;
317 }
318 iov.iov_base = &ret;
319 iov.iov_len = sizeof ret;
320
321 if (wl->verbose)
322 fprintf(stderr, "weston-launch: opened %s: ret: %d, fd: %d\n",
323 message->path, ret, fd);
324 do {
325 len = sendmsg(wl->sock[0], &nmsg, 0);
326 } while (len < 0 && errno == EINTR);
327
328 if (len < 0)
329 return -1;
330
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700331 if (major(s.st_rdev) == DRM_MAJOR)
332 wl->drm_fd = fd;
333
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100334 return 0;
335}
336
337static int
338handle_socket_msg(struct weston_launch *wl)
339{
340 char control[CMSG_SPACE(sizeof(int))];
341 char buf[BUFSIZ];
342 struct msghdr msg;
343 struct iovec iov;
344 int ret = -1;
345 ssize_t len;
346 struct weston_launcher_message *message;
347
348 memset(&msg, 0, sizeof(msg));
349 iov.iov_base = buf;
350 iov.iov_len = sizeof buf;
351 msg.msg_iov = &iov;
352 msg.msg_iovlen = 1;
353 msg.msg_control = control;
354 msg.msg_controllen = sizeof control;
355
356 do {
357 len = recvmsg(wl->sock[0], &msg, 0);
358 } while (len < 0 && errno == EINTR);
359
360 if (len < 1)
361 return -1;
362
363 message = (void *) buf;
364 switch (message->opcode) {
365 case WESTON_LAUNCHER_OPEN:
366 ret = handle_open(wl, &msg, len);
367 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100368 }
369
370 return ret;
371}
372
373static void
374quit(struct weston_launch *wl, int status)
375{
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700376 struct vt_mode mode = { 0 };
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100377 int err;
378
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100379 close(wl->signalfd);
380 close(wl->sock[0]);
381
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700382 if (wl->new_user) {
383 err = pam_close_session(wl->ph, 0);
384 if (err)
385 fprintf(stderr, "pam_close_session failed: %d: %s\n",
386 err, pam_strerror(wl->ph, err));
387 pam_end(wl->ph, err);
388 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100389
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700390 if (ioctl(wl->tty, KDSKBMODE, wl->kb_mode))
391 fprintf(stderr, "failed to restore keyboard mode: %m\n");
392
393 if (ioctl(wl->tty, KDSETMODE, KD_TEXT))
394 fprintf(stderr, "failed to set KD_TEXT mode on tty: %m\n");
395
396 if (tcsetattr(wl->tty, TCSANOW, &wl->terminal_attributes) < 0)
397 fprintf(stderr,
398 "could not restore terminal to canonical mode\n");
399
400 mode.mode = VT_AUTO;
401 if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
402 fprintf(stderr, "could not reset vt handling\n");
403
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100404 exit(status);
405}
406
407static int
408handle_signal(struct weston_launch *wl)
409{
410 struct signalfd_siginfo sig;
Philipp Brüschweiler7a3ec742013-03-10 15:14:01 +0100411 int pid, status, ret;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100412
413 if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) {
414 error(0, errno, "reading signalfd failed");
415 return -1;
416 }
417
418 switch (sig.ssi_signo) {
419 case SIGCHLD:
420 pid = waitpid(-1, &status, 0);
421 if (pid == wl->child) {
422 wl->child = 0;
Philipp Brüschweiler7a3ec742013-03-10 15:14:01 +0100423 if (WIFEXITED(status))
424 ret = WEXITSTATUS(status);
425 else if (WIFSIGNALED(status))
426 /*
427 * If weston dies because of signal N, we
428 * return 10+N. This is distinct from
429 * weston-launch dying because of a signal
430 * (128+N).
431 */
432 ret = 10 + WTERMSIG(status);
433 else
434 ret = 0;
435 quit(wl, ret);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100436 }
437 break;
438 case SIGTERM:
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100439 case SIGINT:
440 if (wl->child)
Kristian Høgsberg1a81abb2013-06-17 15:23:20 -0400441 kill(wl->child, sig.ssi_signo);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100442 break;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700443 case SIGUSR1:
444 send_reply(wl, WESTON_LAUNCHER_DEACTIVATE);
445 drmDropMaster(wl->drm_fd);
446 ioctl(wl->tty, VT_RELDISP, 1);
447 break;
448 case SIGUSR2:
449 ioctl(wl->tty, VT_RELDISP, VT_ACKACQ);
450 drmSetMaster(wl->drm_fd);
451 send_reply(wl, WESTON_LAUNCHER_ACTIVATE);
452 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100453 default:
454 return -1;
455 }
456
457 return 0;
458}
459
460static int
461setup_tty(struct weston_launch *wl, const char *tty)
462{
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700463 struct termios raw_attributes;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100464 struct stat buf;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700465 struct vt_mode mode = { 0 };
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100466 char *t;
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700467 int ret;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100468
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700469 if (!wl->new_user) {
470 wl->tty = STDIN_FILENO;
471 } else if (tty) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100472 t = ttyname(STDIN_FILENO);
473 if (t && strcmp(t, tty) == 0)
474 wl->tty = STDIN_FILENO;
475 else
476 wl->tty = open(tty, O_RDWR | O_NOCTTY);
477 } else {
478 int tty0 = open("/dev/tty0", O_WRONLY | O_CLOEXEC);
479 char filename[16];
480
481 if (tty0 < 0)
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300482 error(1, errno, "could not open tty0");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100483
484 if (ioctl(tty0, VT_OPENQRY, &wl->ttynr) < 0 || wl->ttynr == -1)
485 error(1, errno, "failed to find non-opened console");
486
487 snprintf(filename, sizeof filename, "/dev/tty%d", wl->ttynr);
488 wl->tty = open(filename, O_RDWR | O_NOCTTY);
489 close(tty0);
490 }
491
492 if (wl->tty < 0)
493 error(1, errno, "failed to open tty");
494
495 if (tty) {
496 if (fstat(wl->tty, &buf) < 0)
497 error(1, errno, "stat %s failed", tty);
498
499 if (major(buf.st_rdev) != TTY_MAJOR)
500 error(1, 0, "invalid tty device: %s", tty);
501
502 wl->ttynr = minor(buf.st_rdev);
503 }
504
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700505 if (tcgetattr(wl->tty, &wl->terminal_attributes) < 0)
506 error(1, errno, "could not get terminal attributes: %m\n");
507
508 /* Ignore control characters and disable echo */
509 raw_attributes = wl->terminal_attributes;
510 cfmakeraw(&raw_attributes);
511
512 /* Fix up line endings to be normal (cfmakeraw hoses them) */
513 raw_attributes.c_oflag |= OPOST | OCRNL;
514
515 if (tcsetattr(wl->tty, TCSANOW, &raw_attributes) < 0)
516 error(1, errno, "could not put terminal into raw mode: %m\n");
517
518 ioctl(wl->tty, KDGKBMODE, &wl->kb_mode);
519 ret = ioctl(wl->tty, KDSKBMODE, K_OFF);
520 if (ret)
521 ret = ioctl(wl->tty, KDSKBMODE, K_RAW);
522 if (ret)
523 error(1, errno, "failed to set keyboard mode on tty: %m\n");
524
525 ret = ioctl(wl->tty, KDSETMODE, KD_GRAPHICS);
526 if (ret)
527 error(1, errno, "failed to set KD_GRAPHICS mode on tty: %m\n");
528
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700529 mode.mode = VT_PROCESS;
530 mode.relsig = SIGUSR1;
531 mode.acqsig = SIGUSR2;
532 if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
533 error(1, errno, "failed to take control of vt handling\n");
534
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100535 return 0;
536}
537
538static void
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700539setup_session(struct weston_launch *wl)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700540{
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700541 char **env;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700542 char *term;
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700543 int i;
544
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700545 if (wl->tty != STDIN_FILENO) {
546 if (setsid() < 0)
547 error(1, errno, "setsid failed");
548 if (ioctl(wl->tty, TIOCSCTTY, 0) < 0)
549 error(1, errno, "TIOCSCTTY failed - tty is in use");
550 }
551
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700552 term = getenv("TERM");
553 clearenv();
Rob Bradford7ac9f732013-08-09 11:30:38 +0100554 if (term)
555 setenv("TERM", term, 1);
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700556 setenv("USER", wl->pw->pw_name, 1);
557 setenv("LOGNAME", wl->pw->pw_name, 1);
558 setenv("HOME", wl->pw->pw_dir, 1);
559 setenv("SHELL", wl->pw->pw_shell, 1);
560
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700561 env = pam_getenvlist(wl->ph);
562 if (env) {
563 for (i = 0; env[i]; ++i) {
564 if (putenv(env[i]) < 0)
565 error(0, 0, "putenv %s failed", env[i]);
566 }
567 free(env);
568 }
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700569}
570
571static void
Peter Hutterer34be0602013-08-06 12:10:09 +1000572drop_privileges(struct weston_launch *wl)
573{
574 if (setgid(wl->pw->pw_gid) < 0 ||
575#ifdef HAVE_INITGROUPS
576 initgroups(wl->pw->pw_name, wl->pw->pw_gid) < 0 ||
577#endif
578 setuid(wl->pw->pw_uid) < 0)
579 error(1, errno, "dropping privileges failed");
580}
581
582static void
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700583launch_compositor(struct weston_launch *wl, int argc, char *argv[])
584{
585 char *child_argv[MAX_ARGV_SIZE];
Eduardo Limad0357bb2013-07-30 10:43:41 -0700586 sigset_t mask;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700587 int i;
588
589 if (wl->verbose)
590 printf("weston-launch: spawned weston with pid: %d\n", getpid());
591 if (wl->new_user)
592 setup_session(wl);
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700593
Peter Hutterer34be0602013-08-06 12:10:09 +1000594 drop_privileges(wl);
595
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700596 if (wl->tty != STDIN_FILENO)
597 setenv_fd("WESTON_TTY_FD", wl->tty);
598
599 setenv_fd("WESTON_LAUNCHER_SOCK", wl->sock[1]);
600
601 unsetenv("DISPLAY");
602
Kristian Høgsberg73c60ab2013-07-30 09:45:04 -0700603 /* Do not give our signal mask to the new process. */
604 sigemptyset(&mask);
605 sigaddset(&mask, SIGTERM);
606 sigaddset(&mask, SIGCHLD);
607 sigaddset(&mask, SIGINT);
608 sigprocmask(SIG_UNBLOCK, &mask, NULL);
609
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700610 child_argv[0] = wl->pw->pw_shell;
611 child_argv[1] = "-l";
612 child_argv[2] = "-c";
613 child_argv[3] = BINDIR "/weston \"$@\"";
614 child_argv[4] = "weston";
615 for (i = 0; i < argc; ++i)
616 child_argv[5 + i] = argv[i];
617 child_argv[5 + i] = NULL;
618
619 execv(child_argv[0], child_argv);
620 error(1, errno, "exec failed");
621}
622
623static void
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100624help(const char *name)
625{
626 fprintf(stderr, "Usage: %s [args...] [-- [weston args..]]\n", name);
627 fprintf(stderr, " -u, --user Start session as specified username\n");
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300628 fprintf(stderr, " -t, --tty Start session on alternative tty\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100629 fprintf(stderr, " -v, --verbose Be verbose\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100630 fprintf(stderr, " -h, --help Display this help message\n");
631}
632
633int
634main(int argc, char *argv[])
635{
636 struct weston_launch wl;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100637 int i, c;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700638 char *tty = NULL;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100639 struct option opts[] = {
640 { "user", required_argument, NULL, 'u' },
641 { "tty", required_argument, NULL, 't' },
642 { "verbose", no_argument, NULL, 'v' },
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100643 { "help", no_argument, NULL, 'h' },
644 { 0, 0, NULL, 0 }
645 };
646
647 memset(&wl, 0, sizeof wl);
648
Kristian Høgsbergab499942013-07-19 21:26:24 -0700649 while ((c = getopt_long(argc, argv, "u:t::vh", opts, &i)) != -1) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100650 switch (c) {
651 case 'u':
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700652 wl.new_user = optarg;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100653 if (getuid() != 0)
654 error(1, 0, "Permission denied. -u allowed for root only");
655 break;
656 case 't':
657 tty = optarg;
658 break;
659 case 'v':
660 wl.verbose = 1;
661 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100662 case 'h':
Scott Moreaucc9acfc2013-01-21 23:40:59 -0700663 help("weston-launch");
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530664 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100665 }
666 }
667
Ander Conselvan de Oliveira9bdfc482013-05-22 22:55:33 +0300668 if ((argc - optind) > (MAX_ARGV_SIZE - 6))
Quentin Glidicff323092013-05-17 16:20:37 +0200669 error(1, E2BIG, "Too many arguments to pass to weston");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100670
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700671 if (wl.new_user)
672 wl.pw = getpwnam(wl.new_user);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100673 else
674 wl.pw = getpwuid(getuid());
675 if (wl.pw == NULL)
676 error(1, errno, "failed to get username");
677
678 if (!weston_launch_allowed(&wl))
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300679 error(1, 0, "Permission denied. You should either:\n"
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100680#ifdef HAVE_SYSTEMD_LOGIN
681 " - run from an active and local (systemd) session.\n"
682#else
683 " - enable systemd session support for weston-launch.\n"
684#endif
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300685 " - or add yourself to the 'weston-launch' group.");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100686
687 if (setup_tty(&wl, tty) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530688 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100689
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700690 if (wl.new_user && setup_pam(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530691 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100692
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100693 if (setup_launcher_socket(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530694 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100695
696 if (setup_signals(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530697 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100698
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700699 wl.child = fork();
700 if (wl.child == -1) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100701 error(1, errno, "fork failed");
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700702 exit(EXIT_FAILURE);
703 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100704
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700705 if (wl.child == 0)
706 launch_compositor(&wl, argc - optind, argv + optind);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100707
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700708 close(wl.sock[1]);
709 if (wl.tty != STDIN_FILENO)
710 close(wl.tty);
Quentin Glidic735302e2013-06-19 15:27:11 +0200711
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700712 while (1) {
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700713 struct pollfd fds[2];
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700714 int n;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100715
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700716 fds[0].fd = wl.sock[0];
717 fds[0].events = POLLIN;
718 fds[1].fd = wl.signalfd;
719 fds[1].events = POLLIN;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100720
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700721 n = poll(fds, 2, -1);
722 if (n < 0)
723 error(0, errno, "poll failed");
724 if (fds[0].revents & POLLIN)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700725 handle_socket_msg(&wl);
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700726 if (fds[1].revents)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700727 handle_signal(&wl);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100728 }
729
730 return 0;
731}