1 /*
3 Copyright 1987, 1998 The Open Group
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.
11 The above copyright notice and this permission notice shall be included
12 in all copies or substantial portions of the Software.
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.
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.
28 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
29 Copyright 1994 Quarterdeck Office Systems.
31 All Rights Reserved
33 Permission to use, copy, modify, and distribute this software and its
34 documentation for any purpose and without fee is hereby granted,
35 provided that the above copyright notice appear in all copies and that
36 both that copyright notice and this permission notice appear in
37 supporting documentation, and that the names of Digital and
38 Quarterdeck not be used in advertising or publicity pertaining to
39 distribution of the software without specific, written prior
40 permission.
42 DIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
43 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
44 FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT
45 OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
46 OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
47 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
48 OR PERFORMANCE OF THIS SOFTWARE.
50 */
52 #ifdef HAVE_DIX_CONFIG_H
53 #include <dix-config.h>
54 #endif
56 #ifdef __CYGWIN__
57 #include <stdlib.h>
58 #include <signal.h>
59 /*
60 Sigh... We really need a prototype for this to know it is stdcall,
61 but #include-ing <windows.h> here is not a good idea...
62 */
63 __stdcall unsigned long GetTickCount(void);
64 #endif
66 #if defined(WIN32) && !defined(__CYGWIN__)
67 #include <X11/Xwinsock.h>
68 #endif
69 #include <X11/Xos.h>
70 #include <stdio.h>
71 #include <time.h>
72 #if !defined(WIN32) || !defined(__MINGW32__)
73 #include <sys/time.h>
74 #include <sys/resource.h>
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>
109 #include <stdlib.h> /* for malloc() */
111 #if defined(TCPCONN) || defined(STREAMSCONN)
112 # ifndef WIN32
113 # include <netdb.h>
114 # endif
115 #endif
117 #include "opaque.h"
119 #include "dixstruct.h"
121 #include "xkbsrv.h"
123 #include "picture.h"
125 Bool noTestExtensions;
126 #ifdef COMPOSITE
127 Bool noCompositeExtension = FALSE;
128 #endif
130 #ifdef DAMAGE
131 Bool noDamageExtension = FALSE;
132 #endif
133 #ifdef DBE
134 Bool noDbeExtension = FALSE;
135 #endif
136 #ifdef DPMSExtension
137 Bool noDPMSExtension = FALSE;
138 #endif
139 #ifdef GLXEXT
140 Bool noGlxExtension = FALSE;
141 Bool noGlxVisualInit = 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 #ifdef XCSECURITY
154 Bool noSecurityExtension = FALSE;
155 #endif
156 #ifdef RES
157 Bool noResExtension = FALSE;
158 #endif
159 #ifdef XF86BIGFONT
160 Bool noXFree86BigfontExtension = FALSE;
161 #endif
162 #ifdef XFreeXDGA
163 Bool noXFree86DGAExtension = FALSE;
164 #endif
165 #ifdef XF86DRI
166 Bool noXFree86DRIExtension = FALSE;
167 #endif
168 #ifdef XF86VIDMODE
169 Bool noXFree86VidModeExtension = FALSE;
170 #endif
171 #ifdef XFIXES
172 Bool noXFixesExtension = FALSE;
173 #endif
174 #ifdef PANORAMIX
175 /* Xinerama is disabled by default unless enabled via +xinerama */
176 Bool noPanoramiXExtension = TRUE;
177 #endif
178 #ifdef XSELINUX
179 Bool noSELinuxExtension = FALSE;
180 int selinuxEnforcingState = SELINUX_MODE_DEFAULT;
181 #endif
182 #ifdef XV
183 Bool noXvExtension = FALSE;
184 #endif
185 #ifdef DRI2
186 Bool noDRI2Extension = FALSE;
187 #endif
189 Bool noGEExtension = FALSE;
191 #define X_INCLUDE_NETDB_H
192 #include <X11/Xos_r.h>
194 #include <errno.h>
196 Bool CoreDump;
198 #ifdef PANORAMIX
199 Bool PanoramiXExtensionDisabledHack = FALSE;
200 #endif
202 int auditTrailLevel = 1;
204 #if defined(SVR4) || defined(__linux__) || defined(CSRG_BASED)
205 #define HAS_SAVED_IDS_AND_SETEUID
206 #endif
208 OsSigHandlerPtr
209 OsSignal(int sig, OsSigHandlerPtr handler)
210 {
211 struct sigaction act, oact;
213 sigemptyset(&act.sa_mask);
214 if (handler != SIG_IGN)
215 sigaddset(&act.sa_mask, sig);
216 act.sa_flags = 0;
217 act.sa_handler = handler;
218 if (sigaction(sig, &act, &oact))
219 perror("sigaction");
220 return oact.sa_handler;
221 }
223 /*
224 * Explicit support for a server lock file like the ones used for UUCP.
225 * For architectures with virtual terminals that can run more than one
226 * server at a time. This keeps the servers from stomping on each other
227 * if the user forgets to give them different display numbers.
228 */
229 #define LOCK_DIR "/tmp"
230 #define LOCK_TMP_PREFIX "/.tX"
231 #define LOCK_PREFIX "/.X"
232 #define LOCK_SUFFIX "-lock"
234 static Bool StillLocking = FALSE;
235 static char LockFile[PATH_MAX];
236 static Bool nolock = FALSE;
238 /*
239 * LockServer --
240 * Check if the server lock file exists. If so, check if the PID
241 * contained inside is valid. If so, then die. Otherwise, create
242 * the lock file containing the PID.
243 */
244 void
245 LockServer(void)
246 {
247 char tmp[PATH_MAX], pid_str[12];
248 int lfd, i, haslock, l_pid, t;
249 char *tmppath = NULL;
250 int len;
251 char port[20];
253 if (nolock) return;
254 /*
255 * Path names
256 */
257 tmppath = LOCK_DIR;
259 sprintf(port, "%d", atoi(display));
260 len = strlen(LOCK_PREFIX) > strlen(LOCK_TMP_PREFIX) ? strlen(LOCK_PREFIX) :
261 strlen(LOCK_TMP_PREFIX);
262 len += strlen(tmppath) + strlen(port) + strlen(LOCK_SUFFIX) + 1;
263 if (len > sizeof(LockFile))
264 FatalError("Display name `%s' is too long\n", port);
265 (void)sprintf(tmp, "%s" LOCK_TMP_PREFIX "%s" LOCK_SUFFIX, tmppath, port);
266 (void)sprintf(LockFile, "%s" LOCK_PREFIX "%s" LOCK_SUFFIX, tmppath, port);
268 /*
269 * Create a temporary file containing our PID. Attempt three times
270 * to create the file.
271 */
272 StillLocking = TRUE;
273 i = 0;
274 do {
275 i++;
276 lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644);
277 if (lfd < 0)
278 sleep(2);
279 else
280 break;
281 } while (i < 3);
282 if (lfd < 0) {
283 unlink(tmp);
284 i = 0;
285 do {
286 i++;
287 lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644);
288 if (lfd < 0)
289 sleep(2);
290 else
291 break;
292 } while (i < 3);
293 }
294 if (lfd < 0)
295 FatalError("Could not create lock file in %s\n", tmp);
296 (void) sprintf(pid_str, "%10ld\n", (long)getpid());
297 (void) write(lfd, pid_str, 11);
298 (void) fchmod(lfd, 0444);
299 (void) close(lfd);
301 /*
302 * OK. Now the tmp file exists. Try three times to move it in place
303 * for the lock.
304 */
305 i = 0;
306 haslock = 0;
307 while ((!haslock) && (i++ < 3)) {
308 haslock = (link(tmp,LockFile) == 0);
309 if (haslock) {
310 /*
311 * We're done.
312 */
313 break;
314 }
315 else {
316 /*
317 * Read the pid from the existing file
318 */
319 lfd = open(LockFile, O_RDONLY|O_NOFOLLOW);
320 if (lfd < 0) {
321 unlink(tmp);
322 FatalError("Can't read lock file %s\n", LockFile);
323 }
324 pid_str[0] = '\0';
325 if (read(lfd, pid_str, 11) != 11) {
326 /*
327 * Bogus lock file.
328 */
329 unlink(LockFile);
330 close(lfd);
331 continue;
332 }
333 pid_str[11] = '\0';
334 sscanf(pid_str, "%d", &l_pid);
335 close(lfd);
337 /*
338 * Now try to kill the PID to see if it exists.
339 */
340 errno = 0;
341 t = kill(l_pid, 0);
342 if ((t< 0) && (errno == ESRCH)) {
343 /*
344 * Stale lock file.
345 */
346 unlink(LockFile);
347 continue;
348 }
349 else if (((t < 0) && (errno == EPERM)) || (t == 0)) {
350 /*
351 * Process is still active.
352 */
353 unlink(tmp);
354 FatalError("Server is already active for display %s\n%s %s\n%s\n",
355 port, "\tIf this server is no longer running, remove",
356 LockFile, "\tand start again.");
357 }
358 }
359 }
360 unlink(tmp);
361 if (!haslock)
362 FatalError("Could not create server lock file: %s\n", LockFile);
363 StillLocking = FALSE;
364 }
366 /*
367 * UnlockServer --
368 * Remove the server lock file.
369 */
370 void
371 UnlockServer(void)
372 {
373 if (nolock) return;
375 if (!StillLocking){
377 (void) unlink(LockFile);
378 }
379 }
381 /* Force connections to close on SIGHUP from init */
383 void
384 AutoResetServer (int sig)
385 {
386 int olderrno = errno;
388 dispatchException |= DE_RESET;
389 isItTimeToYield = TRUE;
390 errno = olderrno;
391 }
393 /* Force connections to close and then exit on SIGTERM, SIGINT */
395 void
396 GiveUp(int sig)
397 {
398 int olderrno = errno;
400 dispatchException |= DE_TERMINATE;
401 isItTimeToYield = TRUE;
402 errno = olderrno;
403 }
405 #if (defined WIN32 && defined __MINGW32__) || defined(__CYGWIN__)
406 CARD32
407 GetTimeInMillis (void)
408 {
409 return GetTickCount ();
410 }
411 #else
412 CARD32
413 GetTimeInMillis(void)
414 {
415 struct timeval tv;
417 #ifdef MONOTONIC_CLOCK
418 struct timespec tp;
419 static clockid_t clockid;
420 if (!clockid) {
421 #ifdef CLOCK_MONOTONIC_COARSE
422 if (clock_getres(CLOCK_MONOTONIC_COARSE, &tp) == 0 &&
423 (tp.tv_nsec / 1000) <= 1000 &&
424 clock_gettime(CLOCK_MONOTONIC_COARSE, &tp) == 0)
425 clockid = CLOCK_MONOTONIC_COARSE;
426 else
427 #endif
428 if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
429 clockid = CLOCK_MONOTONIC;
430 else
431 clockid = ~0L;
432 }
433 if (clockid != ~0L && clock_gettime(clockid, &tp) == 0)
434 return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
435 #endif
437 X_GETTIMEOFDAY(&tv);
438 return(tv.tv_sec * 1000) + (tv.tv_usec / 1000);
439 }
440 #endif
442 void
443 AdjustWaitForDelay (pointer waitTime, unsigned long newdelay)
444 {
445 static struct timeval delay_val;
446 struct timeval **wt = (struct timeval **) waitTime;
447 unsigned long olddelay;
449 if (*wt == NULL)
450 {
451 delay_val.tv_sec = newdelay / 1000;
452 delay_val.tv_usec = 1000 * (newdelay % 1000);
453 *wt = &delay_val;
454 }
455 else
456 {
457 olddelay = (*wt)->tv_sec * 1000 + (*wt)->tv_usec / 1000;
458 if (newdelay < olddelay)
459 {
460 (*wt)->tv_sec = newdelay / 1000;
461 (*wt)->tv_usec = 1000 * (newdelay % 1000);
462 }
463 }
464 }
466 void UseMsg(void)
467 {
468 ErrorF("use: X [:<display>] [option]\n");
469 ErrorF("-a # default pointer acceleration (factor)\n");
470 ErrorF("-ac disable access control restrictions\n");
471 ErrorF("-audit int set audit trail level\n");
472 ErrorF("-auth file select authorization file\n");
473 ErrorF("-br create root window with black background\n");
474 ErrorF("+bs enable any backing store support\n");
475 ErrorF("-bs disable any backing store support\n");
476 ErrorF("-c turns off key-click\n");
477 ErrorF("c # key-click volume (0-100)\n");
478 ErrorF("-cc int default color visual class\n");
479 ErrorF("-nocursor disable the cursor\n");
480 ErrorF("-core generate core dump on fatal error\n");
481 ErrorF("-dpi int screen resolution in dots per inch\n");
482 #ifdef DPMSExtension
483 ErrorF("-dpms disables VESA DPMS monitor control\n");
484 #endif
485 ErrorF("-deferglyphs [none|all|16] defer loading of [no|all|16-bit] glyphs\n");
486 ErrorF("-f # bell base (0-100)\n");
487 ErrorF("-fc string cursor font\n");
488 ErrorF("-fn string default font name\n");
489 ErrorF("-fp string default font path\n");
490 ErrorF("-help prints message with these options\n");
491 ErrorF("-I ignore all remaining arguments\n");
492 #ifdef RLIMIT_DATA
493 ErrorF("-ld int limit data space to N Kb\n");
494 #endif
495 #ifdef RLIMIT_NOFILE
496 ErrorF("-lf int limit number of open files to N\n");
497 #endif
498 #ifdef RLIMIT_STACK
499 ErrorF("-ls int limit stack space to N Kb\n");
500 #endif
501 ErrorF("-nolock disable the locking mechanism\n");
502 ErrorF("-nolisten string don't listen on protocol\n");
503 ErrorF("-noreset don't reset after last client exists\n");
504 ErrorF("-background [none] create root window with no background\n");
505 ErrorF("-nr (Ubuntu-specific) Synonym for -background none\n");
506 ErrorF("-reset reset after last client exists\n");
507 ErrorF("-p # screen-saver pattern duration (minutes)\n");
508 ErrorF("-pn accept failure to listen on all ports\n");
509 ErrorF("-nopn reject failure to listen on all ports\n");
510 ErrorF("-r turns off auto-repeat\n");
511 ErrorF("r turns on auto-repeat \n");
512 ErrorF("-render [default|mono|gray|color] set render color alloc policy\n");
513 ErrorF("-retro start with classic stipple and cursor\n");
514 ErrorF("-s # screen-saver timeout (minutes)\n");
515 ErrorF("-t # default pointer threshold (pixels/t)\n");
516 ErrorF("-terminate terminate at server reset\n");
517 ErrorF("-to # connection time out\n");
518 ErrorF("-tst disable testing extensions\n");
519 ErrorF("ttyxx server started from init on /dev/ttyxx\n");
520 ErrorF("v video blanking for screen-saver\n");
521 ErrorF("-v screen-saver without video blanking\n");
522 ErrorF("-wm WhenMapped default backing-store\n");
523 ErrorF("-wr create root window with white background\n");
524 ErrorF("-maxbigreqsize set maximal bigrequest size \n");
525 #ifdef PANORAMIX
526 ErrorF("+xinerama Enable XINERAMA extension\n");
527 ErrorF("-xinerama Disable XINERAMA extension\n");
528 #endif
529 ErrorF("-dumbSched Disable smart scheduling, enable old behavior\n");
530 ErrorF("-schedInterval int Set scheduler interval in msec\n");
531 ErrorF("-sigstop Enable SIGSTOP based startup\n");
532 ErrorF("+extension name Enable extension\n");
533 ErrorF("-extension name Disable extension\n");
534 #ifdef XDMCP
535 XdmcpUseMsg();
536 #endif
537 XkbUseMsg();
538 ddxUseMsg();
539 }
541 /* This function performs a rudimentary sanity check
542 * on the display name passed in on the command-line,
543 * since this string is used to generate filenames.
544 * It is especially important that the display name
545 * not contain a "/" and not start with a "-".
546 * --kvajk
547 */
548 static int
549 VerifyDisplayName(const char *d)
550 {
551 if ( d == (char *)0 ) return 0; /* null */
552 if ( *d == '\0' ) return 0; /* empty */
553 if ( *d == '-' ) return 0; /* could be confused for an option */
554 if ( *d == '.' ) return 0; /* must not equal "." or ".." */
555 if ( strchr(d, '/') != (char *)0 ) return 0; /* very important!!! */
556 return 1;
557 }
559 /*
560 * This function parses the command line. Handles device-independent fields
561 * and allows ddx to handle additional fields. It is not allowed to modify
562 * argc or any of the strings pointed to by argv.
563 */
564 void
565 ProcessCommandLine(int argc, char *argv[])
566 {
567 int i, skip;
569 defaultKeyboardControl.autoRepeat = TRUE;
571 #ifdef NO_PART_NET
572 PartialNetwork = FALSE;
573 #else
574 PartialNetwork = TRUE;
575 #endif
577 for ( i = 1; i < argc; i++ )
578 {
579 /* call ddx first, so it can peek/override if it wants */
580 if((skip = ddxProcessArgument(argc, argv, i)))
581 {
582 i += (skip - 1);
583 }
584 else if(argv[i][0] == ':')
585 {
586 /* initialize display */
587 display = argv[i];
588 display++;
589 if( ! VerifyDisplayName( display ) ) {
590 ErrorF("Bad display name: %s\n", display);
591 UseMsg();
592 FatalError("Bad display name, exiting: %s\n", display);
593 }
594 }
595 else if ( strcmp( argv[i], "-a") == 0)
596 {
597 if(++i < argc)
598 defaultPointerControl.num = atoi(argv[i]);
599 else
600 UseMsg();
601 }
602 else if ( strcmp( argv[i], "-ac") == 0)
603 {
604 defeatAccessControl = TRUE;
605 }
606 else if ( strcmp( argv[i], "-audit") == 0)
607 {
608 if(++i < argc)
609 auditTrailLevel = atoi(argv[i]);
610 else
611 UseMsg();
612 }
613 else if ( strcmp( argv[i], "-auth") == 0)
614 {
615 if(++i < argc)
616 InitAuthorization (argv[i]);
617 else
618 UseMsg();
619 }
620 else if ( strcmp( argv[i], "-br") == 0) ; /* default */
621 else if ( strcmp( argv[i], "+bs") == 0)
622 enableBackingStore = TRUE;
623 else if ( strcmp( argv[i], "-bs") == 0)
624 disableBackingStore = TRUE;
625 else if ( strcmp( argv[i], "c") == 0)
626 {
627 if(++i < argc)
628 defaultKeyboardControl.click = atoi(argv[i]);
629 else
630 UseMsg();
631 }
632 else if ( strcmp( argv[i], "-c") == 0)
633 {
634 defaultKeyboardControl.click = 0;
635 }
636 else if ( strcmp( argv[i], "-cc") == 0)
637 {
638 if(++i < argc)
639 defaultColorVisualClass = atoi(argv[i]);
640 else
641 UseMsg();
642 }
643 else if ( strcmp( argv[i], "-core") == 0)
644 {
645 #if !defined(WIN32) || !defined(__MINGW32__)
646 struct rlimit core_limit;
647 getrlimit (RLIMIT_CORE, &core_limit);
648 core_limit.rlim_cur = core_limit.rlim_max;
649 setrlimit (RLIMIT_CORE, &core_limit);
650 #endif
651 CoreDump = TRUE;
652 }
653 else if ( strcmp( argv[i], "-nocursor") == 0)
654 {
655 EnableCursor = FALSE;
656 }
657 else if ( strcmp( argv[i], "-dpi") == 0)
658 {
659 if(++i < argc)
660 monitorResolution = atoi(argv[i]);
661 else
662 UseMsg();
663 }
664 #ifdef DPMSExtension
665 else if ( strcmp( argv[i], "dpms") == 0)
666 /* ignored for compatibility */ ;
667 else if ( strcmp( argv[i], "-dpms") == 0)
668 DPMSDisabledSwitch = TRUE;
669 #endif
670 else if ( strcmp( argv[i], "-deferglyphs") == 0)
671 {
672 if(++i >= argc || !ParseGlyphCachingMode(argv[i]))
673 UseMsg();
674 }
675 else if ( strcmp( argv[i], "-f") == 0)
676 {
677 if(++i < argc)
678 defaultKeyboardControl.bell = atoi(argv[i]);
679 else
680 UseMsg();
681 }
682 else if ( strcmp( argv[i], "-fc") == 0)
683 {
684 if(++i < argc)
685 defaultCursorFont = argv[i];
686 else
687 UseMsg();
688 }
689 else if ( strcmp( argv[i], "-fn") == 0)
690 {
691 if(++i < argc)
692 defaultTextFont = argv[i];
693 else
694 UseMsg();
695 }
696 else if ( strcmp( argv[i], "-fp") == 0)
697 {
698 if(++i < argc)
699 {
700 defaultFontPath = argv[i];
701 }
702 else
703 UseMsg();
704 }
705 else if ( strcmp( argv[i], "-help") == 0)
706 {
707 UseMsg();
708 exit(0);
709 }
710 else if ( (skip=XkbProcessArguments(argc,argv,i))!=0 ) {
711 if (skip>0)
712 i+= skip-1;
713 else UseMsg();
714 }
715 #ifdef RLIMIT_DATA
716 else if ( strcmp( argv[i], "-ld") == 0)
717 {
718 if(++i < argc)
719 {
720 limitDataSpace = atoi(argv[i]);
721 if (limitDataSpace > 0)
722 limitDataSpace *= 1024;
723 }
724 else
725 UseMsg();
726 }
727 #endif
728 #ifdef RLIMIT_NOFILE
729 else if ( strcmp( argv[i], "-lf") == 0)
730 {
731 if(++i < argc)
732 limitNoFile = atoi(argv[i]);
733 else
734 UseMsg();
735 }
736 #endif
737 #ifdef RLIMIT_STACK
738 else if ( strcmp( argv[i], "-ls") == 0)
739 {
740 if(++i < argc)
741 {
742 limitStackSpace = atoi(argv[i]);
743 if (limitStackSpace > 0)
744 limitStackSpace *= 1024;
745 }
746 else
747 UseMsg();
748 }
749 #endif
750 else if ( strcmp ( argv[i], "-nolock") == 0)
751 {
752 #if !defined(WIN32) && !defined(__CYGWIN__)
753 if (getuid() != 0)
754 ErrorF("Warning: the -nolock option can only be used by root\n");
755 else
756 #endif
757 nolock = TRUE;
758 }
759 else if ( strcmp( argv[i], "-nolisten") == 0)
760 {
761 if(++i < argc) {
762 if (_XSERVTransNoListen(argv[i]))
763 FatalError ("Failed to disable listen for %s transport",
764 argv[i]);
765 } else
766 UseMsg();
767 }
768 else if ( strcmp( argv[i], "-noreset") == 0)
769 {
770 dispatchExceptionAtReset = 0;
771 }
772 else if ( strcmp( argv[i], "-reset") == 0)
773 {
774 dispatchExceptionAtReset = DE_RESET;
775 }
776 else if ( strcmp( argv[i], "-p") == 0)
777 {
778 if(++i < argc)
779 defaultScreenSaverInterval = ((CARD32)atoi(argv[i])) *
780 MILLI_PER_MIN;
781 else
782 UseMsg();
783 }
784 else if (strcmp(argv[i], "-pogo") == 0)
785 {
786 dispatchException = DE_TERMINATE;
787 }
788 else if ( strcmp( argv[i], "-pn") == 0)
789 PartialNetwork = TRUE;
790 else if ( strcmp( argv[i], "-nopn") == 0)
791 PartialNetwork = FALSE;
792 else if ( strcmp( argv[i], "r") == 0)
793 defaultKeyboardControl.autoRepeat = TRUE;
794 else if ( strcmp( argv[i], "-r") == 0)
795 defaultKeyboardControl.autoRepeat = FALSE;
796 else if ( strcmp( argv[i], "-retro") == 0)
797 party_like_its_1989 = TRUE;
798 else if ( strcmp( argv[i], "-s") == 0)
799 {
800 if(++i < argc)
801 defaultScreenSaverTime = ((CARD32)atoi(argv[i])) *
802 MILLI_PER_MIN;
803 else
804 UseMsg();
805 }
806 else if ( strcmp( argv[i], "-t") == 0)
807 {
808 if(++i < argc)
809 defaultPointerControl.threshold = atoi(argv[i]);
810 else
811 UseMsg();
812 }
813 else if ( strcmp( argv[i], "-terminate") == 0)
814 {
815 dispatchExceptionAtReset = DE_TERMINATE;
816 }
817 else if ( strcmp( argv[i], "-to") == 0)
818 {
819 if(++i < argc)
820 TimeOutValue = ((CARD32)atoi(argv[i])) * MILLI_PER_SECOND;
821 else
822 UseMsg();
823 }
824 else if ( strcmp( argv[i], "-tst") == 0)
825 {
826 noTestExtensions = TRUE;
827 }
828 else if ( strcmp( argv[i], "v") == 0)
829 defaultScreenSaverBlanking = PreferBlanking;
830 else if ( strcmp( argv[i], "-v") == 0)
831 defaultScreenSaverBlanking = DontPreferBlanking;
832 else if ( strcmp( argv[i], "-wm") == 0)
833 defaultBackingStore = WhenMapped;
834 else if ( strcmp( argv[i], "-wr") == 0)
835 whiteRoot = TRUE;
836 else if ( strcmp( argv[i], "-background") == 0) {
837 if(++i < argc) {
838 if (!strcmp ( argv[i], "none"))
839 bgNoneRoot = TRUE;
840 else
841 UseMsg();
842 }
843 }
844 else if ( strcmp( argv[i], "-nr") == 0)
845 bgNoneRoot = TRUE;
846 else if ( strcmp( argv[i], "-maxbigreqsize") == 0) {
847 if(++i < argc) {
848 long reqSizeArg = atol(argv[i]);
850 /* Request size > 128MB does not make much sense... */
851 if( reqSizeArg > 0L && reqSizeArg < 128L ) {
852 maxBigRequestSize = (reqSizeArg * 1048576L) - 1L;
853 }
854 else
855 {
856 UseMsg();
857 }
858 }
859 else
860 {
861 UseMsg();
862 }
863 }
864 #ifdef PANORAMIX
865 else if ( strcmp( argv[i], "+xinerama") == 0){
866 noPanoramiXExtension = FALSE;
867 }
868 else if ( strcmp( argv[i], "-xinerama") == 0){
869 noPanoramiXExtension = TRUE;
870 }
871 else if ( strcmp( argv[i], "-disablexineramaextension") == 0){
872 PanoramiXExtensionDisabledHack = TRUE;
873 }
874 #endif
875 else if ( strcmp( argv[i], "-I") == 0)
876 {
877 /* ignore all remaining arguments */
878 break;
879 }
880 else if (strncmp (argv[i], "tty", 3) == 0)
881 {
882 /* init supplies us with this useless information */
883 }
884 #ifdef XDMCP
885 else if ((skip = XdmcpOptions(argc, argv, i)) != i)
886 {
887 i = skip - 1;
888 }
889 #endif
890 else if ( strcmp( argv[i], "-dumbSched") == 0)
891 {
892 SmartScheduleDisable = TRUE;
893 }
894 else if ( strcmp( argv[i], "-schedInterval") == 0)
895 {
896 if (++i < argc)
897 {
898 SmartScheduleInterval = atoi(argv[i]);
899 SmartScheduleSlice = SmartScheduleInterval;
900 }
901 else
902 UseMsg();
903 }
904 else if ( strcmp( argv[i], "-schedMax") == 0)
905 {
906 if (++i < argc)
907 {
908 SmartScheduleMaxSlice = atoi(argv[i]);
909 }
910 else
911 UseMsg();
912 }
913 else if ( strcmp( argv[i], "-render" ) == 0)
914 {
915 if (++i < argc)
916 {
917 int policy = PictureParseCmapPolicy (argv[i]);
919 if (policy != PictureCmapPolicyInvalid)
920 PictureCmapPolicy = policy;
921 else
922 UseMsg ();
923 }
924 else
925 UseMsg ();
926 }
927 else if ( strcmp( argv[i], "-sigstop") == 0)
928 {
929 RunFromSigStopParent = TRUE;
930 }
931 else if ( strcmp( argv[i], "+extension") == 0)
932 {
933 if (++i < argc)
934 {
935 if (!EnableDisableExtension(argv[i], TRUE))
936 EnableDisableExtensionError(argv[i], TRUE);
937 }
938 else
939 UseMsg();
940 }
941 else if ( strcmp( argv[i], "-extension") == 0)
942 {
943 if (++i < argc)
944 {
945 if (!EnableDisableExtension(argv[i], FALSE))
946 EnableDisableExtensionError(argv[i], FALSE);
947 }
948 else
949 UseMsg();
950 }
951 else
952 {
953 ErrorF("Unrecognized option: %s\n", argv[i]);
954 UseMsg();
955 FatalError("Unrecognized option: %s\n", argv[i]);
956 }
957 }
958 }
960 /* Implement a simple-minded font authorization scheme. The authorization
961 name is "hp-hostname-1", the contents are simply the host name. */
962 int
963 set_font_authorizations(char **authorizations, int *authlen, pointer client)
964 {
965 #define AUTHORIZATION_NAME "hp-hostname-1"
966 #if defined(TCPCONN) || defined(STREAMSCONN)
967 static char *result = NULL;
968 static char *p = NULL;
970 if (p == NULL)
971 {
972 char hname[1024], *hnameptr;
973 unsigned int len;
974 #if defined(IPv6) && defined(AF_INET6)
975 struct addrinfo hints, *ai = NULL;
976 #else
977 struct hostent *host;
978 #ifdef XTHREADS_NEEDS_BYNAMEPARAMS
979 _Xgethostbynameparams hparams;
980 #endif
981 #endif
983 gethostname(hname, 1024);
984 #if defined(IPv6) && defined(AF_INET6)
985 memset(&hints, 0, sizeof(hints));
986 hints.ai_flags = AI_CANONNAME;
987 if (getaddrinfo(hname, NULL, &hints, &ai) == 0) {
988 hnameptr = ai->ai_canonname;
989 } else {
990 hnameptr = hname;
991 }
992 #else
993 host = _XGethostbyname(hname, hparams);
994 if (host == NULL)
995 hnameptr = hname;
996 else
997 hnameptr = host->h_name;
998 #endif
1000 len = strlen(hnameptr) + 1;
1001 result = malloc(len + sizeof(AUTHORIZATION_NAME) + 4);
1003 p = result;
1004 *p++ = sizeof(AUTHORIZATION_NAME) >> 8;
1005 *p++ = sizeof(AUTHORIZATION_NAME) & 0xff;
1006 *p++ = (len) >> 8;
1007 *p++ = (len & 0xff);
1009 memmove(p, AUTHORIZATION_NAME, sizeof(AUTHORIZATION_NAME));
1010 p += sizeof(AUTHORIZATION_NAME);
1011 memmove(p, hnameptr, len);
1012 p += len;
1013 #if defined(IPv6) && defined(AF_INET6)
1014 if (ai) {
1015 freeaddrinfo(ai);
1016 }
1017 #endif
1018 }
1019 *authlen = p - result;
1020 *authorizations = result;
1021 return 1;
1022 #else /* TCPCONN */
1023 return 0;
1024 #endif /* TCPCONN */
1025 }
1027 void *
1028 Xalloc(unsigned long amount)
1029 {
1030 /*
1031 * Xalloc used to return NULL when large amount of memory is requested. In
1032 * order to catch the buggy callers this warning has been added, slated to
1033 * removal by anyone who touches this code (or just looks at it) in 2011.
1034 *
1035 * -- Mikhail Gusarov
1036 */
1037 if ((long)amount <= 0)
1038 ErrorF("Warning: Xalloc: "
1039 "requesting unpleasantly large amount of memory: %lu bytes.\n",
1040 amount);
1042 return malloc(amount);
1043 }
1045 void *
1046 XNFalloc(unsigned long amount)
1047 {
1048 void *ptr = malloc(amount);
1049 if (!ptr)
1050 FatalError("Out of memory");
1051 return ptr;
1052 }
1054 void *
1055 Xcalloc(unsigned long amount)
1056 {
1057 return calloc(1, amount);
1058 }
1060 void *
1061 XNFcalloc(unsigned long amount)
1062 {
1063 void *ret = calloc(1, amount);
1064 if (!ret)
1065 FatalError("XNFcalloc: Out of memory");
1066 return ret;
1067 }
1069 void *
1070 Xrealloc(void *ptr, unsigned long amount)
1071 {
1072 /*
1073 * Xrealloc used to return NULL when large amount of memory is requested. In
1074 * order to catch the buggy callers this warning has been added, slated to
1075 * removal by anyone who touches this code (or just looks at it) in 2011.
1076 *
1077 * -- Mikhail Gusarov
1078 */
1079 if ((long)amount <= 0)
1080 ErrorF("Warning: Xrealloc: "
1081 "requesting unpleasantly large amount of memory: %lu bytes.\n",
1082 amount);
1084 return realloc(ptr, amount);
1085 }
1087 void *
1088 XNFrealloc(void *ptr, unsigned long amount)
1089 {
1090 void *ret = realloc(ptr, amount);
1091 if (!ret)
1092 FatalError("XNFrealloc: Out of memory");
1093 return ret;
1094 }
1096 void
1097 Xfree(void *ptr)
1098 {
1099 free(ptr);
1100 }
1103 char *
1104 Xstrdup(const char *s)
1105 {
1106 if (s == NULL)
1107 return NULL;
1108 return strdup(s);
1109 }
1111 char *
1112 XNFstrdup(const char *s)
1113 {
1114 char *ret;
1116 if (s == NULL)
1117 return NULL;
1119 ret = strdup(s);
1120 if (!ret)
1121 FatalError("XNFstrdup: Out of memory");
1122 return ret;
1123 }
1125 void
1126 SmartScheduleStopTimer (void)
1127 {
1128 struct itimerval timer;
1130 if (SmartScheduleDisable)
1131 return;
1132 timer.it_interval.tv_sec = 0;
1133 timer.it_interval.tv_usec = 0;
1134 timer.it_value.tv_sec = 0;
1135 timer.it_value.tv_usec = 0;
1136 (void) setitimer (ITIMER_REAL, &timer, 0);
1137 }
1139 void
1140 SmartScheduleStartTimer (void)
1141 {
1142 struct itimerval timer;
1144 if (SmartScheduleDisable)
1145 return;
1146 timer.it_interval.tv_sec = 0;
1147 timer.it_interval.tv_usec = SmartScheduleInterval * 1000;
1148 timer.it_value.tv_sec = 0;
1149 timer.it_value.tv_usec = SmartScheduleInterval * 1000;
1150 setitimer (ITIMER_REAL, &timer, 0);
1151 }
1153 static void
1154 SmartScheduleTimer (int sig)
1155 {
1156 SmartScheduleTime += SmartScheduleInterval;
1157 }
1159 void
1160 SmartScheduleInit (void)
1161 {
1162 struct sigaction act;
1164 if (SmartScheduleDisable)
1165 return;
1167 memset((char *) &act, 0, sizeof(struct sigaction));
1169 /* Set up the timer signal function */
1170 act.sa_handler = SmartScheduleTimer;
1171 sigemptyset (&act.sa_mask);
1172 sigaddset (&act.sa_mask, SIGALRM);
1173 if (sigaction (SIGALRM, &act, 0) < 0)
1174 {
1175 perror ("sigaction for smart scheduler");
1176 SmartScheduleDisable = TRUE;
1177 }
1178 }
1180 #ifdef SIG_BLOCK
1181 static sigset_t PreviousSignalMask;
1182 static int BlockedSignalCount;
1183 #endif
1185 void
1186 OsBlockSignals (void)
1187 {
1188 #ifdef SIG_BLOCK
1189 if (BlockedSignalCount++ == 0)
1190 {
1191 sigset_t set;
1193 sigemptyset (&set);
1194 sigaddset (&set, SIGALRM);
1195 sigaddset (&set, SIGVTALRM);
1196 #ifdef SIGWINCH
1197 sigaddset (&set, SIGWINCH);
1198 #endif
1199 #ifdef SIGIO
1200 sigaddset (&set, SIGIO);
1201 #endif
1202 sigaddset (&set, SIGTSTP);
1203 sigaddset (&set, SIGTTIN);
1204 sigaddset (&set, SIGTTOU);
1205 sigaddset (&set, SIGCHLD);
1206 sigprocmask (SIG_BLOCK, &set, &PreviousSignalMask);
1207 }
1208 #endif
1209 }
1211 void
1212 OsReleaseSignals (void)
1213 {
1214 #ifdef SIG_BLOCK
1215 if (--BlockedSignalCount == 0)
1216 {
1217 sigprocmask (SIG_SETMASK, &PreviousSignalMask, 0);
1218 }
1219 #endif
1220 }
1222 /*
1223 * Pending signals may interfere with core dumping. Provide a
1224 * mechanism to block signals when aborting.
1225 */
1227 void
1228 OsAbort (void)
1229 {
1230 #ifndef __APPLE__
1231 OsBlockSignals();
1232 #endif
1233 abort();
1234 }
1236 #if !defined(WIN32)
1237 /*
1238 * "safer" versions of system(3), popen(3) and pclose(3) which give up
1239 * all privs before running a command.
1240 *
1241 * This is based on the code in FreeBSD 2.2 libc.
1242 *
1243 * XXX It'd be good to redirect stderr so that it ends up in the log file
1244 * as well. As it is now, xkbcomp messages don't end up in the log file.
1245 */
1247 int
1248 System(char *command)
1249 {
1250 int pid, p;
1251 void (*csig)(int);
1252 int status;
1254 if (!command)
1255 return 1;
1257 csig = signal(SIGCHLD, SIG_DFL);
1258 if (csig == SIG_ERR) {
1259 perror("signal");
1260 return -1;
1261 }
1262 DebugF("System: `%s'\n", command);
1264 switch (pid = fork()) {
1265 case -1: /* error */
1266 p = -1;
1267 case 0: /* child */
1268 if (setgid(getgid()) == -1)
1269 _exit(127);
1270 if (setuid(getuid()) == -1)
1271 _exit(127);
1272 execl("/bin/sh", "sh", "-c", command, (char *)NULL);
1273 _exit(127);
1274 default: /* parent */
1275 do {
1276 p = waitpid(pid, &status, 0);
1277 } while (p == -1 && errno == EINTR);
1279 }
1281 if (signal(SIGCHLD, csig) == SIG_ERR) {
1282 perror("signal");
1283 return -1;
1284 }
1286 return p == -1 ? -1 : status;
1287 }
1289 static struct pid {
1290 struct pid *next;
1291 FILE *fp;
1292 int pid;
1293 } *pidlist;
1295 OsSigHandlerPtr old_alarm = NULL; /* XXX horrible awful hack */
1297 pointer
1298 Popen(char *command, char *type)
1299 {
1300 struct pid *cur;
1301 FILE *iop;
1302 int pdes[2], pid;
1304 if (command == NULL || type == NULL)
1305 return NULL;
1307 if ((*type != 'r' && *type != 'w') || type[1])
1308 return NULL;
1310 if ((cur = malloc(sizeof(struct pid))) == NULL)
1311 return NULL;
1313 if (pipe(pdes) < 0) {
1314 free(cur);
1315 return NULL;
1316 }
1318 /* Ignore the smart scheduler while this is going on */
1319 old_alarm = OsSignal(SIGALRM, SIG_IGN);
1320 if (old_alarm == SIG_ERR) {
1321 close(pdes[0]);
1322 close(pdes[1]);
1323 free(cur);
1324 perror("signal");
1325 return NULL;
1326 }
1328 switch (pid = fork()) {
1329 case -1: /* error */
1330 close(pdes[0]);
1331 close(pdes[1]);
1332 free(cur);
1333 if (OsSignal(SIGALRM, old_alarm) == SIG_ERR)
1334 perror("signal");
1335 return NULL;
1336 case 0: /* child */
1337 if (setgid(getgid()) == -1)
1338 _exit(127);
1339 if (setuid(getuid()) == -1)
1340 _exit(127);
1341 if (*type == 'r') {
1342 if (pdes[1] != 1) {
1343 /* stdout */
1344 dup2(pdes[1], 1);
1345 close(pdes[1]);
1346 }
1347 close(pdes[0]);
1348 } else {
1349 if (pdes[0] != 0) {
1350 /* stdin */
1351 dup2(pdes[0], 0);
1352 close(pdes[0]);
1353 }
1354 close(pdes[1]);
1355 }
1356 execl("/bin/sh", "sh", "-c", command, (char *)NULL);
1357 _exit(127);
1358 }
1360 /* Avoid EINTR during stdio calls */
1361 OsBlockSignals ();
1363 /* parent */
1364 if (*type == 'r') {
1365 iop = fdopen(pdes[0], type);
1366 close(pdes[1]);
1367 } else {
1368 iop = fdopen(pdes[1], type);
1369 close(pdes[0]);
1370 }
1372 cur->fp = iop;
1373 cur->pid = pid;
1374 cur->next = pidlist;
1375 pidlist = cur;
1377 DebugF("Popen: `%s', fp = %p\n", command, iop);
1379 return iop;
1380 }
1382 /* fopen that drops privileges */
1383 pointer
1384 Fopen(char *file, char *type)
1385 {
1386 FILE *iop;
1387 #ifndef HAS_SAVED_IDS_AND_SETEUID
1388 struct pid *cur;
1389 int pdes[2], pid;
1391 if (file == NULL || type == NULL)
1392 return NULL;
1394 if ((*type != 'r' && *type != 'w') || type[1])
1395 return NULL;
1397 if ((cur = malloc(sizeof(struct pid))) == NULL)
1398 return NULL;
1400 if (pipe(pdes) < 0) {
1401 free(cur);
1402 return NULL;
1403 }
1405 switch (pid = fork()) {
1406 case -1: /* error */
1407 close(pdes[0]);
1408 close(pdes[1]);
1409 free(cur);
1410 return NULL;
1411 case 0: /* child */
1412 if (setgid(getgid()) == -1)
1413 _exit(127);
1414 if (setuid(getuid()) == -1)
1415 _exit(127);
1416 if (*type == 'r') {
1417 if (pdes[1] != 1) {
1418 /* stdout */
1419 dup2(pdes[1], 1);
1420 close(pdes[1]);
1421 }
1422 close(pdes[0]);
1423 } else {
1424 if (pdes[0] != 0) {
1425 /* stdin */
1426 dup2(pdes[0], 0);
1427 close(pdes[0]);
1428 }
1429 close(pdes[1]);
1430 }
1431 execl("/bin/cat", "cat", file, (char *)NULL);
1432 _exit(127);
1433 }
1435 /* Avoid EINTR during stdio calls */
1436 OsBlockSignals ();
1438 /* parent */
1439 if (*type == 'r') {
1440 iop = fdopen(pdes[0], type);
1441 close(pdes[1]);
1442 } else {
1443 iop = fdopen(pdes[1], type);
1444 close(pdes[0]);
1445 }
1447 cur->fp = iop;
1448 cur->pid = pid;
1449 cur->next = pidlist;
1450 pidlist = cur;
1452 DebugF("Fopen(%s), fp = %p\n", file, iop);
1454 return iop;
1455 #else
1456 int ruid, euid;
1458 ruid = getuid();
1459 euid = geteuid();
1461 if (seteuid(ruid) == -1) {
1462 return NULL;
1463 }
1464 iop = fopen(file, type);
1466 if (seteuid(euid) == -1) {
1467 fclose(iop);
1468 return NULL;
1469 }
1470 return iop;
1471 #endif /* HAS_SAVED_IDS_AND_SETEUID */
1472 }
1474 int
1475 Pclose(pointer iop)
1476 {
1477 struct pid *cur, *last;
1478 int pstat;
1479 int pid;
1481 DebugF("Pclose: fp = %p\n", iop);
1482 fclose(iop);
1484 for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
1485 if (cur->fp == iop)
1486 break;
1487 if (cur == NULL)
1488 return -1;
1490 do {
1491 pid = waitpid(cur->pid, &pstat, 0);
1492 } while (pid == -1 && errno == EINTR);
1494 if (last == NULL)
1495 pidlist = cur->next;
1496 else
1497 last->next = cur->next;
1498 free(cur);
1500 /* allow EINTR again */
1501 OsReleaseSignals ();
1503 if (old_alarm && OsSignal(SIGALRM, old_alarm) == SIG_ERR) {
1504 perror("signal");
1505 return -1;
1506 }
1508 return pid == -1 ? -1 : pstat;
1509 }
1511 int
1512 Fclose(pointer iop)
1513 {
1514 #ifdef HAS_SAVED_IDS_AND_SETEUID
1515 return fclose(iop);
1516 #else
1517 return Pclose(iop);
1518 #endif
1519 }
1521 #endif /* !WIN32 */
1524 /*
1525 * CheckUserParameters: check for long command line arguments and long
1526 * environment variables. By default, these checks are only done when
1527 * the server's euid != ruid. In 3.3.x, these checks were done in an
1528 * external wrapper utility.
1529 */
1531 /* Consider LD* variables insecure? */
1532 #ifndef REMOVE_ENV_LD
1533 #define REMOVE_ENV_LD 1
1534 #endif
1536 /* Remove long environment variables? */
1537 #ifndef REMOVE_LONG_ENV
1538 #define REMOVE_LONG_ENV 1
1539 #endif
1541 /*
1542 * Disallow stdout or stderr as pipes? It's possible to block the X server
1543 * when piping stdout+stderr to a pipe.
1544 *
1545 * Don't enable this because it looks like it's going to cause problems.
1546 */
1547 #ifndef NO_OUTPUT_PIPES
1548 #define NO_OUTPUT_PIPES 0
1549 #endif
1552 /* Check args and env only if running setuid (euid == 0 && euid != uid) ? */
1553 #ifndef CHECK_EUID
1554 #ifndef WIN32
1555 #define CHECK_EUID 1
1556 #else
1557 #define CHECK_EUID 0
1558 #endif
1559 #endif
1561 /*
1562 * Maybe the locale can be faked to make isprint(3) report that everything
1563 * is printable? Avoid it by default.
1564 */
1565 #ifndef USE_ISPRINT
1566 #define USE_ISPRINT 0
1567 #endif
1569 #define MAX_ARG_LENGTH 128
1570 #define MAX_ENV_LENGTH 256
1571 #define MAX_ENV_PATH_LENGTH 2048 /* Limit for *PATH and TERMCAP */
1573 #if USE_ISPRINT
1574 #include <ctype.h>
1575 #define checkPrintable(c) isprint(c)
1576 #else
1577 #define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f)
1578 #endif
1580 enum BadCode {
1581 NotBad = 0,
1582 UnsafeArg,
1583 ArgTooLong,
1584 UnprintableArg,
1585 EnvTooLong,
1586 OutputIsPipe,
1587 InternalError
1588 };
1590 #if defined(VENDORSUPPORT)
1591 #define BUGADDRESS VENDORSUPPORT
1592 #elif defined(BUILDERADDR)
1593 #define BUGADDRESS BUILDERADDR
1594 #else
1595 #define BUGADDRESS "xorg@freedesktop.org"
1596 #endif
1598 void
1599 CheckUserParameters(int argc, char **argv, char **envp)
1600 {
1601 enum BadCode bad = NotBad;
1602 int i = 0, j;
1603 char *a, *e = NULL;
1605 #if CHECK_EUID
1606 if (geteuid() == 0 && getuid() != geteuid())
1607 #endif
1608 {
1609 /* Check each argv[] */
1610 for (i = 1; i < argc; i++) {
1611 if (strcmp(argv[i], "-fp") == 0)
1612 {
1613 i++; /* continue with next argument. skip the length check */
1614 if (i >= argc)
1615 break;
1616 } else
1617 {
1618 if (strlen(argv[i]) > MAX_ARG_LENGTH) {
1619 bad = ArgTooLong;
1620 break;
1621 }
1622 }
1623 a = argv[i];
1624 while (*a) {
1625 if (checkPrintable(*a) == 0) {
1626 bad = UnprintableArg;
1627 break;
1628 }
1629 a++;
1630 }
1631 if (bad)
1632 break;
1633 }
1634 if (!bad) {
1635 /* Check each envp[] */
1636 for (i = 0; envp[i]; i++) {
1638 /* Check for bad environment variables and values */
1639 #if REMOVE_ENV_LD
1640 while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) {
1641 for (j = i; envp[j]; j++) {
1642 envp[j] = envp[j+1];
1643 }
1644 }
1645 #endif
1646 if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) {
1647 #if REMOVE_LONG_ENV
1648 for (j = i; envp[j]; j++) {
1649 envp[j] = envp[j+1];
1650 }
1651 i--;
1652 #else
1653 char *eq;
1654 int len;
1656 eq = strchr(envp[i], '=');
1657 if (!eq)
1658 continue;
1659 len = eq - envp[i];
1660 e = malloc(len + 1);
1661 if (!e) {
1662 bad = InternalError;
1663 break;
1664 }
1665 strncpy(e, envp[i], len);
1666 e[len] = 0;
1667 if (len >= 4 &&
1668 (strcmp(e + len - 4, "PATH") == 0 ||
1669 strcmp(e, "TERMCAP") == 0)) {
1670 if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) {
1671 bad = EnvTooLong;
1672 break;
1673 } else {
1674 free(e);
1675 }
1676 } else {
1677 bad = EnvTooLong;
1678 break;
1679 }
1680 #endif
1681 }
1682 }
1683 }
1684 #if NO_OUTPUT_PIPES
1685 if (!bad) {
1686 struct stat buf;
1688 if (fstat(fileno(stdout), &buf) == 0 && S_ISFIFO(buf.st_mode))
1689 bad = OutputIsPipe;
1690 if (fstat(fileno(stderr), &buf) == 0 && S_ISFIFO(buf.st_mode))
1691 bad = OutputIsPipe;
1692 }
1693 #endif
1694 }
1695 switch (bad) {
1696 case NotBad:
1697 return;
1698 case UnsafeArg:
1699 ErrorF("Command line argument number %d is unsafe\n", i);
1700 break;
1701 case ArgTooLong:
1702 ErrorF("Command line argument number %d is too long\n", i);
1703 break;
1704 case UnprintableArg:
1705 ErrorF("Command line argument number %d contains unprintable"
1706 " characters\n", i);
1707 break;
1708 case EnvTooLong:
1709 ErrorF("Environment variable `%s' is too long\n", e);
1710 break;
1711 case OutputIsPipe:
1712 ErrorF("Stdout and/or stderr is a pipe\n");
1713 break;
1714 case InternalError:
1715 ErrorF("Internal Error\n");
1716 break;
1717 default:
1718 ErrorF("Unknown error\n");
1719 break;
1720 }
1721 FatalError("X server aborted because of unsafe environment\n");
1722 }
1724 /*
1725 * CheckUserAuthorization: check if the user is allowed to start the
1726 * X server. This usually means some sort of PAM checking, and it is
1727 * usually only done for setuid servers (uid != euid).
1728 */
1730 #ifdef USE_PAM
1731 #include <security/pam_appl.h>
1732 #include <security/pam_misc.h>
1733 #include <pwd.h>
1734 #endif /* USE_PAM */
1736 void
1737 CheckUserAuthorization(void)
1738 {
1739 #ifdef USE_PAM
1740 static struct pam_conv conv = {
1741 misc_conv,
1742 NULL
1743 };
1745 pam_handle_t *pamh = NULL;
1746 struct passwd *pw;
1747 int retval;
1749 if (getuid() != geteuid()) {
1750 pw = getpwuid(getuid());
1751 if (pw == NULL)
1752 FatalError("getpwuid() failed for uid %d\n", getuid());
1754 retval = pam_start("xserver", pw->pw_name, &conv, &pamh);
1755 if (retval != PAM_SUCCESS)
1756 FatalError("pam_start() failed.\n"
1757 "\tMissing or mangled PAM config file or module?\n");
1759 retval = pam_authenticate(pamh, 0);
1760 if (retval != PAM_SUCCESS) {
1761 pam_end(pamh, retval);
1762 FatalError("PAM authentication failed, cannot start X server.\n"
1763 "\tPerhaps you do not have console ownership?\n");
1764 }
1766 retval = pam_acct_mgmt(pamh, 0);
1767 if (retval != PAM_SUCCESS) {
1768 pam_end(pamh, retval);
1769 FatalError("PAM authentication failed, cannot start X server.\n"
1770 "\tPerhaps you do not have console ownership?\n");
1771 }
1773 /* this is not a session, so do not do session management */
1774 pam_end(pamh, PAM_SUCCESS);
1775 }
1776 #endif
1777 }
1779 /*
1780 * Tokenize a string into a NULL terminated array of strings. Always returns
1781 * an allocated array unless an error occurs.
1782 */
1783 char**
1784 xstrtokenize(const char *str, const char *separators)
1785 {
1786 char **list, **nlist;
1787 char *tok, *tmp;
1788 unsigned num = 0, n;
1790 if (!str)
1791 return NULL;
1792 list = calloc(1, sizeof(*list));
1793 if (!list)
1794 return NULL;
1795 tmp = strdup(str);
1796 if (!tmp)
1797 goto error;
1798 for (tok = strtok(tmp, separators); tok; tok = strtok(NULL, separators)) {
1799 nlist = realloc(list, (num + 2) * sizeof(*list));
1800 if (!nlist)
1801 goto error;
1802 list = nlist;
1803 list[num] = strdup(tok);
1804 if (!list[num])
1805 goto error;
1806 list[++num] = NULL;
1807 }
1808 free(tmp);
1809 return list;
1811 error:
1812 free(tmp);
1813 for (n = 0; n < num; n++)
1814 free(list[n]);
1815 free(list);
1816 return NULL;
1817 }