remove more internal jpeg headers
[oweals/cde.git] / cde / programs / dtlogin / server.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /*                                                                      *
24  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
25  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
26  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
27  * (c) Copyright 1993, 1994 Novell, Inc.                                *
28  */
29 /*
30  * xdm - display manager daemon
31  *
32  * $XConsortium: server.c /main/4 1995/10/27 16:14:56 rswiston $
33  *
34  * Copyright 1988 Massachusetts Institute of Technology
35  *
36  * Permission to use, copy, modify, and distribute this software and its
37  * documentation for any purpose and without fee is hereby granted, provided
38  * that the above copyright notice appear in all copies and that both that
39  * copyright notice and this permission notice appear in supporting
40  * documentation, and that the name of M.I.T. not be used in advertising or
41  * publicity pertaining to distribution of the software without specific,
42  * written prior permission.  M.I.T. makes no representations about the
43  * suitability of this software for any purpose.  It is provided "as is"
44  * without express or implied warranty.
45  *
46  * Author:  Keith Packard, MIT X Consortium
47  */
48
49 # include       <sys/types.h>
50 # include       <sys/signal.h>
51 # include       <setjmp.h>
52 # include       <errno.h>
53 # include       <pwd.h>
54 # include       "dm.h"
55 # include       "vgmsg.h"
56
57 static receivedUsr1;
58
59
60
61 /***************************************************************************
62  *
63  *  Local procedure declarations
64  *
65  ***************************************************************************/
66
67 static const char * _SysErrorMsg( int n) ;
68 static SIGVAL CatchUsr1( int arg ) ;
69 static void   GetRemoteAddress( struct display *d, int fd) ;
70 static SIGVAL PingBlocked( int arg ) ;
71 static SIGVAL PingLost( int arg ) ;
72 static SIGVAL abortOpen( int arg ) ;
73 static int    serverPause( unsigned t, int serverPid) ;
74 static SIGVAL serverPauseAbort( int arg ) ;
75 static SIGVAL serverPauseUsr1( int arg ) ;
76
77
78
79
80
81 /***************************************************************************
82  *
83  *  Global variables
84  *
85  ***************************************************************************/
86
87 static Display  *dpy;
88
89
90
91 static SIGVAL
92 CatchUsr1( int arg )
93 {
94 #if defined(SYSV) || defined(SVR4)
95     (void) signal (SIGUSR1, CatchUsr1);
96 #endif
97     Debug ("Display Manager caught SIGUSR1\n");
98     ++receivedUsr1;
99 }
100
101 static const char * 
102 _SysErrorMsg( int n )
103 {
104
105   const char *s = strerror(n);
106
107     return (s ? s : "no such error");
108 }
109
110 int 
111 StartServerOnce( struct display *d )
112 {
113     char        **f;
114     char        **argv;
115     char        arg[1024];
116     int         pid;
117     char        **env;
118     
119     extern struct passwd   puser;       /* pseudo_user password entry   */
120
121     Debug ("Starting server for %s\n", d->name);
122     receivedUsr1 = 0;
123     signal (SIGUSR1, CatchUsr1);
124     argv = d->argv;
125     switch (pid = fork ()) {
126     case 0:
127         CleanUpChild ();
128         if (d->authFile) {
129             sprintf (arg, "-auth %s", d->authFile);
130             argv = parseArgs (argv, arg);
131         }
132         if (!argv) {
133             LogError(ReadCatalog(MC_LOG_SET,MC_LOG_NO_ARGS,MC_DEF_LOG_NO_ARGS));
134             exit(1);
135         }
136         Debug("Server invoked as ");
137         for (f = argv; *f; f++)
138             Debug ("'%s' ", *f);
139         Debug ("\n");
140
141         /*
142          *  set the permissions on  console devices to  pseudo-user.
143          *  run the server as a pseudo-user, not root...
144          */
145 #ifdef sun
146         if (solaris_setdevperm(d->gettyLine, puser.pw_uid, puser.pw_gid) == 0)
147              Debug ("Unable to set permissions on console devices ..\n");
148         else {
149 #endif
150              if(-1 == setgid (puser.pw_gid)) {
151                   Debug ("setgid() failed setting %d\n", puser.pw_gid);
152              }
153              if(-1 == setuid (puser.pw_uid)) {
154                   Debug ("setuid() failed setting %d\n", puser.pw_uid);
155              }
156 #ifdef sun
157         }
158 #endif
159
160         /*
161          *  build the server environment (if any)...
162          */
163         env = 0;
164         if (d->environStr && strlen(d->environStr) > 0)
165             env = parseEnv(env, d->environStr);
166 #ifdef sun
167         if (getEnv (env, "OPENWINHOME") == NULL) 
168             env = setEnv(env, "OPENWINHOME", "/usr/openwin");
169 #endif
170 #ifdef _AIX
171         if (getEnv (env, "ODMDIR") == NULL)
172             env = setEnv(env, "ODMDIR", "/etc/objrepos");
173 #ifdef _POWER
174         env = setEnv(env, "XTOEXEC", "true");           /* flag for xserverrc */
175 #endif
176 #endif
177
178         /*
179          * give the server SIGUSR1 ignored,
180          * it will notice that and send SIGUSR1
181          * when ready
182          */
183         signal (SIGUSR1, SIG_IGN);
184         (void) execve (argv[0], argv, env);
185         LogError(ReadCatalog(
186                 MC_LOG_SET,MC_LOG_NO_EXESRV,MC_DEF_LOG_NO_EXESRV),argv[0]);
187         exit(1);
188     case -1:
189         LogError(ReadCatalog(MC_LOG_SET,MC_LOG_FAIL_FORK,MC_DEF_LOG_FAIL_FORK));
190         return 0;
191     default:
192         break;
193     }
194     Debug ("Server started. Process ID = %d\n", pid);
195     d->serverPid = pid;
196     if (serverPause ((unsigned) d->openDelay, pid))
197         return FALSE;
198     return TRUE;
199 }
200
201
202 int 
203 StartServer( struct display *d )
204 {
205     int i;
206     int ret = FALSE;
207
208     i = 0;
209     while (d->serverAttempts == 0 || i < d->serverAttempts)
210     {
211         if ((ret = StartServerOnce (d)) == TRUE)
212             break;
213         sleep (d->openDelay);
214         i++;
215     }
216     return ret;
217 }
218
219
220 /*
221  * sleep for t seconds, return 1 if the server is dead when
222  * the sleep finishes, 0 else
223  */
224
225 static jmp_buf  pauseAbort;
226 static int      serverPauseRet;
227
228 static SIGVAL
229 serverPauseAbort( int arg )
230 {
231     Debug ("Display Manager pause timed out\n");
232     longjmp (pauseAbort, 1);
233 }
234
235 static SIGVAL
236 serverPauseUsr1( int arg )
237 {
238     Debug ("Display Manager pause received SIGUSR1\n");
239     ++receivedUsr1;
240     longjmp (pauseAbort, 1);
241 }
242
243 static int 
244 serverPause( unsigned t, int serverPid )
245 {
246     int         pid;
247
248     serverPauseRet = 0;
249     Debug ("Display Manager pausing until SIGUSR1 from server or timeout\n");
250     if (!setjmp (pauseAbort)) {
251         signal (SIGALRM, serverPauseAbort);
252         signal (SIGUSR1, serverPauseUsr1);
253 #ifdef SYSV
254         if (receivedUsr1)
255             alarm ((unsigned) 1);
256         else
257             alarm (t);
258 #else
259         if (!receivedUsr1)
260             alarm (t);
261         else
262             Debug ("ServerPause(): already received USR1\n");
263 #endif
264         for (;;) {
265 #ifdef SYSV
266             pid = wait ((waitType *) 0);
267 #else
268             if (!receivedUsr1)
269                 pid = wait ((waitType *) 0);
270             else
271 #  ifdef        SVR4
272                 {
273                     int dummy;
274                 pid = waitpid ((pid_t) 0,&dummy,WNOHANG);
275                 }
276 #  else
277                 pid = wait3 ((waitType *) 0, WNOHANG,
278                              (struct rusage *) 0);
279 #  endif
280 #endif
281             if (pid == serverPid ||
282                 pid == -1 && errno == ECHILD)
283             {
284                 Debug ("Server dead\n");
285                 serverPauseRet = 1;
286                 break;
287             }
288 #ifndef SYSV
289             if (pid == 0) {
290                 Debug ("Server alive and kicking\n");
291                 break;
292             }
293 #endif
294         }
295     }
296     alarm ((unsigned) 0);
297     signal (SIGALRM, SIG_DFL);
298     signal (SIGUSR1, CatchUsr1);
299     if (serverPauseRet) {
300         Debug ("Server died\n");
301         LogError(ReadCatalog(MC_LOG_SET,MC_LOG_SRV_DIED,MC_DEF_LOG_SRV_DIED));
302     }
303     return serverPauseRet;
304 }
305
306
307 /*
308  * this code is complicated by some TCP failings.  On
309  * many systems, the connect will occasionally hang forever,
310  * this trouble is avoided by setting up a timeout to longjmp
311  * out of the connect (possibly leaving piles of garbage around
312  * inside Xlib) and give up, terminating the server.
313  */
314
315 static jmp_buf  openAbort;
316
317 static SIGVAL
318 abortOpen( int arg )
319 {
320         longjmp (openAbort, 1);
321 }
322
323 static void
324 GetRemoteAddress( struct display *d, int fd )
325 {
326     char    buf[512];
327     int     len = sizeof (buf);
328
329     if (d->peer)
330         free ((char *) d->peer);
331     getpeername (fd, (struct sockaddr *) buf, &len);
332     d->peerlen = 0;
333     if (len)
334     {
335         d->peer = (struct sockaddr *) malloc (len);
336         if (d->peer)
337         {
338             bcopy (buf, (char *) d->peer, len);
339             d->peerlen = len;
340         }
341     }
342     Debug ("Got remote address %s %d\n", d->name, d->peerlen);
343 }
344
345
346
347 /****************************************************************************
348  *
349  *  LogOpenError()
350  *
351  *  If d->startAttempts is a large number and a connection cannot be made to
352  *  the server, the error log can fill up rapidly with error messages. This
353  *  could be common in X-terminals that do not support XDMCP and are turned
354  *  off over a weekend. This routine attempts to reduce the number of error
355  *  messages logged in this scenario.
356  *  
357  ****************************************************************************/
358
359 int 
360 LogOpenError( int count )
361 {
362
363     if ( count <= 10                        ) return 1;
364     if ( count <= 100 && (count %  10 == 0) ) return 1;
365     if ( count <= 500 && (count %  50 == 0) ) return 1;
366     if (                 (count % 100 == 0) ) return 1;
367     
368     return 0;
369 }
370
371
372 int 
373 WaitForServer( struct display *d )
374 {
375     int     i;
376
377     for (i = 0; i < (d->openRepeat > 0 ? d->openRepeat : 1); i++) {
378         (void) signal (SIGALRM, abortOpen);
379         (void) alarm ((unsigned) d->openTimeout);
380         if (!setjmp (openAbort)) {
381             Debug ("Before XOpenDisplay(%s)\n", d->name);
382             errno = 0;
383             dpy = XOpenDisplay (d->name);
384             (void) alarm ((unsigned) 0);
385             (void) signal (SIGALRM, SIG_DFL);
386             Debug ("After XOpenDisplay()\n");
387             if (dpy) {
388                 if (d->displayType.location == Foreign)
389                     GetRemoteAddress (d, ConnectionNumber (dpy));
390                 RegisterCloseOnFork (ConnectionNumber (dpy));
391                 (void) fcntl (ConnectionNumber (dpy), F_SETFD, 0);
392                 return 1;
393             } else {
394                 Debug ("OpenDisplay failed %d (%s)\n",
395                        errno, _SysErrorMsg (errno));
396             }
397             Debug ("Waiting for server to start %d\n", i);
398             sleep ((unsigned) d->openDelay);
399         } else {
400             Debug ("Hung in open, aborting\n");
401             if (LogOpenError(d->startTries))
402                 LogError(ReadCatalog(
403                         MC_LOG_SET,MC_LOG_HUNG_DPY,MC_DEF_LOG_HUNG_DPY),
404                            d->name, d->startTries);
405             (void) signal (SIGALRM, SIG_DFL);
406             break;
407         }
408     }
409     Debug ("Giving up on server\n");
410     if (LogOpenError(d->startTries))
411         LogError(ReadCatalog(
412                 MC_LOG_SET,MC_LOG_FAIL_SRVOPEN,MC_DEF_LOG_FAIL_SRVOPEN),
413                 d->startTries, d->name);
414     return 0;
415 }
416
417 void
418 ResetServer( struct display *d )
419 {
420     if (dpy && d->displayType.origin != FromXDMCP)
421         pseudoReset (dpy);
422 }
423
424
425 /****************************************************************************
426  *
427  *  Server pinging routines...
428  *
429  *  These routines attempt to determine if the server is still alive.
430  *  Periodically (d->pingInterval) an XSync is sent to the server. If an I/O
431  *  error occurs, then the connection has been lost and the server needs to
432  *  be reset. If the server is blocked for some reason (i.e. server grab) the
433  *  XSync will block until a local timer expires. In this case, we just note
434  *  the block and continue...
435  *
436  *  7/26/90 - prr
437  *  The XSync was replaced by a socket-level ping. For some reason, an XSync
438  *  to a grabbed server causes a subsequent pseudoReset (KillClients) to not 
439  *  kill all clients. The socket ping is not affected by a grabbed server,
440  *  but it cannot detect a server shutdown and restart within one ping
441  *  interval. 
442  *
443  ****************************************************************************/
444
445 static jmp_buf  pingTime;
446 static int      serverDead = FALSE;
447
448 static SIGVAL
449 PingLost( int arg )
450 {
451     serverDead = TRUE;
452     longjmp (pingTime, 1);
453 }
454
455
456 static SIGVAL
457 PingBlocked( int arg )
458 {
459     serverDead = FALSE;
460     longjmp (pingTime, 1);
461 }
462
463
464 int 
465 PingServer( struct display *d, Display *alternateDpy )
466 {
467     int     (*oldError)();
468     SIGVAL  (*oldSig)();
469     int     oldAlarm;
470
471     if (!alternateDpy)
472         alternateDpy = dpy;
473     oldError = XSetIOErrorHandler ((XIOErrorHandler)PingLost);
474     oldAlarm = alarm (0);
475     oldSig = signal (SIGALRM, PingBlocked);
476     alarm (d->pingTimeout * 60);
477     if (!setjmp (pingTime))
478     {
479         Debug ("Ping server\n");
480         XNoOp (alternateDpy);
481         XSync (alternateDpy, 0);
482         Debug ("Server alive\n");
483
484         while (XPending(alternateDpy)) {
485             XEvent event;
486             XNextEvent(alternateDpy, &event);
487         }
488     }
489     else
490     {
491         if ( serverDead ) {
492             Debug ("Server dead\n");
493             alarm (0);
494             signal (SIGALRM, SIG_DFL);
495             XSetIOErrorHandler (oldError);
496             return 0;
497         }
498         else
499             Debug ("Server blocked, continuing...\n");
500     }
501     alarm (0);
502     signal (SIGALRM, oldSig);
503     alarm (oldAlarm);
504     XSetIOErrorHandler (oldError);
505     return 1;
506 }