]> git.sesse.net Git - rdpsrv/blob - Xserver/programs/Xserver/os/wrapper.c
Import X server from vnc-3.3.7.
[rdpsrv] / Xserver / programs / Xserver / os / wrapper.c
1 /*
2  * X server wrapper.
3  *
4  * This wrapper makes some sanity checks on the command line arguments
5  * and environment variables when run with euid == 0 && euid != uid.
6  * If the checks fail, the wrapper exits with a message.
7  * If they succeed, it exec's the Xserver.
8  */
9
10 /*
11  * Copyright (c) 1998 by The XFree86 Project, Inc.  All Rights Reserved.
12  *
13  * Permission is hereby granted, free of charge, to any person obtaining
14  * a copy of this software and associated documentation files (the
15  * "Software"), to deal in the Software without restriction, including
16  * without limitation the rights to use, copy, modify, merge, publish,
17  * distribute, sublicense, and/or sell copies of the Software, and to
18  * permit persons to whom the Software is furnished to do so, subject
19  * to the following conditions:
20  *
21  * The above copyright notice and this permission notice shall be included
22  * in all copies or substantial portions of the Software.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
27  * IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES
28  * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
29  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
30  * OR OTHER DEALINGS IN THE SOFTWARE.
31  *
32  * Except as contained in this notice, the name of the XFree86 Project
33  * shall not be used in advertising or otherwise to promote the sale,
34  * use or other dealings in this Software without prior written
35  * authorization from the XFree86 Project.
36  */
37
38 /* $XFree86: xc/programs/Xserver/os/wrapper.c,v 1.1.2.5 1998/02/27 15:28:59 dawes Exp $ */
39
40 /* This is normally set in the Imakefile */
41 #ifndef XSERVER_PATH
42 #define XSERVER_PATH    "/usr/X11R6/bin/X"
43 #endif
44
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <errno.h>
49 #include <unistd.h>
50
51 /* Neither of these should be required for XFree86 3.3.2 */
52 #ifndef REJECT_CONFIG
53 #define REJECT_CONFIG 0
54 #endif
55 #ifndef REJECT_XKBDIR
56 #define REJECT_XKBDIR 0
57 #endif
58
59 /* Consider LD* variables insecure ? */
60 #ifndef REMOVE_ENV_LD
61 #define REMOVE_ENV_LD 1
62 #endif
63
64 /* Remove long environment variables? */
65 #ifndef REMOVE_LONG_ENV
66 #define REMOVE_LONG_ENV 1
67 #endif
68
69 /* Check args and env only if running setuid (euid == 0 && euid != uid) ? */
70 #ifndef CHECK_EUID
71 #define CHECK_EUID 1
72 #endif
73
74 /*
75  * Maybe the locale can be faked to make isprint(3) report that everything
76  * is printable?  Avoid it by default.
77  */
78 #ifndef USE_ISPRINT
79 #define USE_ISPRINT 0
80 #endif
81
82 #define MAX_ARG_LENGTH          128
83 #define MAX_ENV_LENGTH          256
84 #define MAX_ENV_PATH_LENGTH     2048
85
86 #if USE_ISPRINT
87 #include <ctype.h>
88 #define checkPrintable(c) isprint(c)
89 #else
90 #define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f)
91 #endif
92
93 enum BadCode {
94     NotBad = 0,
95     UnsafeArg,
96     ArgTooLong,
97     UnprintableArg,
98     EnvTooLong,
99     InternalError
100 };
101
102 #define ARGMSG \
103     "\nIf the arguments used are valid, and have been rejected incorrectly\n" \
104       "please send details of the arguments and why they are valid to\n" \
105       "XFree86@XFree86.org.  In the meantime, you can start the Xserver as\n" \
106       "the \"super user\" (root).\n"   
107
108 #define ENVMSG \
109     "\nIf the environment is valid, and have been rejected incorrectly\n" \
110       "please send details of the environment and why it is valid to\n" \
111       "XFree86@XFree86.org.  In the meantime, you can start the Xserver as\n" \
112       "the \"super user\" (root).\n"
113
114 int
115 main(int argc, char **argv, char **envp)
116 {
117     enum BadCode bad = NotBad;
118     int i, j;
119     char *a, *e;
120
121 #if CHECK_EUID
122     if (geteuid() == 0 && getuid() != geteuid()) {
123 #endif
124         /* Check each argv[] */
125         for (i = 1; i < argc; i++) {
126
127             /* Check for known bad arguments */
128 #if REJECT_CONFIG
129             if (strcmp(argv[i], "-config") == 0) {
130                 bad = UnsafeArg;
131                 break;
132             }
133 #endif
134 #if REJECT_XKBDIR
135             if (strcmp(argv[i], "-xkbdir") == 0) {
136                 bad = UnsafeArg;
137                 break;
138             }
139 #endif
140             if (strlen(argv[i]) > MAX_ARG_LENGTH) {
141                 bad = ArgTooLong;
142                 break;
143             }
144             a = argv[i];
145             while (*a) {
146                 if (checkPrintable(*a) == 0) {
147                     bad = UnprintableArg;
148                     break;
149                 }
150                 a++;
151             }
152             if (bad)
153                 break;
154         }
155         /* Check each envp[] */
156         if (!bad)
157             for (i = 0; envp[i]; i++) {
158
159                 /* Check for bad environment variables and values */
160 #if REMOVE_ENV_LD
161                 while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) {
162                     for (j = i; envp[j]; j++) {
163                         envp[j] = envp[j+1];
164                     }
165                 }
166 #endif   
167                 if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) {
168 #if REMOVE_LONG_ENV
169                     for (j = i; envp[j]; j++) {
170                         envp[j] = envp[j+1];
171                     }
172                     i--;
173 #else
174                     char *eq;
175                     int len;
176
177                     eq = strchr(envp[i], '=');
178                     if (!eq)
179                         continue;
180                     len = eq - envp[i];
181                     e = malloc(len + 1);
182                     if (!e) {
183                         bad = InternalError;
184                         break;
185                     }
186                     strncpy(e, envp[i], len);
187                     e[len] = 0;
188                     if (len >= 4 &&
189                         (strcmp(e + len - 4, "PATH") == 0 ||
190                          strcmp(e, "TERMCAP") == 0)) {
191                         if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) {
192                             bad = EnvTooLong;
193                             break;
194                         } else {
195                             free(e);
196                         }
197                     } else {
198                         bad = EnvTooLong;
199                         break;
200                     }
201 #endif
202                 }
203             }
204 #if CHECK_EUID
205     }
206 #endif
207     switch (bad) {
208     case NotBad:
209         execve(XSERVER_PATH, argv, envp);
210         fprintf(stderr, "execve failed for %s (errno %d)\n", XSERVER_PATH,
211                 errno);
212         break;
213     case UnsafeArg:
214         fprintf(stderr, "Command line argument number %d is unsafe\n", i);
215         fprintf(stderr, ARGMSG);
216         break;
217     case ArgTooLong:
218         fprintf(stderr, "Command line argument number %d is too long\n", i);
219         fprintf(stderr, ARGMSG);
220         break;
221     case UnprintableArg:
222         fprintf(stderr, "Command line argument number %d contains unprintable"
223                 " characters\n", i);
224         fprintf(stderr, ARGMSG);
225         break;
226     case EnvTooLong:
227         fprintf(stderr, "Environment variable `%s' is too long\n", e);
228         fprintf(stderr, ENVMSG);
229         break;
230     case InternalError:
231         fprintf(stderr, "Internal Error\n");
232         break;
233     default:
234         fprintf(stderr, "Unknown error\n");
235         fprintf(stderr, ARGMSG);
236         fprintf(stderr, ENVMSG);
237         break;
238     }
239     exit(1);
240 }
241