blob: 8118d038758d78d283ee44683c9ee7d5f686b957 [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
Quentin Glidicff323092013-05-17 16:20:37 +020067#define MAX_ARGV_SIZE 256
68
Benjamin Franzkebfeda132012-01-30 14:04:04 +010069struct weston_launch {
70 struct pam_conv pc;
71 pam_handle_t *ph;
72 int tty;
73 int ttynr;
74 int sock[2];
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -070075 int drm_fd;
Kristian Høgsberg81b49632013-09-17 22:43:22 -070076 int kb_mode;
Benjamin Franzkebfeda132012-01-30 14:04:04 +010077 struct passwd *pw;
78
Benjamin Franzkebfeda132012-01-30 14:04:04 +010079 int signalfd;
80
81 pid_t child;
82 int verbose;
Kristian Høgsberg636156d2013-07-22 10:35:47 -070083 char *new_user;
Benjamin Franzkebfeda132012-01-30 14:04:04 +010084};
85
Kristian Høgsberg9e140912012-04-10 01:26:18 -040086union cmsg_data { unsigned char b[4]; int fd; };
87
Benjamin Franzkebfeda132012-01-30 14:04:04 +010088static gid_t *
89read_groups(void)
90{
91 int n;
92 gid_t *groups;
93
94 n = getgroups(0, NULL);
Rob Bradford40be7b42012-12-05 18:47:11 +000095
96 if (n < 0) {
97 fprintf(stderr, "Unable to retrieve groups: %m\n");
98 return NULL;
99 }
100
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100101 groups = malloc(n * sizeof(gid_t));
102 if (!groups)
103 return NULL;
104
105 if (getgroups(n, groups) < 0) {
Rob Bradford40be7b42012-12-05 18:47:11 +0000106 fprintf(stderr, "Unable to retrieve groups: %m\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100107 free(groups);
108 return NULL;
109 }
110 return groups;
111}
112
113static int
114weston_launch_allowed(struct weston_launch *wl)
115{
116 struct group *gr;
117 gid_t *groups;
118 int i;
119#ifdef HAVE_SYSTEMD_LOGIN
120 char *session, *seat;
121 int err;
122#endif
123
124 if (getuid() == 0)
125 return 1;
126
127 gr = getgrnam("weston-launch");
128 if (gr) {
129 groups = read_groups();
130 if (groups) {
131 for (i = 0; groups[i]; ++i) {
132 if (groups[i] == gr->gr_gid) {
133 free(groups);
134 return 1;
135 }
136 }
137 free(groups);
138 }
139 }
140
141#ifdef HAVE_SYSTEMD_LOGIN
142 err = sd_pid_get_session(getpid(), &session);
143 if (err == 0 && session) {
144 if (sd_session_is_active(session) &&
145 sd_session_get_seat(session, &seat) == 0) {
146 free(seat);
147 free(session);
148 return 1;
149 }
150 free(session);
151 }
152#endif
153
154 return 0;
155}
156
157static int
158pam_conversation_fn(int msg_count,
159 const struct pam_message **messages,
160 struct pam_response **responses,
161 void *user_data)
162{
163 return PAM_SUCCESS;
164}
165
166static int
167setup_pam(struct weston_launch *wl)
168{
169 int err;
170
171 wl->pc.conv = pam_conversation_fn;
172 wl->pc.appdata_ptr = wl;
173
174 err = pam_start("login", wl->pw->pw_name, &wl->pc, &wl->ph);
John Kåre Alsaker5b90d8f2012-10-12 12:25:05 +0200175 if (err != PAM_SUCCESS) {
176 fprintf(stderr, "failed to start pam transaction: %d: %s\n",
177 err, pam_strerror(wl->ph, err));
178 return -1;
179 }
180
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100181 err = pam_set_item(wl->ph, PAM_TTY, ttyname(wl->tty));
182 if (err != PAM_SUCCESS) {
183 fprintf(stderr, "failed to set PAM_TTY item: %d: %s\n",
184 err, pam_strerror(wl->ph, err));
185 return -1;
186 }
187
188 err = pam_open_session(wl->ph, 0);
189 if (err != PAM_SUCCESS) {
190 fprintf(stderr, "failed to open pam session: %d: %s\n",
191 err, pam_strerror(wl->ph, err));
192 return -1;
193 }
194
195 return 0;
196}
197
198static int
199setup_launcher_socket(struct weston_launch *wl)
200{
Kristian Høgsbergbf3c3742013-09-18 11:01:48 -0700201 if (socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, wl->sock) < 0)
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100202 error(1, errno, "socketpair failed");
203
Kristian Høgsbergf45b1e82013-09-18 11:00:56 -0700204 if (fcntl(wl->sock[0], F_SETFD, FD_CLOEXEC) < 0)
205 error(1, errno, "fcntl failed");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100206
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100207 return 0;
208}
209
210static int
211setup_signals(struct weston_launch *wl)
212{
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100213 int ret;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100214 sigset_t mask;
215 struct sigaction sa;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100216
217 memset(&sa, 0, sizeof sa);
218 sa.sa_handler = SIG_DFL;
219 sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100220 ret = sigaction(SIGCHLD, &sa, NULL);
221 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100222
Kristian Høgsberg18684d42013-07-22 11:59:18 -0700223 sa.sa_handler = SIG_IGN;
224 sa.sa_flags = 0;
225 sigaction(SIGHUP, &sa, NULL);
226
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100227 ret = sigemptyset(&mask);
228 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100229 sigaddset(&mask, SIGCHLD);
230 sigaddset(&mask, SIGINT);
231 sigaddset(&mask, SIGTERM);
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700232 sigaddset(&mask, SIGUSR1);
233 sigaddset(&mask, SIGUSR2);
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100234 ret = sigprocmask(SIG_BLOCK, &mask, NULL);
235 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100236
237 wl->signalfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
238 if (wl->signalfd < 0)
239 return -errno;
240
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100241 return 0;
242}
243
244static void
245setenv_fd(const char *env, int fd)
246{
247 char buf[32];
248
249 snprintf(buf, sizeof buf, "%d", fd);
250 setenv(env, buf, 1);
251}
252
253static int
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700254send_reply(struct weston_launch *wl, int reply)
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100255{
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700256 int len;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100257
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100258 do {
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700259 len = send(wl->sock[0], &reply, sizeof reply, 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100260 } while (len < 0 && errno == EINTR);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100261
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700262 return len;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100263}
264
265static int
266handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
267{
268 int fd = -1, ret = -1;
269 char control[CMSG_SPACE(sizeof(fd))];
270 struct cmsghdr *cmsg;
271 struct stat s;
272 struct msghdr nmsg;
273 struct iovec iov;
274 struct weston_launcher_open *message;
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400275 union cmsg_data *data;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100276
277 message = msg->msg_iov->iov_base;
278 if ((size_t)len < sizeof(*message))
279 goto err0;
280
281 /* Ensure path is null-terminated */
282 ((char *) message)[len-1] = '\0';
283
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100284 fd = open(message->path, message->flags);
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100285 if (fd < 0) {
286 fprintf(stderr, "Error opening device %s: %m\n",
287 message->path);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100288 goto err0;
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100289 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100290
Kristian Høgsberg6a7c8492013-09-18 22:14:09 -0700291 if (fstat(fd, &s) < 0) {
292 close(fd);
293 fd = -1;
294 fprintf(stderr, "Failed to stat %s\n", message->path);
295 goto err0;
296 }
297
Kristian Høgsberg1ff51092013-09-17 14:03:42 -0700298 if (major(s.st_rdev) != INPUT_MAJOR &&
299 major(s.st_rdev) != DRM_MAJOR) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100300 close(fd);
301 fd = -1;
Kristian Høgsberg1ff51092013-09-17 14:03:42 -0700302 fprintf(stderr, "Device %s is not an input or drm device\n",
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100303 message->path);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100304 goto err0;
305 }
306
307err0:
308 memset(&nmsg, 0, sizeof nmsg);
309 nmsg.msg_iov = &iov;
310 nmsg.msg_iovlen = 1;
311 if (fd != -1) {
312 nmsg.msg_control = control;
313 nmsg.msg_controllen = sizeof control;
314 cmsg = CMSG_FIRSTHDR(&nmsg);
315 cmsg->cmsg_level = SOL_SOCKET;
316 cmsg->cmsg_type = SCM_RIGHTS;
317 cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400318 data = (union cmsg_data *) CMSG_DATA(cmsg);
319 data->fd = fd;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100320 nmsg.msg_controllen = cmsg->cmsg_len;
321 ret = 0;
322 }
323 iov.iov_base = &ret;
324 iov.iov_len = sizeof ret;
325
326 if (wl->verbose)
327 fprintf(stderr, "weston-launch: opened %s: ret: %d, fd: %d\n",
328 message->path, ret, fd);
329 do {
330 len = sendmsg(wl->sock[0], &nmsg, 0);
331 } while (len < 0 && errno == EINTR);
332
333 if (len < 0)
334 return -1;
335
Kristian Høgsbergaf393dc2013-10-09 11:25:14 -0700336 if (fd != -1 && major(s.st_rdev) == DRM_MAJOR)
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700337 wl->drm_fd = fd;
338
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100339 return 0;
340}
341
342static int
343handle_socket_msg(struct weston_launch *wl)
344{
345 char control[CMSG_SPACE(sizeof(int))];
346 char buf[BUFSIZ];
347 struct msghdr msg;
348 struct iovec iov;
349 int ret = -1;
350 ssize_t len;
351 struct weston_launcher_message *message;
352
353 memset(&msg, 0, sizeof(msg));
354 iov.iov_base = buf;
355 iov.iov_len = sizeof buf;
356 msg.msg_iov = &iov;
357 msg.msg_iovlen = 1;
358 msg.msg_control = control;
359 msg.msg_controllen = sizeof control;
360
361 do {
362 len = recvmsg(wl->sock[0], &msg, 0);
363 } while (len < 0 && errno == EINTR);
364
365 if (len < 1)
366 return -1;
367
368 message = (void *) buf;
369 switch (message->opcode) {
370 case WESTON_LAUNCHER_OPEN:
371 ret = handle_open(wl, &msg, len);
372 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100373 }
374
375 return ret;
376}
377
378static void
379quit(struct weston_launch *wl, int status)
380{
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700381 struct vt_mode mode = { 0 };
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100382 int err;
383
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100384 close(wl->signalfd);
385 close(wl->sock[0]);
386
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700387 if (wl->new_user) {
388 err = pam_close_session(wl->ph, 0);
389 if (err)
390 fprintf(stderr, "pam_close_session failed: %d: %s\n",
391 err, pam_strerror(wl->ph, err));
392 pam_end(wl->ph, err);
393 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100394
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700395 if (ioctl(wl->tty, KDSKBMUTE, 0) &&
396 ioctl(wl->tty, KDSKBMODE, wl->kb_mode))
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700397 fprintf(stderr, "failed to restore keyboard mode: %m\n");
398
399 if (ioctl(wl->tty, KDSETMODE, KD_TEXT))
400 fprintf(stderr, "failed to set KD_TEXT mode on tty: %m\n");
401
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700402 mode.mode = VT_AUTO;
403 if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
404 fprintf(stderr, "could not reset vt handling\n");
405
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100406 exit(status);
407}
408
409static int
410handle_signal(struct weston_launch *wl)
411{
412 struct signalfd_siginfo sig;
Philipp Brüschweiler7a3ec742013-03-10 15:14:01 +0100413 int pid, status, ret;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100414
415 if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) {
416 error(0, errno, "reading signalfd failed");
417 return -1;
418 }
419
420 switch (sig.ssi_signo) {
421 case SIGCHLD:
422 pid = waitpid(-1, &status, 0);
423 if (pid == wl->child) {
424 wl->child = 0;
Philipp Brüschweiler7a3ec742013-03-10 15:14:01 +0100425 if (WIFEXITED(status))
426 ret = WEXITSTATUS(status);
427 else if (WIFSIGNALED(status))
428 /*
429 * If weston dies because of signal N, we
430 * return 10+N. This is distinct from
431 * weston-launch dying because of a signal
432 * (128+N).
433 */
434 ret = 10 + WTERMSIG(status);
435 else
436 ret = 0;
437 quit(wl, ret);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100438 }
439 break;
440 case SIGTERM:
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100441 case SIGINT:
442 if (wl->child)
Kristian Høgsberg1a81abb2013-06-17 15:23:20 -0400443 kill(wl->child, sig.ssi_signo);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100444 break;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700445 case SIGUSR1:
446 send_reply(wl, WESTON_LAUNCHER_DEACTIVATE);
447 drmDropMaster(wl->drm_fd);
448 ioctl(wl->tty, VT_RELDISP, 1);
449 break;
450 case SIGUSR2:
451 ioctl(wl->tty, VT_RELDISP, VT_ACKACQ);
452 drmSetMaster(wl->drm_fd);
453 send_reply(wl, WESTON_LAUNCHER_ACTIVATE);
454 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100455 default:
456 return -1;
457 }
458
459 return 0;
460}
461
462static int
463setup_tty(struct weston_launch *wl, const char *tty)
464{
465 struct stat buf;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700466 struct vt_mode mode = { 0 };
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100467 char *t;
468
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
Kristian Høgsberge05f2282013-10-02 13:06:02 -0700495 if (fstat(wl->tty, &buf) == -1 ||
496 major(buf.st_rdev) != TTY_MAJOR || minor(buf.st_rdev) == 0)
497 error(1, 0, "weston-launch must be run from a virtual terminal");
498
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100499 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øgsberg3f495872013-09-18 23:00:17 -0700509 if (ioctl(wl->tty, KDGKBMODE, &wl->kb_mode))
510 error(1, errno, "failed to get current keyboard mode: %m\n");
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700511
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700512 if (ioctl(wl->tty, KDSKBMUTE, 1) &&
513 ioctl(wl->tty, KDSKBMODE, K_OFF))
514 error(1, errno, "failed to set K_OFF keyboard mode: %m\n");
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700515
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700516 if (ioctl(wl->tty, KDSETMODE, KD_GRAPHICS))
Kristian Høgsberg81b49632013-09-17 22:43:22 -0700517 error(1, errno, "failed to set KD_GRAPHICS mode on tty: %m\n");
518
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700519 mode.mode = VT_PROCESS;
520 mode.relsig = SIGUSR1;
521 mode.acqsig = SIGUSR2;
522 if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
523 error(1, errno, "failed to take control of vt handling\n");
524
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100525 return 0;
526}
527
528static void
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700529setup_session(struct weston_launch *wl)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700530{
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700531 char **env;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700532 char *term;
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700533 int i;
534
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700535 if (wl->tty != STDIN_FILENO) {
536 if (setsid() < 0)
537 error(1, errno, "setsid failed");
538 if (ioctl(wl->tty, TIOCSCTTY, 0) < 0)
539 error(1, errno, "TIOCSCTTY failed - tty is in use");
540 }
541
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700542 term = getenv("TERM");
543 clearenv();
Rob Bradford7ac9f732013-08-09 11:30:38 +0100544 if (term)
545 setenv("TERM", term, 1);
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700546 setenv("USER", wl->pw->pw_name, 1);
547 setenv("LOGNAME", wl->pw->pw_name, 1);
548 setenv("HOME", wl->pw->pw_dir, 1);
549 setenv("SHELL", wl->pw->pw_shell, 1);
550
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700551 env = pam_getenvlist(wl->ph);
552 if (env) {
553 for (i = 0; env[i]; ++i) {
554 if (putenv(env[i]) < 0)
555 error(0, 0, "putenv %s failed", env[i]);
556 }
557 free(env);
558 }
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700559}
560
561static void
Peter Hutterer34be0602013-08-06 12:10:09 +1000562drop_privileges(struct weston_launch *wl)
563{
564 if (setgid(wl->pw->pw_gid) < 0 ||
565#ifdef HAVE_INITGROUPS
566 initgroups(wl->pw->pw_name, wl->pw->pw_gid) < 0 ||
567#endif
568 setuid(wl->pw->pw_uid) < 0)
569 error(1, errno, "dropping privileges failed");
570}
571
572static void
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700573launch_compositor(struct weston_launch *wl, int argc, char *argv[])
574{
575 char *child_argv[MAX_ARGV_SIZE];
Eduardo Limad0357bb2013-07-30 10:43:41 -0700576 sigset_t mask;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700577 int i;
578
579 if (wl->verbose)
580 printf("weston-launch: spawned weston with pid: %d\n", getpid());
581 if (wl->new_user)
582 setup_session(wl);
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700583
Tomeu Vizosod7865b22013-10-01 12:20:29 +0200584 if (geteuid() == 0)
585 drop_privileges(wl);
Peter Hutterer34be0602013-08-06 12:10:09 +1000586
Kristian Høgsberg3f495872013-09-18 23:00:17 -0700587 setenv_fd("WESTON_TTY_FD", wl->tty);
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700588 setenv_fd("WESTON_LAUNCHER_SOCK", wl->sock[1]);
589
590 unsetenv("DISPLAY");
591
Kristian Høgsberg73c60ab2013-07-30 09:45:04 -0700592 /* Do not give our signal mask to the new process. */
593 sigemptyset(&mask);
594 sigaddset(&mask, SIGTERM);
595 sigaddset(&mask, SIGCHLD);
596 sigaddset(&mask, SIGINT);
597 sigprocmask(SIG_UNBLOCK, &mask, NULL);
598
Kristian Høgsbergfb08e4b2013-10-21 15:14:44 -0700599 child_argv[0] = "/bin/sh";
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700600 child_argv[1] = "-l";
601 child_argv[2] = "-c";
602 child_argv[3] = BINDIR "/weston \"$@\"";
603 child_argv[4] = "weston";
604 for (i = 0; i < argc; ++i)
605 child_argv[5 + i] = argv[i];
606 child_argv[5 + i] = NULL;
607
608 execv(child_argv[0], child_argv);
609 error(1, errno, "exec failed");
610}
611
612static void
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100613help(const char *name)
614{
615 fprintf(stderr, "Usage: %s [args...] [-- [weston args..]]\n", name);
616 fprintf(stderr, " -u, --user Start session as specified username\n");
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300617 fprintf(stderr, " -t, --tty Start session on alternative tty\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100618 fprintf(stderr, " -v, --verbose Be verbose\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100619 fprintf(stderr, " -h, --help Display this help message\n");
620}
621
622int
623main(int argc, char *argv[])
624{
625 struct weston_launch wl;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100626 int i, c;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700627 char *tty = NULL;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100628 struct option opts[] = {
629 { "user", required_argument, NULL, 'u' },
630 { "tty", required_argument, NULL, 't' },
631 { "verbose", no_argument, NULL, 'v' },
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100632 { "help", no_argument, NULL, 'h' },
633 { 0, 0, NULL, 0 }
634 };
635
636 memset(&wl, 0, sizeof wl);
637
Kristian Høgsbergab499942013-07-19 21:26:24 -0700638 while ((c = getopt_long(argc, argv, "u:t::vh", opts, &i)) != -1) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100639 switch (c) {
640 case 'u':
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700641 wl.new_user = optarg;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100642 if (getuid() != 0)
643 error(1, 0, "Permission denied. -u allowed for root only");
644 break;
645 case 't':
646 tty = optarg;
647 break;
648 case 'v':
649 wl.verbose = 1;
650 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100651 case 'h':
Scott Moreaucc9acfc2013-01-21 23:40:59 -0700652 help("weston-launch");
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530653 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100654 }
655 }
656
Ander Conselvan de Oliveira9bdfc482013-05-22 22:55:33 +0300657 if ((argc - optind) > (MAX_ARGV_SIZE - 6))
Quentin Glidicff323092013-05-17 16:20:37 +0200658 error(1, E2BIG, "Too many arguments to pass to weston");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100659
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700660 if (wl.new_user)
661 wl.pw = getpwnam(wl.new_user);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100662 else
663 wl.pw = getpwuid(getuid());
664 if (wl.pw == NULL)
665 error(1, errno, "failed to get username");
666
667 if (!weston_launch_allowed(&wl))
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300668 error(1, 0, "Permission denied. You should either:\n"
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100669#ifdef HAVE_SYSTEMD_LOGIN
670 " - run from an active and local (systemd) session.\n"
671#else
672 " - enable systemd session support for weston-launch.\n"
673#endif
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300674 " - or add yourself to the 'weston-launch' group.");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100675
676 if (setup_tty(&wl, tty) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530677 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100678
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700679 if (wl.new_user && setup_pam(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530680 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100681
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100682 if (setup_launcher_socket(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530683 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100684
685 if (setup_signals(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530686 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100687
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700688 wl.child = fork();
689 if (wl.child == -1) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100690 error(1, errno, "fork failed");
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700691 exit(EXIT_FAILURE);
692 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100693
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700694 if (wl.child == 0)
695 launch_compositor(&wl, argc - optind, argv + optind);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100696
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700697 close(wl.sock[1]);
698 if (wl.tty != STDIN_FILENO)
699 close(wl.tty);
Quentin Glidic735302e2013-06-19 15:27:11 +0200700
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700701 while (1) {
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700702 struct pollfd fds[2];
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700703 int n;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100704
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700705 fds[0].fd = wl.sock[0];
706 fds[0].events = POLLIN;
707 fds[1].fd = wl.signalfd;
708 fds[1].events = POLLIN;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100709
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700710 n = poll(fds, 2, -1);
711 if (n < 0)
712 error(0, errno, "poll failed");
713 if (fds[0].revents & POLLIN)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700714 handle_socket_msg(&wl);
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700715 if (fds[1].revents)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700716 handle_signal(&wl);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100717 }
718
719 return 0;
720}