xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

xorg-wrapper.c (8460B)


      1 /*
      2  * Copyright © 2014 Red Hat, Inc.
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     21  * DEALINGS IN THE SOFTWARE.
     22  *
     23  * Author: Hans de Goede <hdegoede@redhat.com>
     24  */
     25 
     26 #include "dix-config.h"
     27 #include "xorg-config.h"
     28 
     29 #include <errno.h>
     30 #include <fcntl.h>
     31 #include <limits.h>
     32 #include <stdint.h>
     33 #include <stdio.h>
     34 #include <stdlib.h>
     35 #include <string.h>
     36 #include <sys/ioctl.h>
     37 #include <sys/stat.h>
     38 #ifdef HAVE_SYS_SYSMACROS_H
     39 #include <sys/sysmacros.h>
     40 #endif
     41 #include <sys/types.h>
     42 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
     43 #include <sys/consio.h>
     44 #endif
     45 #include <unistd.h>
     46 #ifdef WITH_LIBDRM
     47 #include <drm.h>
     48 #include <xf86drm.h> /* For DRM_DEV_NAME */
     49 #endif
     50 
     51 #include "misc.h"
     52 
     53 #define CONFIG_FILE SYSCONFDIR "/X11/Xwrapper.config"
     54 
     55 static const char *progname;
     56 
     57 enum { ROOT_ONLY, CONSOLE_ONLY, ANYBODY };
     58 
     59 /* KISS non locale / LANG parsing isspace version */
     60 static int is_space(char c)
     61 {
     62     return c == ' ' || c == '\t' || c == '\n';
     63 }
     64 
     65 static char *strip(char *s)
     66 {
     67     int i;
     68 
     69     /* Strip leading whitespace */
     70     while (s[0] && is_space(s[0]))
     71         s++;
     72 
     73     /* Strip trailing whitespace */
     74     i = strlen(s) - 1;
     75     while (i >= 0 && is_space(s[i])) {
     76         s[i] = 0;
     77         i--;
     78     }
     79 
     80     return s;
     81 }
     82 
     83 static void parse_config(int *allowed, int *needs_root_rights)
     84 {
     85     FILE *f;
     86     char buf[1024];
     87     char *stripped, *equals, *key, *value;
     88     int line = 0;
     89 
     90     f = fopen(CONFIG_FILE, "r");
     91     if (!f)
     92         return;
     93 
     94     while (fgets(buf, sizeof(buf), f)) {
     95         line++;
     96 
     97         /* Skip comments and empty lines */
     98         stripped = strip(buf);
     99         if (stripped[0] == '#' || stripped[0] == 0)
    100             continue;
    101 
    102         /* Split in a key + value pair */
    103         equals = strchr(stripped, '=');
    104         if (!equals) {
    105             fprintf(stderr, "%s: Syntax error at %s line %d\n", progname,
    106                 CONFIG_FILE, line);
    107             exit(1);
    108         }
    109         *equals = 0;
    110         key   = strip(stripped);   /* To remove trailing whitespace from key */
    111         value = strip(equals + 1); /* To remove leading whitespace from val */
    112         if (!key[0]) {
    113             fprintf(stderr, "%s: Missing key at %s line %d\n", progname,
    114                 CONFIG_FILE, line);
    115             exit(1);
    116         }
    117         if (!value[0]) {
    118             fprintf(stderr, "%s: Missing value at %s line %d\n", progname,
    119                 CONFIG_FILE, line);
    120             exit(1);
    121         }
    122 
    123         /* And finally process */
    124         if (strcmp(key, "allowed_users") == 0) {
    125             if (strcmp(value, "rootonly") == 0)
    126                 *allowed = ROOT_ONLY;
    127             else if (strcmp(value, "console") == 0)
    128                 *allowed = CONSOLE_ONLY;
    129             else if (strcmp(value, "anybody") == 0)
    130                 *allowed = ANYBODY;
    131             else {
    132                 fprintf(stderr,
    133                     "%s: Invalid value '%s' for 'allowed_users' at %s line %d\n",
    134                     progname, value, CONFIG_FILE, line);
    135                 exit(1);
    136             }
    137         }
    138         else if (strcmp(key, "needs_root_rights") == 0) {
    139             if (strcmp(value, "yes") == 0)
    140                 *needs_root_rights = 1;
    141             else if (strcmp(value, "no") == 0)
    142                 *needs_root_rights = 0;
    143             else if (strcmp(value, "auto") == 0)
    144                 *needs_root_rights = -1;
    145             else {
    146                 fprintf(stderr,
    147                     "%s: Invalid value '%s' for 'needs_root_rights' at %s line %d\n",
    148                     progname, value, CONFIG_FILE, line);
    149                 exit(1);
    150             }
    151         }
    152         else if (strcmp(key, "nice_value") == 0) {
    153             /* Backward compatibility with older Debian Xwrapper, ignore */
    154         }
    155         else {
    156             fprintf(stderr, "%s: Invalid key '%s' at %s line %d\n", key,
    157                 progname, CONFIG_FILE, line);
    158             exit(1);
    159         }
    160     }
    161     fclose(f);
    162 }
    163 
    164 static int on_console(int fd)
    165 {
    166 #if defined(__linux__)
    167     struct stat st;
    168     int r;
    169 
    170     r = fstat(fd, &st);
    171     if (r == 0 && S_ISCHR(st.st_mode) && major(st.st_rdev) == 4)
    172       return 1;
    173 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
    174     int idx;
    175 
    176     if (ioctl(fd, VT_GETINDEX, &idx) != -1)
    177         return 1;
    178 #else
    179 #warning This program needs porting to your kernel.
    180     static int seen;
    181 
    182     if (!seen) {
    183         fprintf(stderr, "%s: Unable to determine if running on a console\n",
    184             progname);
    185         seen = 1;
    186     }
    187 #endif
    188 
    189     return 0;
    190 }
    191 
    192 int main(int argc, char *argv[])
    193 {
    194 #ifdef WITH_LIBDRM
    195     struct drm_mode_card_res res;
    196 #endif
    197     char buf[PATH_MAX];
    198     int i, r, fd;
    199     int kms_cards = 0;
    200     int total_cards = 0;
    201     int allowed = CONSOLE_ONLY;
    202     int needs_root_rights = -1;
    203     char *const empty_envp[1] = { NULL, };
    204 
    205     progname = argv[0];
    206 
    207     parse_config(&allowed, &needs_root_rights);
    208 
    209     /* For non root users check if they are allowed to run the X server */
    210     if (getuid() != 0) {
    211         switch (allowed) {
    212         case ROOT_ONLY:
    213             /* Already checked above */
    214             fprintf(stderr, "%s: Only root is allowed to run the X server\n", argv[0]);
    215             exit(1);
    216             break;
    217         case CONSOLE_ONLY:
    218             /* Some of stdin / stdout / stderr maybe redirected to a file */
    219             for (i = STDIN_FILENO; i <= STDERR_FILENO; i++) {
    220                 if (on_console(i))
    221                     break;
    222             }
    223             if (i > STDERR_FILENO) {
    224                 fprintf(stderr, "%s: Only console users are allowed to run the X server\n", argv[0]);
    225                 exit(1);
    226             }
    227             break;
    228         case ANYBODY:
    229             break;
    230         }
    231     }
    232 
    233 #ifdef WITH_LIBDRM
    234     /* Detect if we need root rights, except when overridden by the config */
    235     if (needs_root_rights == -1) {
    236         for (i = 0; i < 16; i++) {
    237             snprintf(buf, sizeof(buf), DRM_DEV_NAME, DRM_DIR_NAME, i);
    238             fd = open(buf, O_RDWR);
    239             if (fd == -1)
    240                 continue;
    241 
    242             total_cards++;
    243 
    244             memset(&res, 0, sizeof(struct drm_mode_card_res));
    245             r = ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res);
    246             if (r == 0)
    247                 kms_cards++;
    248 
    249             close(fd);
    250         }
    251     }
    252 #endif
    253 
    254     /* If we've found cards, and all cards support kms, drop root rights */
    255     if (needs_root_rights == 0 || (total_cards && kms_cards == total_cards)) {
    256         gid_t realgid = getgid();
    257         uid_t realuid = getuid();
    258 
    259         if (setresgid(-1, realgid, realgid) != 0) {
    260             fprintf(stderr, "%s: Could not drop setgid privileges: %s\n",
    261                 progname, strerror(errno));
    262             exit(1);
    263         }
    264         if (setresuid(-1, realuid, realuid) != 0) {
    265             fprintf(stderr, "%s: Could not drop setuid privileges: %s\n",
    266                 progname, strerror(errno));
    267             exit(1);
    268         }
    269     }
    270 
    271     snprintf(buf, sizeof(buf), "%s/Xorg", SUID_WRAPPER_DIR);
    272 
    273     /* Check if the server is executable by our real uid */
    274     if (access(buf, X_OK) != 0) {
    275         fprintf(stderr, "%s: Missing execute permissions for %s: %s\n",
    276             progname, buf, strerror(errno));
    277         exit(1);
    278     }
    279 
    280     argv[0] = buf;
    281     if (getuid() == geteuid())
    282         (void) execv(argv[0], argv);
    283     else
    284         (void) execve(argv[0], argv, empty_envp);
    285     fprintf(stderr, "%s: Failed to execute %s: %s\n",
    286         progname, buf, strerror(errno));
    287     exit(1);
    288 }