Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /* |
2 | ||
3 | Copyright 1987, 1998 The Open Group | |
4 | ||
5 | Permission to use, copy, modify, distribute, and sell this software and its | |
6 | documentation for any purpose is hereby granted without fee, provided that | |
7 | the above copyright notice appear in all copies and that both that | |
8 | copyright notice and this permission notice appear in supporting | |
9 | documentation. | |
10 | ||
11 | The above copyright notice and this permission notice shall be included | |
12 | in all copies or substantial portions of the Software. | |
13 | ||
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
15 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
17 | IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
18 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
19 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
20 | OTHER DEALINGS IN THE SOFTWARE. | |
21 | ||
22 | Except as contained in this notice, the name of The Open Group shall | |
23 | not be used in advertising or otherwise to promote the sale, use or | |
24 | other dealings in this Software without prior written authorization | |
25 | from The Open Group. | |
26 | ||
27 | Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, | |
28 | Copyright 1994 Quarterdeck Office Systems. | |
29 | ||
30 | All Rights Reserved | |
31 | ||
32 | Permission to use, copy, modify, and distribute this software and its | |
33 | documentation for any purpose and without fee is hereby granted, | |
34 | provided that the above copyright notice appear in all copies and that | |
35 | both that copyright notice and this permission notice appear in | |
36 | supporting documentation, and that the names of Digital and | |
37 | Quarterdeck not be used in advertising or publicity pertaining to | |
38 | distribution of the software without specific, written prior | |
39 | permission. | |
40 | ||
41 | DIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS | |
42 | SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
43 | FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT | |
44 | OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS | |
45 | OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE | |
46 | OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE | |
47 | OR PERFORMANCE OF THIS SOFTWARE. | |
48 | ||
49 | */ | |
50 | ||
51 | #ifdef HAVE_DIX_CONFIG_H | |
52 | #include <dix-config.h> | |
53 | #endif | |
54 | ||
55 | #ifdef __CYGWIN__ | |
56 | #include <stdlib.h> | |
57 | #include <signal.h> | |
58 | /* | |
59 | Sigh... We really need a prototype for this to know it is stdcall, | |
60 | but #include-ing <windows.h> here is not a good idea... | |
61 | */ | |
62 | __stdcall unsigned long GetTickCount(void); | |
63 | #endif | |
64 | ||
65 | #if defined(WIN32) && !defined(__CYGWIN__) | |
66 | #include <X11/Xwinsock.h> | |
67 | #endif | |
68 | #include <X11/Xos.h> | |
69 | #include <stdio.h> | |
70 | #include <time.h> | |
71 | #if !defined(WIN32) || !defined(__MINGW32__) | |
72 | #include <sys/time.h> | |
73 | #include <sys/resource.h> | |
74 | # define SMART_SCHEDULE_POSSIBLE | |
75 | #endif | |
76 | #include "misc.h" | |
77 | #include <X11/X.h> | |
78 | #define XSERV_t | |
79 | #define TRANS_SERVER | |
80 | #define TRANS_REOPEN | |
81 | #include <X11/Xtrans/Xtrans.h> | |
82 | #include "input.h" | |
83 | #include "dixfont.h" | |
84 | #include "osdep.h" | |
85 | #include "extension.h" | |
86 | #ifdef X_POSIX_C_SOURCE | |
87 | #define _POSIX_C_SOURCE X_POSIX_C_SOURCE | |
88 | #include <signal.h> | |
89 | #undef _POSIX_C_SOURCE | |
90 | #else | |
91 | #if defined(_POSIX_SOURCE) | |
92 | #include <signal.h> | |
93 | #else | |
94 | #define _POSIX_SOURCE | |
95 | #include <signal.h> | |
96 | #undef _POSIX_SOURCE | |
97 | #endif | |
98 | #endif | |
99 | #ifndef WIN32 | |
100 | #include <sys/wait.h> | |
101 | #endif | |
102 | #if !defined(SYSV) && !defined(WIN32) | |
103 | #include <sys/resource.h> | |
104 | #endif | |
105 | #include <sys/stat.h> | |
106 | #include <ctype.h> /* for isspace */ | |
107 | #include <stdarg.h> | |
108 | ||
109 | #include <stdlib.h> /* for malloc() */ | |
110 | ||
111 | #if defined(TCPCONN) || defined(STREAMSCONN) | |
112 | #ifndef WIN32 | |
113 | #include <netdb.h> | |
114 | #endif | |
115 | #endif | |
116 | ||
117 | #include "opaque.h" | |
118 | ||
119 | #include "dixstruct.h" | |
120 | ||
121 | #include "xkbsrv.h" | |
122 | ||
123 | #include "picture.h" | |
124 | ||
125 | Bool noTestExtensions; | |
126 | ||
127 | #ifdef COMPOSITE | |
128 | Bool noCompositeExtension = FALSE; | |
129 | #endif | |
130 | ||
131 | #ifdef DAMAGE | |
132 | Bool noDamageExtension = FALSE; | |
133 | #endif | |
134 | #ifdef DBE | |
135 | Bool noDbeExtension = FALSE; | |
136 | #endif | |
137 | #ifdef DPMSExtension | |
138 | Bool noDPMSExtension = FALSE; | |
139 | #endif | |
140 | #ifdef GLXEXT | |
141 | Bool noGlxExtension = FALSE; | |
142 | #endif | |
143 | #ifdef SCREENSAVER | |
144 | Bool noScreenSaverExtension = FALSE; | |
145 | #endif | |
146 | #ifdef MITSHM | |
147 | Bool noMITShmExtension = FALSE; | |
148 | #endif | |
149 | #ifdef RANDR | |
150 | Bool noRRExtension = FALSE; | |
151 | #endif | |
152 | Bool noRenderExtension = FALSE; | |
153 | ||
154 | #ifdef XCSECURITY | |
155 | Bool noSecurityExtension = FALSE; | |
156 | #endif | |
157 | #ifdef RES | |
158 | Bool noResExtension = FALSE; | |
159 | #endif | |
160 | #ifdef XF86BIGFONT | |
161 | Bool noXFree86BigfontExtension = FALSE; | |
162 | #endif | |
163 | #ifdef XFreeXDGA | |
164 | Bool noXFree86DGAExtension = FALSE; | |
165 | #endif | |
166 | #ifdef XF86DRI | |
167 | Bool noXFree86DRIExtension = FALSE; | |
168 | #endif | |
169 | #ifdef XF86VIDMODE | |
170 | Bool noXFree86VidModeExtension = FALSE; | |
171 | #endif | |
172 | Bool noXFixesExtension = FALSE; | |
173 | #ifdef PANORAMIX | |
174 | /* Xinerama is disabled by default unless enabled via +xinerama */ | |
175 | Bool noPanoramiXExtension = TRUE; | |
176 | #endif | |
177 | #ifdef XSELINUX | |
178 | Bool noSELinuxExtension = FALSE; | |
179 | int selinuxEnforcingState = SELINUX_MODE_DEFAULT; | |
180 | #endif | |
181 | #ifdef XV | |
182 | Bool noXvExtension = FALSE; | |
183 | #endif | |
184 | #ifdef DRI2 | |
185 | Bool noDRI2Extension = FALSE; | |
186 | #endif | |
187 | ||
188 | Bool noGEExtension = FALSE; | |
189 | ||
190 | #define X_INCLUDE_NETDB_H | |
191 | #include <X11/Xos_r.h> | |
192 | ||
193 | #include <errno.h> | |
194 | ||
195 | Bool CoreDump; | |
196 | ||
197 | #ifdef PANORAMIX | |
198 | Bool PanoramiXExtensionDisabledHack = FALSE; | |
199 | #endif | |
200 | ||
201 | int auditTrailLevel = 1; | |
202 | ||
203 | char *SeatId = NULL; | |
204 | ||
205 | sig_atomic_t inSignalContext = FALSE; | |
206 | ||
207 | #if defined(SVR4) || defined(__linux__) || defined(CSRG_BASED) | |
208 | #define HAS_SAVED_IDS_AND_SETEUID | |
209 | #endif | |
210 | ||
211 | OsSigHandlerPtr | |
212 | OsSignal(int sig, OsSigHandlerPtr handler) | |
213 | { | |
214 | #if defined(WIN32) && !defined(__CYGWIN__) | |
215 | return signal(sig, handler); | |
216 | #else | |
217 | struct sigaction act, oact; | |
218 | ||
219 | sigemptyset(&act.sa_mask); | |
220 | if (handler != SIG_IGN) | |
221 | sigaddset(&act.sa_mask, sig); | |
222 | act.sa_flags = 0; | |
223 | act.sa_handler = handler; | |
224 | if (sigaction(sig, &act, &oact)) | |
225 | perror("sigaction"); | |
226 | return oact.sa_handler; | |
227 | #endif | |
228 | } | |
229 | ||
230 | /* | |
231 | * Explicit support for a server lock file like the ones used for UUCP. | |
232 | * For architectures with virtual terminals that can run more than one | |
233 | * server at a time. This keeps the servers from stomping on each other | |
234 | * if the user forgets to give them different display numbers. | |
235 | */ | |
236 | #define LOCK_DIR "/tmp" | |
237 | #define LOCK_TMP_PREFIX "/.tX" | |
238 | #define LOCK_PREFIX "/.X" | |
239 | #define LOCK_SUFFIX "-lock" | |
240 | ||
241 | #if !defined(WIN32) || defined(__CYGWIN__) | |
242 | #define LOCK_SERVER | |
243 | #endif | |
244 | ||
245 | #ifndef LOCK_SERVER | |
246 | void | |
247 | LockServer(void) | |
248 | {} | |
249 | ||
250 | void | |
251 | UnlockServer(void) | |
252 | {} | |
253 | #else /* LOCK_SERVER */ | |
254 | static Bool StillLocking = FALSE; | |
255 | static char LockFile[PATH_MAX]; | |
256 | static Bool nolock = FALSE; | |
257 | ||
258 | /* | |
259 | * LockServer -- | |
260 | * Check if the server lock file exists. If so, check if the PID | |
261 | * contained inside is valid. If so, then die. Otherwise, create | |
262 | * the lock file containing the PID. | |
263 | */ | |
264 | void | |
265 | LockServer(void) | |
266 | { | |
267 | char tmp[PATH_MAX], pid_str[12]; | |
268 | int lfd, i, haslock, l_pid, t; | |
269 | const char *tmppath = LOCK_DIR; | |
270 | int len; | |
271 | char port[20]; | |
272 | ||
273 | if (nolock) | |
274 | return; | |
275 | /* | |
276 | * Path names | |
277 | */ | |
278 | snprintf(port, sizeof(port), "%d", atoi(display)); | |
279 | len = strlen(LOCK_PREFIX) > strlen(LOCK_TMP_PREFIX) ? strlen(LOCK_PREFIX) : | |
280 | strlen(LOCK_TMP_PREFIX); | |
281 | len += strlen(tmppath) + strlen(port) + strlen(LOCK_SUFFIX) + 1; | |
282 | if (len > sizeof(LockFile)) | |
283 | FatalError("Display name `%s' is too long\n", port); | |
284 | (void) sprintf(tmp, "%s" LOCK_TMP_PREFIX "%s" LOCK_SUFFIX, tmppath, port); | |
285 | (void) sprintf(LockFile, "%s" LOCK_PREFIX "%s" LOCK_SUFFIX, tmppath, port); | |
286 | ||
287 | /* | |
288 | * Create a temporary file containing our PID. Attempt three times | |
289 | * to create the file. | |
290 | */ | |
291 | StillLocking = TRUE; | |
292 | i = 0; | |
293 | do { | |
294 | i++; | |
295 | lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644); | |
296 | if (lfd < 0) | |
297 | sleep(2); | |
298 | else | |
299 | break; | |
300 | } while (i < 3); | |
301 | if (lfd < 0) { | |
302 | unlink(tmp); | |
303 | i = 0; | |
304 | do { | |
305 | i++; | |
306 | lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644); | |
307 | if (lfd < 0) | |
308 | sleep(2); | |
309 | else | |
310 | break; | |
311 | } while (i < 3); | |
312 | } | |
313 | if (lfd < 0) | |
314 | FatalError("Could not create lock file in %s\n", tmp); | |
315 | snprintf(pid_str, sizeof(pid_str), "%10ld\n", (long) getpid()); | |
316 | (void) write(lfd, pid_str, 11); | |
317 | (void) fchmod(lfd, 0444); | |
318 | (void) close(lfd); | |
319 | ||
320 | /* | |
321 | * OK. Now the tmp file exists. Try three times to move it in place | |
322 | * for the lock. | |
323 | */ | |
324 | i = 0; | |
325 | haslock = 0; | |
326 | while ((!haslock) && (i++ < 3)) { | |
327 | haslock = (link(tmp, LockFile) == 0); | |
328 | if (haslock) { | |
329 | /* | |
330 | * We're done. | |
331 | */ | |
332 | break; | |
333 | } | |
334 | else { | |
335 | /* | |
336 | * Read the pid from the existing file | |
337 | */ | |
338 | lfd = open(LockFile, O_RDONLY | O_NOFOLLOW); | |
339 | if (lfd < 0) { | |
340 | unlink(tmp); | |
341 | FatalError("Can't read lock file %s\n", LockFile); | |
342 | } | |
343 | pid_str[0] = '\0'; | |
344 | if (read(lfd, pid_str, 11) != 11) { | |
345 | /* | |
346 | * Bogus lock file. | |
347 | */ | |
348 | unlink(LockFile); | |
349 | close(lfd); | |
350 | continue; | |
351 | } | |
352 | pid_str[11] = '\0'; | |
353 | sscanf(pid_str, "%d", &l_pid); | |
354 | close(lfd); | |
355 | ||
356 | /* | |
357 | * Now try to kill the PID to see if it exists. | |
358 | */ | |
359 | errno = 0; | |
360 | t = kill(l_pid, 0); | |
361 | if ((t < 0) && (errno == ESRCH)) { | |
362 | /* | |
363 | * Stale lock file. | |
364 | */ | |
365 | unlink(LockFile); | |
366 | continue; | |
367 | } | |
368 | else if (((t < 0) && (errno == EPERM)) || (t == 0)) { | |
369 | /* | |
370 | * Process is still active. | |
371 | */ | |
372 | unlink(tmp); | |
373 | FatalError | |
374 | ("Server is already active for display %s\n%s %s\n%s\n", | |
375 | port, "\tIf this server is no longer running, remove", | |
376 | LockFile, "\tand start again."); | |
377 | } | |
378 | } | |
379 | } | |
380 | unlink(tmp); | |
381 | if (!haslock) | |
382 | FatalError("Could not create server lock file: %s\n", LockFile); | |
383 | StillLocking = FALSE; | |
384 | } | |
385 | ||
386 | /* | |
387 | * UnlockServer -- | |
388 | * Remove the server lock file. | |
389 | */ | |
390 | void | |
391 | UnlockServer(void) | |
392 | { | |
393 | if (nolock) | |
394 | return; | |
395 | ||
396 | if (!StillLocking) { | |
397 | ||
398 | (void) unlink(LockFile); | |
399 | } | |
400 | } | |
401 | #endif /* LOCK_SERVER */ | |
402 | ||
403 | /* Force connections to close on SIGHUP from init */ | |
404 | ||
405 | void | |
406 | AutoResetServer(int sig) | |
407 | { | |
408 | int olderrno = errno; | |
409 | ||
410 | dispatchException |= DE_RESET; | |
411 | isItTimeToYield = TRUE; | |
412 | errno = olderrno; | |
413 | } | |
414 | ||
415 | /* Force connections to close and then exit on SIGTERM, SIGINT */ | |
416 | ||
417 | void | |
418 | GiveUp(int sig) | |
419 | { | |
420 | int olderrno = errno; | |
421 | ||
422 | dispatchException |= DE_TERMINATE; | |
423 | isItTimeToYield = TRUE; | |
424 | errno = olderrno; | |
425 | } | |
426 | ||
427 | #if (defined WIN32 && defined __MINGW32__) || defined(__CYGWIN__) | |
428 | CARD32 | |
429 | GetTimeInMillis(void) | |
430 | { | |
431 | return GetTickCount(); | |
432 | } | |
433 | CARD64 | |
434 | GetTimeInMicros(void) | |
435 | { | |
436 | return (CARD64) GetTickCount() * 1000; | |
437 | } | |
438 | #else | |
439 | CARD32 | |
440 | GetTimeInMillis(void) | |
441 | { | |
442 | struct timeval tv; | |
443 | ||
444 | #ifdef MONOTONIC_CLOCK | |
445 | struct timespec tp; | |
446 | static clockid_t clockid; | |
447 | ||
448 | if (!clockid) { | |
449 | #ifdef CLOCK_MONOTONIC_COARSE | |
450 | if (clock_getres(CLOCK_MONOTONIC_COARSE, &tp) == 0 && | |
451 | (tp.tv_nsec / 1000) <= 1000 && | |
452 | clock_gettime(CLOCK_MONOTONIC_COARSE, &tp) == 0) | |
453 | clockid = CLOCK_MONOTONIC_COARSE; | |
454 | else | |
455 | #endif | |
456 | if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) | |
457 | clockid = CLOCK_MONOTONIC; | |
458 | else | |
459 | clockid = ~0L; | |
460 | } | |
461 | if (clockid != ~0L && clock_gettime(clockid, &tp) == 0) | |
462 | return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L); | |
463 | #endif | |
464 | ||
465 | X_GETTIMEOFDAY(&tv); | |
466 | return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); | |
467 | } | |
468 | ||
469 | CARD64 | |
470 | GetTimeInMicros(void) | |
471 | { | |
472 | struct timeval tv; | |
473 | #ifdef MONOTONIC_CLOCK | |
474 | struct timespec tp; | |
475 | static clockid_t clockid; | |
476 | ||
477 | if (!clockid) { | |
478 | if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) | |
479 | clockid = CLOCK_MONOTONIC; | |
480 | else | |
481 | clockid = ~0L; | |
482 | } | |
483 | if (clockid != ~0L && clock_gettime(clockid, &tp) == 0) | |
484 | return (CARD64) tp.tv_sec * (CARD64)1000000 + tp.tv_nsec / 1000; | |
485 | #endif | |
486 | ||
487 | X_GETTIMEOFDAY(&tv); | |
488 | return (CARD64) tv.tv_sec * (CARD64)1000000000 + (CARD64) tv.tv_usec * 1000; | |
489 | } | |
490 | #endif | |
491 | ||
492 | void | |
493 | AdjustWaitForDelay(pointer waitTime, unsigned long newdelay) | |
494 | { | |
495 | static struct timeval delay_val; | |
496 | struct timeval **wt = (struct timeval **) waitTime; | |
497 | unsigned long olddelay; | |
498 | ||
499 | if (*wt == NULL) { | |
500 | delay_val.tv_sec = newdelay / 1000; | |
501 | delay_val.tv_usec = 1000 * (newdelay % 1000); | |
502 | *wt = &delay_val; | |
503 | } | |
504 | else { | |
505 | olddelay = (*wt)->tv_sec * 1000 + (*wt)->tv_usec / 1000; | |
506 | if (newdelay < olddelay) { | |
507 | (*wt)->tv_sec = newdelay / 1000; | |
508 | (*wt)->tv_usec = 1000 * (newdelay % 1000); | |
509 | } | |
510 | } | |
511 | } | |
512 | ||
513 | void | |
514 | UseMsg(void) | |
515 | { | |
516 | ErrorF("use: X [:<display>] [option]\n"); | |
517 | ErrorF("-a # default pointer acceleration (factor)\n"); | |
518 | ErrorF("-ac disable access control restrictions\n"); | |
519 | ErrorF("-audit int set audit trail level\n"); | |
520 | ErrorF("-auth file select authorization file\n"); | |
521 | ErrorF("-br create root window with black background\n"); | |
522 | ErrorF("+bs enable any backing store support\n"); | |
523 | ErrorF("-bs disable any backing store support\n"); | |
524 | ErrorF("-c turns off key-click\n"); | |
525 | ErrorF("c # key-click volume (0-100)\n"); | |
526 | ErrorF("-cc int default color visual class\n"); | |
527 | ErrorF("-nocursor disable the cursor\n"); | |
528 | ErrorF("-core generate core dump on fatal error\n"); | |
529 | ErrorF("-dpi int screen resolution in dots per inch\n"); | |
530 | #ifdef DPMSExtension | |
531 | ErrorF("-dpms disables VESA DPMS monitor control\n"); | |
532 | #endif | |
533 | ErrorF | |
534 | ("-deferglyphs [none|all|16] defer loading of [no|all|16-bit] glyphs\n"); | |
535 | ErrorF("-f # bell base (0-100)\n"); | |
536 | ErrorF("-fc string cursor font\n"); | |
537 | ErrorF("-fn string default font name\n"); | |
538 | ErrorF("-fp string default font path\n"); | |
539 | ErrorF("-help prints message with these options\n"); | |
540 | ErrorF("-I ignore all remaining arguments\n"); | |
541 | #ifdef RLIMIT_DATA | |
542 | ErrorF("-ld int limit data space to N Kb\n"); | |
543 | #endif | |
544 | #ifdef RLIMIT_NOFILE | |
545 | ErrorF("-lf int limit number of open files to N\n"); | |
546 | #endif | |
547 | #ifdef RLIMIT_STACK | |
548 | ErrorF("-ls int limit stack space to N Kb\n"); | |
549 | #endif | |
550 | #ifdef LOCK_SERVER | |
551 | ErrorF("-nolock disable the locking mechanism\n"); | |
552 | #endif | |
553 | ErrorF("-nolisten string don't listen on protocol\n"); | |
554 | ErrorF("-noreset don't reset after last client exists\n"); | |
555 | ErrorF("-background [none] create root window with no background\n"); | |
556 | ErrorF("-reset reset after last client exists\n"); | |
557 | ErrorF("-p # screen-saver pattern duration (minutes)\n"); | |
558 | ErrorF("-pn accept failure to listen on all ports\n"); | |
559 | ErrorF("-nopn reject failure to listen on all ports\n"); | |
560 | ErrorF("-r turns off auto-repeat\n"); | |
561 | ErrorF("r turns on auto-repeat \n"); | |
562 | ErrorF("-render [default|mono|gray|color] set render color alloc policy\n"); | |
563 | ErrorF("-retro start with classic stipple and cursor\n"); | |
564 | ErrorF("-s # screen-saver timeout (minutes)\n"); | |
565 | ErrorF("-seat string seat to run on\n"); | |
566 | ErrorF("-t # default pointer threshold (pixels/t)\n"); | |
567 | ErrorF("-terminate terminate at server reset\n"); | |
568 | ErrorF("-to # connection time out\n"); | |
569 | ErrorF("-tst disable testing extensions\n"); | |
570 | ErrorF("ttyxx server started from init on /dev/ttyxx\n"); | |
571 | ErrorF("v video blanking for screen-saver\n"); | |
572 | ErrorF("-v screen-saver without video blanking\n"); | |
573 | ErrorF("-wm WhenMapped default backing-store\n"); | |
574 | ErrorF("-wr create root window with white background\n"); | |
575 | ErrorF("-maxbigreqsize set maximal bigrequest size \n"); | |
576 | #ifdef PANORAMIX | |
577 | ErrorF("+xinerama Enable XINERAMA extension\n"); | |
578 | ErrorF("-xinerama Disable XINERAMA extension\n"); | |
579 | #endif | |
580 | ErrorF | |
581 | ("-dumbSched Disable smart scheduling, enable old behavior\n"); | |
582 | ErrorF("-schedInterval int Set scheduler interval in msec\n"); | |
583 | ErrorF("-sigstop Enable SIGSTOP based startup\n"); | |
584 | ErrorF("+extension name Enable extension\n"); | |
585 | ErrorF("-extension name Disable extension\n"); | |
586 | #ifdef XDMCP | |
587 | XdmcpUseMsg(); | |
588 | #endif | |
589 | XkbUseMsg(); | |
590 | ddxUseMsg(); | |
591 | } | |
592 | ||
593 | /* This function performs a rudimentary sanity check | |
594 | * on the display name passed in on the command-line, | |
595 | * since this string is used to generate filenames. | |
596 | * It is especially important that the display name | |
597 | * not contain a "/" and not start with a "-". | |
598 | * --kvajk | |
599 | */ | |
600 | static int | |
601 | VerifyDisplayName(const char *d) | |
602 | { | |
603 | int i; | |
604 | int period_found = FALSE; | |
605 | int after_period = 0; | |
606 | ||
607 | if (d == (char *) 0) | |
608 | return 0; /* null */ | |
609 | if (*d == '\0') | |
610 | return 0; /* empty */ | |
611 | if (*d == '-') | |
612 | return 0; /* could be confused for an option */ | |
613 | if (*d == '.') | |
614 | return 0; /* must not equal "." or ".." */ | |
615 | if (strchr(d, '/') != (char *) 0) | |
616 | return 0; /* very important!!! */ | |
617 | ||
618 | /* Since we run atoi() on the display later, only allow | |
619 | for digits, or exception of :0.0 and similar (two decimal points max) | |
620 | */ | |
621 | for (i = 0; i < strlen(d); i++) { | |
622 | if (!isdigit(d[i])) { | |
623 | if (d[i] != '.' || period_found) | |
624 | return 0; | |
625 | period_found = TRUE; | |
626 | } else if (period_found) | |
627 | after_period++; | |
628 | ||
629 | if (after_period > 2) | |
630 | return 0; | |
631 | } | |
632 | ||
633 | /* don't allow for :0. */ | |
634 | if (period_found && after_period == 0) | |
635 | return 0; | |
636 | ||
637 | if (atol(d) > INT_MAX) | |
638 | return 0; | |
639 | ||
640 | return 1; | |
641 | } | |
642 | ||
643 | /* | |
644 | * This function parses the command line. Handles device-independent fields | |
645 | * and allows ddx to handle additional fields. It is not allowed to modify | |
646 | * argc or any of the strings pointed to by argv. | |
647 | */ | |
648 | void | |
649 | ProcessCommandLine(int argc, char *argv[]) | |
650 | { | |
651 | int i, skip; | |
652 | ||
653 | defaultKeyboardControl.autoRepeat = TRUE; | |
654 | ||
655 | #ifdef NO_PART_NET | |
656 | PartialNetwork = FALSE; | |
657 | #else | |
658 | PartialNetwork = TRUE; | |
659 | #endif | |
660 | ||
661 | for (i = 1; i < argc; i++) { | |
662 | /* call ddx first, so it can peek/override if it wants */ | |
663 | if ((skip = ddxProcessArgument(argc, argv, i))) { | |
664 | i += (skip - 1); | |
665 | } | |
666 | else if (argv[i][0] == ':') { | |
667 | /* initialize display */ | |
668 | display = argv[i]; | |
669 | display++; | |
670 | if (!VerifyDisplayName(display)) { | |
671 | ErrorF("Bad display name: %s\n", display); | |
672 | UseMsg(); | |
673 | FatalError("Bad display name, exiting: %s\n", display); | |
674 | } | |
675 | } | |
676 | else if (strcmp(argv[i], "-a") == 0) { | |
677 | if (++i < argc) | |
678 | defaultPointerControl.num = atoi(argv[i]); | |
679 | else | |
680 | UseMsg(); | |
681 | } | |
682 | else if (strcmp(argv[i], "-ac") == 0) { | |
683 | defeatAccessControl = TRUE; | |
684 | } | |
685 | else if (strcmp(argv[i], "-audit") == 0) { | |
686 | if (++i < argc) | |
687 | auditTrailLevel = atoi(argv[i]); | |
688 | else | |
689 | UseMsg(); | |
690 | } | |
691 | else if (strcmp(argv[i], "-auth") == 0) { | |
692 | if (++i < argc) | |
693 | InitAuthorization(argv[i]); | |
694 | else | |
695 | UseMsg(); | |
696 | } | |
697 | else if (strcmp(argv[i], "-br") == 0); /* default */ | |
698 | else if (strcmp(argv[i], "+bs") == 0) | |
699 | enableBackingStore = TRUE; | |
700 | else if (strcmp(argv[i], "-bs") == 0) | |
701 | disableBackingStore = TRUE; | |
702 | else if (strcmp(argv[i], "c") == 0) { | |
703 | if (++i < argc) | |
704 | defaultKeyboardControl.click = atoi(argv[i]); | |
705 | else | |
706 | UseMsg(); | |
707 | } | |
708 | else if (strcmp(argv[i], "-c") == 0) { | |
709 | defaultKeyboardControl.click = 0; | |
710 | } | |
711 | else if (strcmp(argv[i], "-cc") == 0) { | |
712 | if (++i < argc) | |
713 | defaultColorVisualClass = atoi(argv[i]); | |
714 | else | |
715 | UseMsg(); | |
716 | } | |
717 | else if (strcmp(argv[i], "-core") == 0) { | |
718 | #if !defined(WIN32) || !defined(__MINGW32__) | |
719 | struct rlimit core_limit; | |
720 | ||
721 | getrlimit(RLIMIT_CORE, &core_limit); | |
722 | core_limit.rlim_cur = core_limit.rlim_max; | |
723 | setrlimit(RLIMIT_CORE, &core_limit); | |
724 | #endif | |
725 | CoreDump = TRUE; | |
726 | } | |
727 | else if (strcmp(argv[i], "-nocursor") == 0) { | |
728 | EnableCursor = FALSE; | |
729 | } | |
730 | else if (strcmp(argv[i], "-dpi") == 0) { | |
731 | if (++i < argc) | |
732 | monitorResolution = atoi(argv[i]); | |
733 | else | |
734 | UseMsg(); | |
735 | } | |
736 | else if (strcmp(argv[i], "-displayfd") == 0) { | |
737 | if (++i < argc) { | |
738 | displayfd = atoi(argv[i]); | |
739 | display = NULL; | |
740 | #ifdef LOCK_SERVER | |
741 | nolock = TRUE; | |
742 | #endif | |
743 | } | |
744 | else | |
745 | UseMsg(); | |
746 | } | |
747 | #ifdef DPMSExtension | |
748 | else if (strcmp(argv[i], "dpms") == 0) | |
749 | /* ignored for compatibility */ ; | |
750 | else if (strcmp(argv[i], "-dpms") == 0) | |
751 | DPMSDisabledSwitch = TRUE; | |
752 | #endif | |
753 | else if (strcmp(argv[i], "-deferglyphs") == 0) { | |
754 | if (++i >= argc || !ParseGlyphCachingMode(argv[i])) | |
755 | UseMsg(); | |
756 | } | |
757 | else if (strcmp(argv[i], "-f") == 0) { | |
758 | if (++i < argc) | |
759 | defaultKeyboardControl.bell = atoi(argv[i]); | |
760 | else | |
761 | UseMsg(); | |
762 | } | |
763 | else if (strcmp(argv[i], "-fc") == 0) { | |
764 | if (++i < argc) | |
765 | defaultCursorFont = argv[i]; | |
766 | else | |
767 | UseMsg(); | |
768 | } | |
769 | else if (strcmp(argv[i], "-fn") == 0) { | |
770 | if (++i < argc) | |
771 | defaultTextFont = argv[i]; | |
772 | else | |
773 | UseMsg(); | |
774 | } | |
775 | else if (strcmp(argv[i], "-fp") == 0) { | |
776 | if (++i < argc) { | |
777 | defaultFontPath = argv[i]; | |
778 | } | |
779 | else | |
780 | UseMsg(); | |
781 | } | |
782 | else if (strcmp(argv[i], "-help") == 0) { | |
783 | UseMsg(); | |
784 | exit(0); | |
785 | } | |
786 | else if ((skip = XkbProcessArguments(argc, argv, i)) != 0) { | |
787 | if (skip > 0) | |
788 | i += skip - 1; | |
789 | else | |
790 | UseMsg(); | |
791 | } | |
792 | #ifdef RLIMIT_DATA | |
793 | else if (strcmp(argv[i], "-ld") == 0) { | |
794 | if (++i < argc) { | |
795 | limitDataSpace = atoi(argv[i]); | |
796 | if (limitDataSpace > 0) | |
797 | limitDataSpace *= 1024; | |
798 | } | |
799 | else | |
800 | UseMsg(); | |
801 | } | |
802 | #endif | |
803 | #ifdef RLIMIT_NOFILE | |
804 | else if (strcmp(argv[i], "-lf") == 0) { | |
805 | if (++i < argc) | |
806 | limitNoFile = atoi(argv[i]); | |
807 | else | |
808 | UseMsg(); | |
809 | } | |
810 | #endif | |
811 | #ifdef RLIMIT_STACK | |
812 | else if (strcmp(argv[i], "-ls") == 0) { | |
813 | if (++i < argc) { | |
814 | limitStackSpace = atoi(argv[i]); | |
815 | if (limitStackSpace > 0) | |
816 | limitStackSpace *= 1024; | |
817 | } | |
818 | else | |
819 | UseMsg(); | |
820 | } | |
821 | #endif | |
822 | #ifdef LOCK_SERVER | |
823 | else if (strcmp(argv[i], "-nolock") == 0) { | |
824 | #if !defined(WIN32) && !defined(__CYGWIN__) | |
825 | if (getuid() != 0) | |
826 | ErrorF | |
827 | ("Warning: the -nolock option can only be used by root\n"); | |
828 | else | |
829 | #endif | |
830 | nolock = TRUE; | |
831 | } | |
832 | #endif | |
833 | else if (strcmp(argv[i], "-nolisten") == 0) { | |
834 | if (++i < argc) { | |
835 | if (_XSERVTransNoListen(argv[i])) | |
836 | ErrorF("Failed to disable listen for %s transport", | |
837 | argv[i]); | |
838 | } | |
839 | else | |
840 | UseMsg(); | |
841 | } | |
842 | else if (strcmp(argv[i], "-noreset") == 0) { | |
843 | dispatchExceptionAtReset = 0; | |
844 | } | |
845 | else if (strcmp(argv[i], "-reset") == 0) { | |
846 | dispatchExceptionAtReset = DE_RESET; | |
847 | } | |
848 | else if (strcmp(argv[i], "-p") == 0) { | |
849 | if (++i < argc) | |
850 | defaultScreenSaverInterval = ((CARD32) atoi(argv[i])) * | |
851 | MILLI_PER_MIN; | |
852 | else | |
853 | UseMsg(); | |
854 | } | |
855 | else if (strcmp(argv[i], "-pogo") == 0) { | |
856 | dispatchException = DE_TERMINATE; | |
857 | } | |
858 | else if (strcmp(argv[i], "-pn") == 0) | |
859 | PartialNetwork = TRUE; | |
860 | else if (strcmp(argv[i], "-nopn") == 0) | |
861 | PartialNetwork = FALSE; | |
862 | else if (strcmp(argv[i], "r") == 0) | |
863 | defaultKeyboardControl.autoRepeat = TRUE; | |
864 | else if (strcmp(argv[i], "-r") == 0) | |
865 | defaultKeyboardControl.autoRepeat = FALSE; | |
866 | else if (strcmp(argv[i], "-retro") == 0) | |
867 | party_like_its_1989 = TRUE; | |
868 | else if (strcmp(argv[i], "-s") == 0) { | |
869 | if (++i < argc) | |
870 | defaultScreenSaverTime = ((CARD32) atoi(argv[i])) * | |
871 | MILLI_PER_MIN; | |
872 | else | |
873 | UseMsg(); | |
874 | } | |
875 | else if (strcmp(argv[i], "-seat") == 0) { | |
876 | if (++i < argc) | |
877 | SeatId = argv[i]; | |
878 | else | |
879 | UseMsg(); | |
880 | } | |
881 | else if (strcmp(argv[i], "-t") == 0) { | |
882 | if (++i < argc) | |
883 | defaultPointerControl.threshold = atoi(argv[i]); | |
884 | else | |
885 | UseMsg(); | |
886 | } | |
887 | else if (strcmp(argv[i], "-terminate") == 0) { | |
888 | dispatchExceptionAtReset = DE_TERMINATE; | |
889 | } | |
890 | else if (strcmp(argv[i], "-to") == 0) { | |
891 | if (++i < argc) | |
892 | TimeOutValue = ((CARD32) atoi(argv[i])) * MILLI_PER_SECOND; | |
893 | else | |
894 | UseMsg(); | |
895 | } | |
896 | else if (strcmp(argv[i], "-tst") == 0) { | |
897 | noTestExtensions = TRUE; | |
898 | } | |
899 | else if (strcmp(argv[i], "v") == 0) | |
900 | defaultScreenSaverBlanking = PreferBlanking; | |
901 | else if (strcmp(argv[i], "-v") == 0) | |
902 | defaultScreenSaverBlanking = DontPreferBlanking; | |
903 | else if (strcmp(argv[i], "-wm") == 0) | |
904 | defaultBackingStore = WhenMapped; | |
905 | else if (strcmp(argv[i], "-wr") == 0) | |
906 | whiteRoot = TRUE; | |
907 | else if (strcmp(argv[i], "-background") == 0) { | |
908 | if (++i < argc) { | |
909 | if (!strcmp(argv[i], "none")) | |
910 | bgNoneRoot = TRUE; | |
911 | else | |
912 | UseMsg(); | |
913 | } | |
914 | } | |
915 | else if (strcmp(argv[i], "-maxbigreqsize") == 0) { | |
916 | if (++i < argc) { | |
917 | long reqSizeArg = atol(argv[i]); | |
918 | ||
919 | /* Request size > 128MB does not make much sense... */ | |
920 | if (reqSizeArg > 0L && reqSizeArg < 128L) { | |
921 | maxBigRequestSize = (reqSizeArg * 1048576L) - 1L; | |
922 | } | |
923 | else { | |
924 | UseMsg(); | |
925 | } | |
926 | } | |
927 | else { | |
928 | UseMsg(); | |
929 | } | |
930 | } | |
931 | #ifdef PANORAMIX | |
932 | else if (strcmp(argv[i], "+xinerama") == 0) { | |
933 | noPanoramiXExtension = FALSE; | |
934 | } | |
935 | else if (strcmp(argv[i], "-xinerama") == 0) { | |
936 | noPanoramiXExtension = TRUE; | |
937 | } | |
938 | else if (strcmp(argv[i], "-disablexineramaextension") == 0) { | |
939 | PanoramiXExtensionDisabledHack = TRUE; | |
940 | } | |
941 | #endif | |
942 | else if (strcmp(argv[i], "-I") == 0) { | |
943 | /* ignore all remaining arguments */ | |
944 | break; | |
945 | } | |
946 | else if (strncmp(argv[i], "tty", 3) == 0) { | |
947 | /* init supplies us with this useless information */ | |
948 | } | |
949 | #ifdef XDMCP | |
950 | else if ((skip = XdmcpOptions(argc, argv, i)) != i) { | |
951 | i = skip - 1; | |
952 | } | |
953 | #endif | |
954 | #ifdef SMART_SCHEDULE_POSSIBLE | |
955 | else if (strcmp(argv[i], "-dumbSched") == 0) { | |
956 | SmartScheduleDisable = TRUE; | |
957 | } | |
958 | else if (strcmp(argv[i], "-schedInterval") == 0) { | |
959 | if (++i < argc) { | |
960 | SmartScheduleInterval = atoi(argv[i]); | |
961 | SmartScheduleSlice = SmartScheduleInterval; | |
962 | } | |
963 | else | |
964 | UseMsg(); | |
965 | } | |
966 | else if (strcmp(argv[i], "-schedMax") == 0) { | |
967 | if (++i < argc) { | |
968 | SmartScheduleMaxSlice = atoi(argv[i]); | |
969 | } | |
970 | else | |
971 | UseMsg(); | |
972 | } | |
973 | #endif | |
974 | else if (strcmp(argv[i], "-render") == 0) { | |
975 | if (++i < argc) { | |
976 | int policy = PictureParseCmapPolicy(argv[i]); | |
977 | ||
978 | if (policy != PictureCmapPolicyInvalid) | |
979 | PictureCmapPolicy = policy; | |
980 | else | |
981 | UseMsg(); | |
982 | } | |
983 | else | |
984 | UseMsg(); | |
985 | } | |
986 | else if (strcmp(argv[i], "-sigstop") == 0) { | |
987 | RunFromSigStopParent = TRUE; | |
988 | } | |
989 | else if (strcmp(argv[i], "+extension") == 0) { | |
990 | if (++i < argc) { | |
991 | if (!EnableDisableExtension(argv[i], TRUE)) | |
992 | EnableDisableExtensionError(argv[i], TRUE); | |
993 | } | |
994 | else | |
995 | UseMsg(); | |
996 | } | |
997 | else if (strcmp(argv[i], "-extension") == 0) { | |
998 | if (++i < argc) { | |
999 | if (!EnableDisableExtension(argv[i], FALSE)) | |
1000 | EnableDisableExtensionError(argv[i], FALSE); | |
1001 | } | |
1002 | else | |
1003 | UseMsg(); | |
1004 | } | |
1005 | else { | |
1006 | ErrorF("Unrecognized option: %s\n", argv[i]); | |
1007 | UseMsg(); | |
1008 | FatalError("Unrecognized option: %s\n", argv[i]); | |
1009 | } | |
1010 | } | |
1011 | } | |
1012 | ||
1013 | /* Implement a simple-minded font authorization scheme. The authorization | |
1014 | name is "hp-hostname-1", the contents are simply the host name. */ | |
1015 | int | |
1016 | set_font_authorizations(char **authorizations, int *authlen, pointer client) | |
1017 | { | |
1018 | #define AUTHORIZATION_NAME "hp-hostname-1" | |
1019 | #if defined(TCPCONN) || defined(STREAMSCONN) | |
1020 | static char *result = NULL; | |
1021 | static char *p = NULL; | |
1022 | ||
1023 | if (p == NULL) { | |
1024 | char hname[1024], *hnameptr; | |
1025 | unsigned int len; | |
1026 | ||
1027 | #if defined(IPv6) && defined(AF_INET6) | |
1028 | struct addrinfo hints, *ai = NULL; | |
1029 | #else | |
1030 | struct hostent *host; | |
1031 | ||
1032 | #ifdef XTHREADS_NEEDS_BYNAMEPARAMS | |
1033 | _Xgethostbynameparams hparams; | |
1034 | #endif | |
1035 | #endif | |
1036 | ||
1037 | gethostname(hname, 1024); | |
1038 | #if defined(IPv6) && defined(AF_INET6) | |
1039 | memset(&hints, 0, sizeof(hints)); | |
1040 | hints.ai_flags = AI_CANONNAME; | |
1041 | if (getaddrinfo(hname, NULL, &hints, &ai) == 0) { | |
1042 | hnameptr = ai->ai_canonname; | |
1043 | } | |
1044 | else { | |
1045 | hnameptr = hname; | |
1046 | } | |
1047 | #else | |
1048 | host = _XGethostbyname(hname, hparams); | |
1049 | if (host == NULL) | |
1050 | hnameptr = hname; | |
1051 | else | |
1052 | hnameptr = host->h_name; | |
1053 | #endif | |
1054 | ||
1055 | len = strlen(hnameptr) + 1; | |
1056 | result = malloc(len + sizeof(AUTHORIZATION_NAME) + 4); | |
1057 | ||
1058 | p = result; | |
1059 | *p++ = sizeof(AUTHORIZATION_NAME) >> 8; | |
1060 | *p++ = sizeof(AUTHORIZATION_NAME) & 0xff; | |
1061 | *p++ = (len) >> 8; | |
1062 | *p++ = (len & 0xff); | |
1063 | ||
1064 | memmove(p, AUTHORIZATION_NAME, sizeof(AUTHORIZATION_NAME)); | |
1065 | p += sizeof(AUTHORIZATION_NAME); | |
1066 | memmove(p, hnameptr, len); | |
1067 | p += len; | |
1068 | #if defined(IPv6) && defined(AF_INET6) | |
1069 | if (ai) { | |
1070 | freeaddrinfo(ai); | |
1071 | } | |
1072 | #endif | |
1073 | } | |
1074 | *authlen = p - result; | |
1075 | *authorizations = result; | |
1076 | return 1; | |
1077 | #else /* TCPCONN */ | |
1078 | return 0; | |
1079 | #endif /* TCPCONN */ | |
1080 | } | |
1081 | ||
1082 | void * | |
1083 | Xalloc(unsigned long amount) | |
1084 | { | |
1085 | /* | |
1086 | * Xalloc used to return NULL when large amount of memory is requested. In | |
1087 | * order to catch the buggy callers this warning has been added, slated to | |
1088 | * removal by anyone who touches this code (or just looks at it) in 2011. | |
1089 | * | |
1090 | * -- Mikhail Gusarov | |
1091 | */ | |
1092 | if ((long) amount <= 0) | |
1093 | ErrorF("Warning: Xalloc: " | |
1094 | "requesting unpleasantly large amount of memory: %lu bytes.\n", | |
1095 | amount); | |
1096 | ||
1097 | return malloc(amount); | |
1098 | } | |
1099 | ||
1100 | void * | |
1101 | XNFalloc(unsigned long amount) | |
1102 | { | |
1103 | void *ptr = malloc(amount); | |
1104 | ||
1105 | if (!ptr) | |
1106 | FatalError("Out of memory"); | |
1107 | return ptr; | |
1108 | } | |
1109 | ||
1110 | void * | |
1111 | Xcalloc(unsigned long amount) | |
1112 | { | |
1113 | return calloc(1, amount); | |
1114 | } | |
1115 | ||
1116 | void * | |
1117 | XNFcalloc(unsigned long amount) | |
1118 | { | |
1119 | void *ret = calloc(1, amount); | |
1120 | ||
1121 | if (!ret) | |
1122 | FatalError("XNFcalloc: Out of memory"); | |
1123 | return ret; | |
1124 | } | |
1125 | ||
1126 | void * | |
1127 | Xrealloc(void *ptr, unsigned long amount) | |
1128 | { | |
1129 | /* | |
1130 | * Xrealloc used to return NULL when large amount of memory is requested. In | |
1131 | * order to catch the buggy callers this warning has been added, slated to | |
1132 | * removal by anyone who touches this code (or just looks at it) in 2011. | |
1133 | * | |
1134 | * -- Mikhail Gusarov | |
1135 | */ | |
1136 | if ((long) amount <= 0) | |
1137 | ErrorF("Warning: Xrealloc: " | |
1138 | "requesting unpleasantly large amount of memory: %lu bytes.\n", | |
1139 | amount); | |
1140 | ||
1141 | return realloc(ptr, amount); | |
1142 | } | |
1143 | ||
1144 | void * | |
1145 | XNFrealloc(void *ptr, unsigned long amount) | |
1146 | { | |
1147 | void *ret = realloc(ptr, amount); | |
1148 | ||
1149 | if (!ret) | |
1150 | FatalError("XNFrealloc: Out of memory"); | |
1151 | return ret; | |
1152 | } | |
1153 | ||
1154 | void | |
1155 | Xfree(void *ptr) | |
1156 | { | |
1157 | free(ptr); | |
1158 | } | |
1159 | ||
1160 | char * | |
1161 | Xstrdup(const char *s) | |
1162 | { | |
1163 | if (s == NULL) | |
1164 | return NULL; | |
1165 | return strdup(s); | |
1166 | } | |
1167 | ||
1168 | char * | |
1169 | XNFstrdup(const char *s) | |
1170 | { | |
1171 | char *ret; | |
1172 | ||
1173 | if (s == NULL) | |
1174 | return NULL; | |
1175 | ||
1176 | ret = strdup(s); | |
1177 | if (!ret) | |
1178 | FatalError("XNFstrdup: Out of memory"); | |
1179 | return ret; | |
1180 | } | |
1181 | ||
1182 | void | |
1183 | SmartScheduleStopTimer(void) | |
1184 | { | |
1185 | #ifdef SMART_SCHEDULE_POSSIBLE | |
1186 | struct itimerval timer; | |
1187 | ||
1188 | if (SmartScheduleDisable) | |
1189 | return; | |
1190 | timer.it_interval.tv_sec = 0; | |
1191 | timer.it_interval.tv_usec = 0; | |
1192 | timer.it_value.tv_sec = 0; | |
1193 | timer.it_value.tv_usec = 0; | |
1194 | (void) setitimer(ITIMER_REAL, &timer, 0); | |
1195 | #endif | |
1196 | } | |
1197 | ||
1198 | void | |
1199 | SmartScheduleStartTimer(void) | |
1200 | { | |
1201 | #ifdef SMART_SCHEDULE_POSSIBLE | |
1202 | struct itimerval timer; | |
1203 | ||
1204 | if (SmartScheduleDisable) | |
1205 | return; | |
1206 | timer.it_interval.tv_sec = 0; | |
1207 | timer.it_interval.tv_usec = SmartScheduleInterval * 1000; | |
1208 | timer.it_value.tv_sec = 0; | |
1209 | timer.it_value.tv_usec = SmartScheduleInterval * 1000; | |
1210 | setitimer(ITIMER_REAL, &timer, 0); | |
1211 | #endif | |
1212 | } | |
1213 | ||
1214 | static void | |
1215 | SmartScheduleTimer(int sig) | |
1216 | { | |
1217 | SmartScheduleTime += SmartScheduleInterval; | |
1218 | } | |
1219 | ||
1220 | void | |
1221 | SmartScheduleInit(void) | |
1222 | { | |
1223 | #ifdef SMART_SCHEDULE_POSSIBLE | |
1224 | struct sigaction act; | |
1225 | ||
1226 | if (SmartScheduleDisable) | |
1227 | return; | |
1228 | ||
1229 | memset((char *) &act, 0, sizeof(struct sigaction)); | |
1230 | ||
1231 | /* Set up the timer signal function */ | |
1232 | act.sa_handler = SmartScheduleTimer; | |
1233 | sigemptyset(&act.sa_mask); | |
1234 | sigaddset(&act.sa_mask, SIGALRM); | |
1235 | if (sigaction(SIGALRM, &act, 0) < 0) { | |
1236 | perror("sigaction for smart scheduler"); | |
1237 | SmartScheduleDisable = TRUE; | |
1238 | } | |
1239 | #endif | |
1240 | } | |
1241 | ||
1242 | #ifdef SIG_BLOCK | |
1243 | static sigset_t PreviousSignalMask; | |
1244 | static int BlockedSignalCount; | |
1245 | #endif | |
1246 | ||
1247 | void | |
1248 | OsBlockSignals(void) | |
1249 | { | |
1250 | #ifdef SIG_BLOCK | |
1251 | if (BlockedSignalCount++ == 0) { | |
1252 | sigset_t set; | |
1253 | ||
1254 | #ifdef SIGIO | |
1255 | OsBlockSIGIO(); | |
1256 | #endif | |
1257 | sigemptyset(&set); | |
1258 | sigaddset(&set, SIGALRM); | |
1259 | sigaddset(&set, SIGVTALRM); | |
1260 | #ifdef SIGWINCH | |
1261 | sigaddset(&set, SIGWINCH); | |
1262 | #endif | |
1263 | sigaddset(&set, SIGTSTP); | |
1264 | sigaddset(&set, SIGTTIN); | |
1265 | sigaddset(&set, SIGTTOU); | |
1266 | sigaddset(&set, SIGCHLD); | |
1267 | sigprocmask(SIG_BLOCK, &set, &PreviousSignalMask); | |
1268 | } | |
1269 | #endif | |
1270 | } | |
1271 | ||
1272 | #ifdef SIG_BLOCK | |
1273 | static sig_atomic_t sigio_blocked; | |
1274 | static sigset_t PreviousSigIOMask; | |
1275 | #endif | |
1276 | ||
1277 | /** | |
1278 | * returns zero if this call caused SIGIO to be blocked now, non-zero if it | |
1279 | * was already blocked by a previous call to this function. | |
1280 | */ | |
1281 | int | |
1282 | OsBlockSIGIO(void) | |
1283 | { | |
1284 | #ifdef SIGIO | |
1285 | #ifdef SIG_BLOCK | |
1286 | if (sigio_blocked++ == 0) { | |
1287 | sigset_t set; | |
1288 | int ret; | |
1289 | ||
1290 | sigemptyset(&set); | |
1291 | sigaddset(&set, SIGIO); | |
1292 | sigprocmask(SIG_BLOCK, &set, &PreviousSigIOMask); | |
1293 | ret = sigismember(&PreviousSigIOMask, SIGIO); | |
1294 | return ret; | |
1295 | } | |
1296 | #endif | |
1297 | #endif | |
1298 | return 1; | |
1299 | } | |
1300 | ||
1301 | void | |
1302 | OsReleaseSIGIO(void) | |
1303 | { | |
1304 | #ifdef SIGIO | |
1305 | #ifdef SIG_BLOCK | |
1306 | if (--sigio_blocked == 0) { | |
1307 | sigprocmask(SIG_SETMASK, &PreviousSigIOMask, 0); | |
1308 | } else if (sigio_blocked < 0) { | |
1309 | BUG_WARN(sigio_blocked < 0); | |
1310 | sigio_blocked = 0; | |
1311 | } | |
1312 | #endif | |
1313 | #endif | |
1314 | } | |
1315 | ||
1316 | void | |
1317 | OsReleaseSignals(void) | |
1318 | { | |
1319 | #ifdef SIG_BLOCK | |
1320 | if (--BlockedSignalCount == 0) { | |
1321 | sigprocmask(SIG_SETMASK, &PreviousSignalMask, 0); | |
1322 | OsReleaseSIGIO(); | |
1323 | } | |
1324 | #endif | |
1325 | } | |
1326 | ||
1327 | void | |
1328 | OsResetSignals(void) | |
1329 | { | |
1330 | #ifdef SIG_BLOCK | |
1331 | while (BlockedSignalCount > 0) | |
1332 | OsReleaseSignals(); | |
1333 | #ifdef SIGIO | |
1334 | while (sigio_blocked > 0) | |
1335 | OsReleaseSIGIO(); | |
1336 | #endif | |
1337 | #endif | |
1338 | } | |
1339 | ||
1340 | /* | |
1341 | * Pending signals may interfere with core dumping. Provide a | |
1342 | * mechanism to block signals when aborting. | |
1343 | */ | |
1344 | ||
1345 | void | |
1346 | OsAbort(void) | |
1347 | { | |
1348 | #ifndef __APPLE__ | |
1349 | OsBlockSignals(); | |
1350 | #endif | |
1351 | abort(); | |
1352 | } | |
1353 | ||
1354 | #if !defined(WIN32) | |
1355 | /* | |
1356 | * "safer" versions of system(3), popen(3) and pclose(3) which give up | |
1357 | * all privs before running a command. | |
1358 | * | |
1359 | * This is based on the code in FreeBSD 2.2 libc. | |
1360 | * | |
1361 | * XXX It'd be good to redirect stderr so that it ends up in the log file | |
1362 | * as well. As it is now, xkbcomp messages don't end up in the log file. | |
1363 | */ | |
1364 | ||
1365 | int | |
1366 | System(const char *command) | |
1367 | { | |
1368 | int pid, p; | |
1369 | void (*csig) (int); | |
1370 | int status; | |
1371 | ||
1372 | if (!command) | |
1373 | return 1; | |
1374 | ||
1375 | csig = signal(SIGCHLD, SIG_DFL); | |
1376 | if (csig == SIG_ERR) { | |
1377 | perror("signal"); | |
1378 | return -1; | |
1379 | } | |
1380 | DebugF("System: `%s'\n", command); | |
1381 | ||
1382 | switch (pid = fork()) { | |
1383 | case -1: /* error */ | |
1384 | p = -1; | |
1385 | case 0: /* child */ | |
1386 | if (setgid(getgid()) == -1) | |
1387 | _exit(127); | |
1388 | if (setuid(getuid()) == -1) | |
1389 | _exit(127); | |
1390 | execl("/bin/sh", "sh", "-c", command, (char *) NULL); | |
1391 | _exit(127); | |
1392 | default: /* parent */ | |
1393 | do { | |
1394 | p = waitpid(pid, &status, 0); | |
1395 | } while (p == -1 && errno == EINTR); | |
1396 | ||
1397 | } | |
1398 | ||
1399 | if (signal(SIGCHLD, csig) == SIG_ERR) { | |
1400 | perror("signal"); | |
1401 | return -1; | |
1402 | } | |
1403 | ||
1404 | return p == -1 ? -1 : status; | |
1405 | } | |
1406 | ||
1407 | static struct pid { | |
1408 | struct pid *next; | |
1409 | FILE *fp; | |
1410 | int pid; | |
1411 | } *pidlist; | |
1412 | ||
1413 | OsSigHandlerPtr old_alarm = NULL; /* XXX horrible awful hack */ | |
1414 | ||
1415 | pointer | |
1416 | Popen(const char *command, const char *type) | |
1417 | { | |
1418 | struct pid *cur; | |
1419 | FILE *iop; | |
1420 | int pdes[2], pid; | |
1421 | ||
1422 | if (command == NULL || type == NULL) | |
1423 | return NULL; | |
1424 | ||
1425 | if ((*type != 'r' && *type != 'w') || type[1]) | |
1426 | return NULL; | |
1427 | ||
1428 | if ((cur = malloc(sizeof(struct pid))) == NULL) | |
1429 | return NULL; | |
1430 | ||
1431 | if (pipe(pdes) < 0) { | |
1432 | free(cur); | |
1433 | return NULL; | |
1434 | } | |
1435 | ||
1436 | /* Ignore the smart scheduler while this is going on */ | |
1437 | old_alarm = OsSignal(SIGALRM, SIG_IGN); | |
1438 | if (old_alarm == SIG_ERR) { | |
1439 | close(pdes[0]); | |
1440 | close(pdes[1]); | |
1441 | free(cur); | |
1442 | perror("signal"); | |
1443 | return NULL; | |
1444 | } | |
1445 | ||
1446 | switch (pid = fork()) { | |
1447 | case -1: /* error */ | |
1448 | close(pdes[0]); | |
1449 | close(pdes[1]); | |
1450 | free(cur); | |
1451 | if (OsSignal(SIGALRM, old_alarm) == SIG_ERR) | |
1452 | perror("signal"); | |
1453 | return NULL; | |
1454 | case 0: /* child */ | |
1455 | if (setgid(getgid()) == -1) | |
1456 | _exit(127); | |
1457 | if (setuid(getuid()) == -1) | |
1458 | _exit(127); | |
1459 | if (*type == 'r') { | |
1460 | if (pdes[1] != 1) { | |
1461 | /* stdout */ | |
1462 | dup2(pdes[1], 1); | |
1463 | close(pdes[1]); | |
1464 | } | |
1465 | close(pdes[0]); | |
1466 | } | |
1467 | else { | |
1468 | if (pdes[0] != 0) { | |
1469 | /* stdin */ | |
1470 | dup2(pdes[0], 0); | |
1471 | close(pdes[0]); | |
1472 | } | |
1473 | close(pdes[1]); | |
1474 | } | |
1475 | execl("/bin/sh", "sh", "-c", command, (char *) NULL); | |
1476 | _exit(127); | |
1477 | } | |
1478 | ||
1479 | /* Avoid EINTR during stdio calls */ | |
1480 | OsBlockSignals(); | |
1481 | ||
1482 | /* parent */ | |
1483 | if (*type == 'r') { | |
1484 | iop = fdopen(pdes[0], type); | |
1485 | close(pdes[1]); | |
1486 | } | |
1487 | else { | |
1488 | iop = fdopen(pdes[1], type); | |
1489 | close(pdes[0]); | |
1490 | } | |
1491 | ||
1492 | cur->fp = iop; | |
1493 | cur->pid = pid; | |
1494 | cur->next = pidlist; | |
1495 | pidlist = cur; | |
1496 | ||
1497 | DebugF("Popen: `%s', fp = %p\n", command, iop); | |
1498 | ||
1499 | return iop; | |
1500 | } | |
1501 | ||
1502 | /* fopen that drops privileges */ | |
1503 | pointer | |
1504 | Fopen(const char *file, const char *type) | |
1505 | { | |
1506 | FILE *iop; | |
1507 | ||
1508 | #ifndef HAS_SAVED_IDS_AND_SETEUID | |
1509 | struct pid *cur; | |
1510 | int pdes[2], pid; | |
1511 | ||
1512 | if (file == NULL || type == NULL) | |
1513 | return NULL; | |
1514 | ||
1515 | if ((*type != 'r' && *type != 'w') || type[1]) | |
1516 | return NULL; | |
1517 | ||
1518 | if ((cur = malloc(sizeof(struct pid))) == NULL) | |
1519 | return NULL; | |
1520 | ||
1521 | if (pipe(pdes) < 0) { | |
1522 | free(cur); | |
1523 | return NULL; | |
1524 | } | |
1525 | ||
1526 | switch (pid = fork()) { | |
1527 | case -1: /* error */ | |
1528 | close(pdes[0]); | |
1529 | close(pdes[1]); | |
1530 | free(cur); | |
1531 | return NULL; | |
1532 | case 0: /* child */ | |
1533 | if (setgid(getgid()) == -1) | |
1534 | _exit(127); | |
1535 | if (setuid(getuid()) == -1) | |
1536 | _exit(127); | |
1537 | if (*type == 'r') { | |
1538 | if (pdes[1] != 1) { | |
1539 | /* stdout */ | |
1540 | dup2(pdes[1], 1); | |
1541 | close(pdes[1]); | |
1542 | } | |
1543 | close(pdes[0]); | |
1544 | } | |
1545 | else { | |
1546 | if (pdes[0] != 0) { | |
1547 | /* stdin */ | |
1548 | dup2(pdes[0], 0); | |
1549 | close(pdes[0]); | |
1550 | } | |
1551 | close(pdes[1]); | |
1552 | } | |
1553 | execl("/bin/cat", "cat", file, (char *) NULL); | |
1554 | _exit(127); | |
1555 | } | |
1556 | ||
1557 | /* Avoid EINTR during stdio calls */ | |
1558 | OsBlockSignals(); | |
1559 | ||
1560 | /* parent */ | |
1561 | if (*type == 'r') { | |
1562 | iop = fdopen(pdes[0], type); | |
1563 | close(pdes[1]); | |
1564 | } | |
1565 | else { | |
1566 | iop = fdopen(pdes[1], type); | |
1567 | close(pdes[0]); | |
1568 | } | |
1569 | ||
1570 | cur->fp = iop; | |
1571 | cur->pid = pid; | |
1572 | cur->next = pidlist; | |
1573 | pidlist = cur; | |
1574 | ||
1575 | DebugF("Fopen(%s), fp = %p\n", file, iop); | |
1576 | ||
1577 | return iop; | |
1578 | #else | |
1579 | int ruid, euid; | |
1580 | ||
1581 | ruid = getuid(); | |
1582 | euid = geteuid(); | |
1583 | ||
1584 | if (seteuid(ruid) == -1) { | |
1585 | return NULL; | |
1586 | } | |
1587 | iop = fopen(file, type); | |
1588 | ||
1589 | if (seteuid(euid) == -1) { | |
1590 | fclose(iop); | |
1591 | return NULL; | |
1592 | } | |
1593 | return iop; | |
1594 | #endif /* HAS_SAVED_IDS_AND_SETEUID */ | |
1595 | } | |
1596 | ||
1597 | int | |
1598 | Pclose(pointer iop) | |
1599 | { | |
1600 | struct pid *cur, *last; | |
1601 | int pstat; | |
1602 | int pid; | |
1603 | ||
1604 | DebugF("Pclose: fp = %p\n", iop); | |
1605 | fclose(iop); | |
1606 | ||
1607 | for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next) | |
1608 | if (cur->fp == iop) | |
1609 | break; | |
1610 | if (cur == NULL) | |
1611 | return -1; | |
1612 | ||
1613 | do { | |
1614 | pid = waitpid(cur->pid, &pstat, 0); | |
1615 | } while (pid == -1 && errno == EINTR); | |
1616 | ||
1617 | if (last == NULL) | |
1618 | pidlist = cur->next; | |
1619 | else | |
1620 | last->next = cur->next; | |
1621 | free(cur); | |
1622 | ||
1623 | /* allow EINTR again */ | |
1624 | OsReleaseSignals(); | |
1625 | ||
1626 | if (old_alarm && OsSignal(SIGALRM, old_alarm) == SIG_ERR) { | |
1627 | perror("signal"); | |
1628 | return -1; | |
1629 | } | |
1630 | ||
1631 | return pid == -1 ? -1 : pstat; | |
1632 | } | |
1633 | ||
1634 | int | |
1635 | Fclose(pointer iop) | |
1636 | { | |
1637 | #ifdef HAS_SAVED_IDS_AND_SETEUID | |
1638 | return fclose(iop); | |
1639 | #else | |
1640 | return Pclose(iop); | |
1641 | #endif | |
1642 | } | |
1643 | ||
1644 | #endif /* !WIN32 */ | |
1645 | ||
1646 | #ifdef WIN32 | |
1647 | ||
1648 | #include <X11/Xwindows.h> | |
1649 | ||
1650 | const char * | |
1651 | Win32TempDir() | |
1652 | { | |
1653 | static char buffer[PATH_MAX]; | |
1654 | ||
1655 | if (GetTempPath(sizeof(buffer), buffer)) { | |
1656 | int len; | |
1657 | ||
1658 | buffer[sizeof(buffer) - 1] = 0; | |
1659 | len = strlen(buffer); | |
1660 | if (len > 0) | |
1661 | if (buffer[len - 1] == '\\') | |
1662 | buffer[len - 1] = 0; | |
1663 | return buffer; | |
1664 | } | |
1665 | if (getenv("TEMP") != NULL) | |
1666 | return getenv("TEMP"); | |
1667 | else if (getenv("TMP") != NULL) | |
1668 | return getenv("TMP"); | |
1669 | else | |
1670 | return "/tmp"; | |
1671 | } | |
1672 | ||
1673 | int | |
1674 | System(const char *cmdline) | |
1675 | { | |
1676 | STARTUPINFO si; | |
1677 | PROCESS_INFORMATION pi; | |
1678 | DWORD dwExitCode; | |
1679 | char *cmd = strdup(cmdline); | |
1680 | ||
1681 | ZeroMemory(&si, sizeof(si)); | |
1682 | si.cb = sizeof(si); | |
1683 | ZeroMemory(&pi, sizeof(pi)); | |
1684 | ||
1685 | if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { | |
1686 | LPVOID buffer; | |
1687 | ||
1688 | if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | | |
1689 | FORMAT_MESSAGE_FROM_SYSTEM | | |
1690 | FORMAT_MESSAGE_IGNORE_INSERTS, | |
1691 | NULL, | |
1692 | GetLastError(), | |
1693 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | |
1694 | (LPTSTR) &buffer, 0, NULL)) { | |
1695 | ErrorF("[xkb] Starting '%s' failed!\n", cmdline); | |
1696 | } | |
1697 | else { | |
1698 | ErrorF("[xkb] Starting '%s' failed: %s", cmdline, (char *) buffer); | |
1699 | LocalFree(buffer); | |
1700 | } | |
1701 | ||
1702 | free(cmd); | |
1703 | return -1; | |
1704 | } | |
1705 | /* Wait until child process exits. */ | |
1706 | WaitForSingleObject(pi.hProcess, INFINITE); | |
1707 | ||
1708 | GetExitCodeProcess(pi.hProcess, &dwExitCode); | |
1709 | ||
1710 | /* Close process and thread handles. */ | |
1711 | CloseHandle(pi.hProcess); | |
1712 | CloseHandle(pi.hThread); | |
1713 | free(cmd); | |
1714 | ||
1715 | return dwExitCode; | |
1716 | } | |
1717 | #endif | |
1718 | ||
1719 | /* | |
1720 | * CheckUserParameters: check for long command line arguments and long | |
1721 | * environment variables. By default, these checks are only done when | |
1722 | * the server's euid != ruid. In 3.3.x, these checks were done in an | |
1723 | * external wrapper utility. | |
1724 | */ | |
1725 | ||
1726 | /* Consider LD* variables insecure? */ | |
1727 | #ifndef REMOVE_ENV_LD | |
1728 | #define REMOVE_ENV_LD 1 | |
1729 | #endif | |
1730 | ||
1731 | /* Remove long environment variables? */ | |
1732 | #ifndef REMOVE_LONG_ENV | |
1733 | #define REMOVE_LONG_ENV 1 | |
1734 | #endif | |
1735 | ||
1736 | /* | |
1737 | * Disallow stdout or stderr as pipes? It's possible to block the X server | |
1738 | * when piping stdout+stderr to a pipe. | |
1739 | * | |
1740 | * Don't enable this because it looks like it's going to cause problems. | |
1741 | */ | |
1742 | #ifndef NO_OUTPUT_PIPES | |
1743 | #define NO_OUTPUT_PIPES 0 | |
1744 | #endif | |
1745 | ||
1746 | /* Check args and env only if running setuid (euid == 0 && euid != uid) ? */ | |
1747 | #ifndef CHECK_EUID | |
1748 | #ifndef WIN32 | |
1749 | #define CHECK_EUID 1 | |
1750 | #else | |
1751 | #define CHECK_EUID 0 | |
1752 | #endif | |
1753 | #endif | |
1754 | ||
1755 | /* | |
1756 | * Maybe the locale can be faked to make isprint(3) report that everything | |
1757 | * is printable? Avoid it by default. | |
1758 | */ | |
1759 | #ifndef USE_ISPRINT | |
1760 | #define USE_ISPRINT 0 | |
1761 | #endif | |
1762 | ||
1763 | #define MAX_ARG_LENGTH 128 | |
1764 | #define MAX_ENV_LENGTH 256 | |
1765 | #define MAX_ENV_PATH_LENGTH 2048 /* Limit for *PATH and TERMCAP */ | |
1766 | ||
1767 | #if USE_ISPRINT | |
1768 | #include <ctype.h> | |
1769 | #define checkPrintable(c) isprint(c) | |
1770 | #else | |
1771 | #define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f) | |
1772 | #endif | |
1773 | ||
1774 | enum BadCode { | |
1775 | NotBad = 0, | |
1776 | UnsafeArg, | |
1777 | ArgTooLong, | |
1778 | UnprintableArg, | |
1779 | EnvTooLong, | |
1780 | OutputIsPipe, | |
1781 | InternalError | |
1782 | }; | |
1783 | ||
1784 | #if defined(VENDORSUPPORT) | |
1785 | #define BUGADDRESS VENDORSUPPORT | |
1786 | #elif defined(BUILDERADDR) | |
1787 | #define BUGADDRESS BUILDERADDR | |
1788 | #else | |
1789 | #define BUGADDRESS "xorg@freedesktop.org" | |
1790 | #endif | |
1791 | ||
1792 | void | |
1793 | CheckUserParameters(int argc, char **argv, char **envp) | |
1794 | { | |
1795 | enum BadCode bad = NotBad; | |
1796 | int i = 0, j; | |
1797 | char *a, *e = NULL; | |
1798 | ||
1799 | #if CHECK_EUID | |
1800 | if (geteuid() == 0 && getuid() != geteuid()) | |
1801 | #endif | |
1802 | { | |
1803 | /* Check each argv[] */ | |
1804 | for (i = 1; i < argc; i++) { | |
1805 | if (strcmp(argv[i], "-fp") == 0) { | |
1806 | i++; /* continue with next argument. skip the length check */ | |
1807 | if (i >= argc) | |
1808 | break; | |
1809 | } | |
1810 | else { | |
1811 | if (strlen(argv[i]) > MAX_ARG_LENGTH) { | |
1812 | bad = ArgTooLong; | |
1813 | break; | |
1814 | } | |
1815 | } | |
1816 | a = argv[i]; | |
1817 | while (*a) { | |
1818 | if (checkPrintable(*a) == 0) { | |
1819 | bad = UnprintableArg; | |
1820 | break; | |
1821 | } | |
1822 | a++; | |
1823 | } | |
1824 | if (bad) | |
1825 | break; | |
1826 | } | |
1827 | if (!bad) { | |
1828 | /* Check each envp[] */ | |
1829 | for (i = 0; envp[i]; i++) { | |
1830 | ||
1831 | /* Check for bad environment variables and values */ | |
1832 | #if REMOVE_ENV_LD | |
1833 | while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) { | |
1834 | for (j = i; envp[j]; j++) { | |
1835 | envp[j] = envp[j + 1]; | |
1836 | } | |
1837 | } | |
1838 | #endif | |
1839 | if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) { | |
1840 | #if REMOVE_LONG_ENV | |
1841 | for (j = i; envp[j]; j++) { | |
1842 | envp[j] = envp[j + 1]; | |
1843 | } | |
1844 | i--; | |
1845 | #else | |
1846 | char *eq; | |
1847 | int len; | |
1848 | ||
1849 | eq = strchr(envp[i], '='); | |
1850 | if (!eq) | |
1851 | continue; | |
1852 | len = eq - envp[i]; | |
1853 | e = strndup(envp[i], len); | |
1854 | if (!e) { | |
1855 | bad = InternalError; | |
1856 | break; | |
1857 | } | |
1858 | if (len >= 4 && | |
1859 | (strcmp(e + len - 4, "PATH") == 0 || | |
1860 | strcmp(e, "TERMCAP") == 0)) { | |
1861 | if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) { | |
1862 | bad = EnvTooLong; | |
1863 | break; | |
1864 | } | |
1865 | else { | |
1866 | free(e); | |
1867 | } | |
1868 | } | |
1869 | else { | |
1870 | bad = EnvTooLong; | |
1871 | break; | |
1872 | } | |
1873 | #endif | |
1874 | } | |
1875 | } | |
1876 | } | |
1877 | #if NO_OUTPUT_PIPES | |
1878 | if (!bad) { | |
1879 | struct stat buf; | |
1880 | ||
1881 | if (fstat(fileno(stdout), &buf) == 0 && S_ISFIFO(buf.st_mode)) | |
1882 | bad = OutputIsPipe; | |
1883 | if (fstat(fileno(stderr), &buf) == 0 && S_ISFIFO(buf.st_mode)) | |
1884 | bad = OutputIsPipe; | |
1885 | } | |
1886 | #endif | |
1887 | } | |
1888 | switch (bad) { | |
1889 | case NotBad: | |
1890 | return; | |
1891 | case UnsafeArg: | |
1892 | ErrorF("Command line argument number %d is unsafe\n", i); | |
1893 | break; | |
1894 | case ArgTooLong: | |
1895 | ErrorF("Command line argument number %d is too long\n", i); | |
1896 | break; | |
1897 | case UnprintableArg: | |
1898 | ErrorF("Command line argument number %d contains unprintable" | |
1899 | " characters\n", i); | |
1900 | break; | |
1901 | case EnvTooLong: | |
1902 | ErrorF("Environment variable `%s' is too long\n", e); | |
1903 | break; | |
1904 | case OutputIsPipe: | |
1905 | ErrorF("Stdout and/or stderr is a pipe\n"); | |
1906 | break; | |
1907 | case InternalError: | |
1908 | ErrorF("Internal Error\n"); | |
1909 | break; | |
1910 | default: | |
1911 | ErrorF("Unknown error\n"); | |
1912 | break; | |
1913 | } | |
1914 | FatalError("X server aborted because of unsafe environment\n"); | |
1915 | } | |
1916 | ||
1917 | /* | |
1918 | * CheckUserAuthorization: check if the user is allowed to start the | |
1919 | * X server. This usually means some sort of PAM checking, and it is | |
1920 | * usually only done for setuid servers (uid != euid). | |
1921 | */ | |
1922 | ||
1923 | #ifdef USE_PAM | |
1924 | #include <security/pam_appl.h> | |
1925 | #include <security/pam_misc.h> | |
1926 | #include <pwd.h> | |
1927 | #endif /* USE_PAM */ | |
1928 | ||
1929 | void | |
1930 | CheckUserAuthorization(void) | |
1931 | { | |
1932 | #ifdef USE_PAM | |
1933 | static struct pam_conv conv = { | |
1934 | misc_conv, | |
1935 | NULL | |
1936 | }; | |
1937 | ||
1938 | pam_handle_t *pamh = NULL; | |
1939 | struct passwd *pw; | |
1940 | int retval; | |
1941 | ||
1942 | if (getuid() != geteuid()) { | |
1943 | pw = getpwuid(getuid()); | |
1944 | if (pw == NULL) | |
1945 | FatalError("getpwuid() failed for uid %d\n", getuid()); | |
1946 | ||
1947 | retval = pam_start("xserver", pw->pw_name, &conv, &pamh); | |
1948 | if (retval != PAM_SUCCESS) | |
1949 | FatalError("pam_start() failed.\n" | |
1950 | "\tMissing or mangled PAM config file or module?\n"); | |
1951 | ||
1952 | retval = pam_authenticate(pamh, 0); | |
1953 | if (retval != PAM_SUCCESS) { | |
1954 | pam_end(pamh, retval); | |
1955 | FatalError("PAM authentication failed, cannot start X server.\n" | |
1956 | "\tPerhaps you do not have console ownership?\n"); | |
1957 | } | |
1958 | ||
1959 | retval = pam_acct_mgmt(pamh, 0); | |
1960 | if (retval != PAM_SUCCESS) { | |
1961 | pam_end(pamh, retval); | |
1962 | FatalError("PAM authentication failed, cannot start X server.\n" | |
1963 | "\tPerhaps you do not have console ownership?\n"); | |
1964 | } | |
1965 | ||
1966 | /* this is not a session, so do not do session management */ | |
1967 | pam_end(pamh, PAM_SUCCESS); | |
1968 | } | |
1969 | #endif | |
1970 | } | |
1971 | ||
1972 | /* | |
1973 | * Tokenize a string into a NULL terminated array of strings. Always returns | |
1974 | * an allocated array unless an error occurs. | |
1975 | */ | |
1976 | char ** | |
1977 | xstrtokenize(const char *str, const char *separators) | |
1978 | { | |
1979 | char **list, **nlist; | |
1980 | char *tok, *tmp; | |
1981 | unsigned num = 0, n; | |
1982 | ||
1983 | if (!str) | |
1984 | return NULL; | |
1985 | list = calloc(1, sizeof(*list)); | |
1986 | if (!list) | |
1987 | return NULL; | |
1988 | tmp = strdup(str); | |
1989 | if (!tmp) | |
1990 | goto error; | |
1991 | for (tok = strtok(tmp, separators); tok; tok = strtok(NULL, separators)) { | |
1992 | nlist = realloc(list, (num + 2) * sizeof(*list)); | |
1993 | if (!nlist) | |
1994 | goto error; | |
1995 | list = nlist; | |
1996 | list[num] = strdup(tok); | |
1997 | if (!list[num]) | |
1998 | goto error; | |
1999 | list[++num] = NULL; | |
2000 | } | |
2001 | free(tmp); | |
2002 | return list; | |
2003 | ||
2004 | error: | |
2005 | free(tmp); | |
2006 | for (n = 0; n < num; n++) | |
2007 | free(list[n]); | |
2008 | free(list); | |
2009 | return NULL; | |
2010 | } | |
2011 | ||
2012 | /* Format a signed number into a string in a signal safe manner. The string | |
2013 | * should be at least 21 characters in order to handle all int64_t values. | |
2014 | */ | |
2015 | void | |
2016 | FormatInt64(int64_t num, char *string) | |
2017 | { | |
2018 | if (num < 0) { | |
2019 | string[0] = '-'; | |
2020 | num *= -1; | |
2021 | string++; | |
2022 | } | |
2023 | FormatUInt64(num, string); | |
2024 | } | |
2025 | ||
2026 | /* Format a number into a string in a signal safe manner. The string should be | |
2027 | * at least 21 characters in order to handle all uint64_t values. */ | |
2028 | void | |
2029 | FormatUInt64(uint64_t num, char *string) | |
2030 | { | |
2031 | uint64_t divisor; | |
2032 | int len; | |
2033 | int i; | |
2034 | ||
2035 | for (len = 1, divisor = 10; | |
2036 | len < 20 && num / divisor; | |
2037 | len++, divisor *= 10); | |
2038 | ||
2039 | for (i = len, divisor = 1; i > 0; i--, divisor *= 10) | |
2040 | string[i - 1] = '0' + ((num / divisor) % 10); | |
2041 | ||
2042 | string[len] = '\0'; | |
2043 | } | |
2044 | ||
2045 | /** | |
2046 | * Format a double number as %.2f. | |
2047 | */ | |
2048 | void | |
2049 | FormatDouble(double dbl, char *string) | |
2050 | { | |
2051 | int slen = 0; | |
2052 | uint64_t frac; | |
2053 | ||
2054 | frac = (dbl > 0 ? dbl : -dbl) * 100.0 + 0.5; | |
2055 | frac %= 100; | |
2056 | ||
2057 | /* write decimal part to string */ | |
2058 | if (dbl < 0 && dbl > -1) | |
2059 | string[slen++] = '-'; | |
2060 | FormatInt64((int64_t)dbl, &string[slen]); | |
2061 | ||
2062 | while(string[slen] != '\0') | |
2063 | slen++; | |
2064 | ||
2065 | /* append fractional part, but only if we have enough characters. We | |
2066 | * expect string to be 21 chars (incl trailing \0) */ | |
2067 | if (slen <= 17) { | |
2068 | string[slen++] = '.'; | |
2069 | if (frac < 10) | |
2070 | string[slen++] = '0'; | |
2071 | ||
2072 | FormatUInt64(frac, &string[slen]); | |
2073 | } | |
2074 | } | |
2075 | ||
2076 | ||
2077 | /* Format a number into a hexadecimal string in a signal safe manner. The string | |
2078 | * should be at least 17 characters in order to handle all uint64_t values. */ | |
2079 | void | |
2080 | FormatUInt64Hex(uint64_t num, char *string) | |
2081 | { | |
2082 | uint64_t divisor; | |
2083 | int len; | |
2084 | int i; | |
2085 | ||
2086 | for (len = 1, divisor = 0x10; | |
2087 | len < 16 && num / divisor; | |
2088 | len++, divisor *= 0x10); | |
2089 | ||
2090 | for (i = len, divisor = 1; i > 0; i--, divisor *= 0x10) { | |
2091 | int val = (num / divisor) % 0x10; | |
2092 | ||
2093 | if (val < 10) | |
2094 | string[i - 1] = '0' + val; | |
2095 | else | |
2096 | string[i - 1] = 'a' + val - 10; | |
2097 | } | |
2098 | ||
2099 | string[len] = '\0'; | |
2100 | } | |
2101 | ||
2102 | /* Move a file descriptor out of the way of our select mask; this | |
2103 | * is useful for file descriptors which will never appear in the | |
2104 | * select mask to avoid reducing the number of clients that can | |
2105 | * connect to the server | |
2106 | */ | |
2107 | int | |
2108 | os_move_fd(int fd) | |
2109 | { | |
2110 | int newfd; | |
2111 | ||
2112 | #ifdef F_DUPFD_CLOEXEC | |
2113 | newfd = fcntl(fd, F_DUPFD_CLOEXEC, MAXCLIENTS); | |
2114 | #else | |
2115 | newfd = fcntl(fd, F_DUPFD, MAXCLIENTS); | |
2116 | #endif | |
2117 | if (newfd < 0) | |
2118 | return fd; | |
2119 | #ifndef F_DUPFD_CLOEXEC | |
2120 | fcntl(newfd, F_SETFD, FD_CLOEXEC); | |
2121 | #endif | |
2122 | close(fd); | |
2123 | return newfd; | |
2124 | } |