Merge branch 'master' of https://git.code.sf.net/p/cdesktopenv/code
[oweals/cde.git] / cde / programs / dtsession / SmMain.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 librararies 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 /* $TOG: SmMain.c /main/18 1998/04/20 12:59:26 mgreess $ */
24 /*                                                                      *
25  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
26  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
27  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
28  * (c) Copyright 1993, 1994 Novell, Inc.                                *
29  */
30 /*************************************<+>*************************************
31  *****************************************************************************
32  **
33  **  File:        SmMain.c
34  **
35  **  Project:     HP DT Session Manager (dtsession)
36  **
37  **  Description:
38  **  -----------
39  **  This is the controlling program for the session manager.  It
40  **  calls routines to start the BMS, initialize globals and handlers,
41  **  and restore the correct session.
42  **
43  **
44  *******************************************************************
45  **  (c) Copyright Hewlett-Packard Company, 1990.  All rights are
46  **  reserved.  Copying or other reproduction of this program
47  **  except for archival purposes is prohibited without prior
48  **  written consent of Hewlett-Packard Company.
49  ********************************************************************
50  **
51  **
52  **
53  *****************************************************************************
54  *************************************<+>*************************************/
55
56 #include <stdio.h>
57 #include <locale.h>
58 #ifdef __osf__
59 #include <sys/access.h>
60 #endif
61 #include <X11/Intrinsic.h>
62 #include <X11/StringDefs.h>
63
64 #if defined (USE_X11SSEXT)
65 #include <X11/extensions/scrnsaver.h>
66 #endif /* USE_X11SSEXT */
67
68 #include <Xm/Xm.h>
69 #include <Dt/UserMsg.h>
70 #include <Dt/EnvControlP.h>
71 #include <Dt/DtP.h>
72 #include "Sm.h"
73 #include "SmError.h"
74 #include "SmGlobals.h"
75 #include "SmCommun.h"
76 #include "SmRestore.h"
77 #include "SmUI.h"
78 #include "SrvPalette.h"
79 #include "SmProtocol.h"
80 #include "SmXSMP.h"
81
82 /*
83  * Internal Functions
84  */
85 static void StopAll(int i);
86 static int RegisterX11ScreenSaver(Display *display, int *ssEventType);
87
88 /*
89  * Internal Defines
90  */
91 #ifdef __hpux
92 #define SECURE_SYS_PATH "/.secure/etc/passwd"
93 #endif
94 #ifdef _AIX
95 #define SECURE_SYS_PATH "/etc/security/passwd"
96 #endif
97 #ifdef SVR4
98 #define SECURE_SYS_PATH "/etc/shadow"
99 #endif
100
101
102 \f
103 /*************************************<->*************************************
104  *
105  *  main (argc, argv)
106  *
107  *
108  *  Description:
109  *  -----------
110  *  Controls the startup and event dispatching of the session manager.
111  *
112  *
113  *  Inputs:
114  *  ------
115  *  argc = command line options
116  *  argv = number of command line options
117  *
118  *
119  *  Outputs:
120  *  -------
121  *
122  *
123  *  Comments:
124  *  --------
125  *
126  *************************************<->***********************************/
127 int
128 main (int argc, char **argv)
129 {
130     int                         n, tmp;
131     Arg                         args[10];
132     XEvent                      next;
133     String                      tmpString;
134     XWindowAttributes           windAtt;
135     XPropertyEvent              *pEvent = (XPropertyEvent *) &next;
136     int                         status;
137     struct stat                 buf;
138     Display                     *srvDisplay;
139     struct sigaction            stopvec;
140     char                        *lang;
141
142 #ifdef __osf__
143
144 # include <sys/sysinfo.h>
145 # include <sys/proc.h>
146
147     unsigned long        op;
148     int                  buffer[2];
149     unsigned long        nbytes = 1;
150     char*                arg = 0;
151     unsigned long        flag = 0;
152
153     int                  ssi_status;
154
155     op = SSI_NVPAIRS;
156
157     buffer[0] = SSIN_UACPROC;
158     buffer[1] =  UAC_NOPRINT;
159 # ifdef DEBUG_UAC
160     buffer[1] |= UAC_SIGBUS;
161 # endif
162
163     ssi_status = setsysinfo ( op, buffer, nbytes, arg, flag );
164 #endif
165
166     setlocale( LC_ALL, "" );
167     XtSetLanguageProc( NULL, NULL, NULL );
168
169     smGD.smState = IN_PROCESS;
170     smGD.programName = strdup (argv[0]);
171
172     /* JET - By default, we always want to leave when SmExit() is called. */
173     smGD.ExitComplete = True;
174
175     /*
176      * We report some errors before we call the DtInitialize procedure.
177      * The Dt initialize procedure sets this name.  If we report
178      * an error via DtSimple error before this is set we see the message
179      * prepended with <unknown program name> in the error log.
180      */
181     DtProgName = SM_RESOURCE_NAME ;
182     
183 #ifdef DEBUG
184     if(argc > 5)
185     {
186         int junk = 1;
187         while(junk)
188         {
189            junk = 1;
190         }
191     }
192 #endif /*  DEBUG */
193     /*
194      * Set our effective gid to the real gid until we need it to be
195      * sys (during contention management)
196      */
197     smGD.runningGID = getgid();
198     smGD.conMgmtGID = getegid();
199
200     /*
201      * Set uid up according to whether this is a secure system
202      * Secure systems need root priviledges to read the /etc/passwd file
203      */
204     smGD.runningUID = getuid();
205
206 #ifdef linux                    /* linux always needs to be setup as secure */
207
208     /*
209      * Save the root priviledge to be restored when trying to unlock
210      */
211     smGD.unLockUID = geteuid();
212     smGD.secureSystem = True;
213     SM_SETEUID(smGD.runningUID);
214     
215 #else
216
217 # ifdef SECURE_SYS_PATH
218     status = stat(SECURE_SYS_PATH, &buf);
219 # else
220     status = -1;
221 # endif
222
223     if(status == -1)
224     {
225         /*
226          * this is not a secure system - remove all suid priviledges
227          */
228         smGD.unLockUID = smGD.runningUID;
229         smGD.secureSystem = False;
230         SM_SETESUID(smGD.runningUID);
231     }
232     else
233     {
234        /*
235         * Save the root priviledge to be restored when trying to unlock
236         */
237         smGD.unLockUID = geteuid();
238         smGD.secureSystem = True;
239         SM_SETEUID(smGD.runningUID);
240     }
241
242 #endif /* linux */
243
244     /*
245      * Initialize LANG if it isn't defined.
246      */
247     if ((lang = getenv ("LANG")) == NULL)
248     {
249         lang = XtMalloc (7);
250         (void) strcpy (lang, "LANG=C");
251         (void) putenv (lang);
252     }
253
254 #ifdef __hpux
255     setresgid(-1, smGD.runningGID, -1);
256 #else  /* _AIX or any other system */
257 #ifndef SVR4
258     setregid(smGD.conMgmtGID, smGD.runningGID);
259 #else
260     setgid(smGD.conMgmtGID);
261     setegid(smGD.runningGID);
262 #endif
263 #endif /* !hpux */
264
265    /*
266     * Set up POSIX sigaction structs
267     */
268
269     /*
270      * Must set SIGPIPE to SIG_IGN so the process does not exit
271      * if a child terminates unexpectedly during an I/O operation
272      * that raises SIGPIPE.  Note that before this process exec's
273      * any subprocesses, SIGPIPE must be set to SIG_DFL.
274      */
275     sigemptyset(&stopvec.sa_mask);
276     stopvec.sa_flags = 0;
277     stopvec.sa_handler = SIG_IGN;
278     (void) sigaction(SIGPIPE, &stopvec, (struct sigaction *) NULL);
279
280     stopvec.sa_handler = StopAll;
281     sigemptyset(&stopvec.sa_mask);
282     stopvec.sa_flags = 0;
283  
284     smGD.childvec.sa_handler = WaitChildDeath;
285     sigemptyset(&smGD.childvec.sa_mask);
286     smGD.childvec.sa_flags = 0;
287
288     smGD.defvec.sa_handler = SIG_DFL;
289     sigemptyset(&smGD.defvec.sa_mask);
290     smGD.defvec.sa_flags = 0;
291
292     smGD.appCon = 0;
293     smGD.display = 0;
294
295     /*
296      * This must be done before XtToolkitInitialize
297      * to set up the local environment
298      */
299     _DtEnvControl(DT_ENV_SET);
300     _DtEnvControl(DT_ENV_SET_BIN);
301
302     /*
303      * Set up NLS error messages first
304      */
305     InitNlsStrings();
306
307     /*
308      * Set the paths of where resources are to be restored from
309      */
310     SetRestorePath(argc, argv);
311
312     /*
313      * The first thing that must happen is that resources must be restored
314      * so that my resources will be correct
315      */
316     if(smGD.compatMode == False)
317     {
318      /*
319       * Load session resources.
320       */
321       RestoreResources(False,
322                        "-load",
323                        "-system",
324                        "-xdefaults",
325                        smGD.resourcePath[0] != '\0' ? "-file" : NULL,
326                        smGD.resourcePath,
327                        NULL);
328     }
329
330     /*
331      * Set up to catch SIGTERM
332      */
333     stopvec.sa_handler = StopAll;
334     sigemptyset(&stopvec.sa_mask);
335     stopvec.sa_flags = 0;
336
337     sigaction(SIGTERM, &stopvec, (struct sigaction *) NULL);
338
339     /*
340      * Now set up a communication with the toolkit
341      *
342      * Create one display connection for dtsession, and one for
343      * the color server. We cannot share a display connection since
344      * motif creates a display object for the color server's display during
345      * color server initialization. Since the color server is not yet 
346      * operational, any dialogs (ie the dtsession logout confirmation
347      * dialogs) created on that display do not get the color server colors. 
348      * The dtsession display object is created after color server
349      * initialization is complete.
350      */
351     if (smGD.appCon == 0) {
352         /*
353          * The following code will have been initialized if the
354          * session creation code posted a dialog.
355          */
356         XtToolkitInitialize();
357         smGD.appCon = XtCreateApplicationContext();
358         smGD.display = XtOpenDisplay(smGD.appCon, NULL, argv[0], 
359                                 SM_RESOURCE_CLASS,
360                                 NULL, 0, &argc, argv);
361     }
362
363     srvDisplay = XtOpenDisplay(smGD.appCon, NULL, argv[0], SM_RESOURCE_CLASS,
364                                  NULL, 0, &argc, argv);
365
366     /*
367      * Initialize XSMP 
368      */
369     if (!InitXSMP (argv[0]))
370         SM_EXIT(-1);
371
372     /* Added the following check to exit in case of error RK 09.08.93 */
373     if(smGD.display == NULL)
374     {
375         PrintError(DtError, GETMESSAGE(4, 1, "Invalid display name - exiting."));
376         SM_EXIT(-1);
377     }
378
379     /*
380      * Lock out other session managers from running - if there is one
381      * running already - exit
382      */
383     if(!_DtGetLock(smGD.display, SM_RUNNING_LOCK))
384     {
385         PrintError(DtError, GETMESSAGE(2, 2, "Another dtsession is currently running - exiting."));
386         SM_EXIT(-1);
387     }
388
389    /*
390     * Restore preferences
391     */
392     if (smGD.resourcePath[0] != '\0')
393     {
394       RestorePreferences(smGD.resourcePath);
395     }
396
397     /*
398      * Start up the color server
399      */
400     InitializeDtcolor(srvDisplay, smGD.sessionType);
401
402     /*
403      * AFTER the colors are set up - create the top level widget
404      * Set up a NULL WM_COMMAND property
405      */
406     n = 0;
407     XtSetArg(args[n], XmNbackground,
408              XBlackPixel(smGD.display, XDefaultScreen(smGD.display))); n++;
409     XtSetArg(args[n], XmNmappedWhenManaged, False); n++;
410     XtSetArg (args[n], XmNwidth, 1); n++;
411     XtSetArg (args[n], XmNheight, 1); n++;
412     smGD.topLevelWid = XtAppCreateShell (SM_RESOURCE_NAME, SM_RESOURCE_CLASS,
413                                          applicationShellWidgetClass,
414                                          smGD.display, args, n);
415     XtRealizeWidget(smGD.topLevelWid);
416
417     /*
418      * Select to get the lock on timeout if the user requests it
419      * and if the server supports it. This must be done before
420      * InitSMGlobals() so smGD.lockOnTimeoutStatus is known.
421      */
422 #if defined (USE_HPSSEXT)
423 #ifdef USE_HP_SPECIFIC_XLIB
424     tmp = XHPSSChangeNotify(smGD.display, &XaSmScreenSaveRet, 3);
425 #else /* USE_HP_SPECIFIC_XLIB */
426     tmp = -1;
427 #endif /* USE_HP_SPECIFIC_XLIB */
428 #elif defined (USE_X11SSEXT)
429     tmp = RegisterX11ScreenSaver(smGD.display, &smGD.ssEventType);
430 #else
431     tmp = -1;
432 #endif
433
434     if(tmp != 0)
435     {
436         smGD.lockOnTimeoutStatus = False;
437         XaSmScreenSaveRet = None;
438 #if defined (USE_X11SSEXT)
439         smGD.ssEventType = None;
440 #endif
441     }
442     else
443     {
444         smGD.lockOnTimeoutStatus = True;
445     }
446
447     InitSMGlobals();
448
449     /*
450      * Put the program into a wait state
451      */
452     ShowWaitState(True);
453
454     InitErrorHandler();
455
456     /*
457      * Restore resources for lang/resolution independence
458      */
459     if((smGD.resourcePath[0] != 0) || (smGD.compatMode == False))
460     {
461         RestoreIndependentResources();
462     }
463
464     /*
465      * Now restore the rest of the clients and the settings
466      */
467     if((smGD.clientPath[0] != 0) && (smGD.compatMode == False))
468     {
469         if(RestoreState() == -1)
470         {
471             StartWM();
472         }
473     }
474     else
475     {
476         if(smGD.compatMode == True)
477         {
478             /*
479              * dtstyle needs the DT_SESSION_STATE  even in
480              * compatibility mode
481              */
482             SetCompatState();
483         }
484         StartWM();
485     }
486
487     /* 
488      * Run the user's startup script if there is one
489      */
490
491     if(smGD.compatMode == False)
492     {
493         StartEtc(False); /* run sessionetc */
494     }
495
496     InitProtocol ();
497
498     /*
499      * If we are in compatibility mode - kill the parent and leave the
500      * child running so that the script exits
501      */
502     if(smGD.compatMode == True)
503     {
504         KillParent();
505     }
506
507     /*
508      * Select for property notify on the top level window - so that
509      * when the style manager changes something - it is known
510      */
511     XGetWindowAttributes(smGD.display, smGD.topLevelWindow, &windAtt);
512     XSelectInput(smGD.display, smGD.topLevelWindow,
513                  windAtt.your_event_mask | PropertyChangeMask);
514
515     ShowWaitState(False);
516
517     /*
518      * Register for events
519      * - PropertyChange (maskable)
520      * - ClientMessage (non-maskable)
521      */
522     XtAddEventHandler(smGD.topLevelWid,
523                       PropertyChangeMask,
524                       True, ProcessEvent, NULL);
525
526     smGD.smState = READY;
527
528 #ifdef __osf__
529     /* If we've just populated a new .dtprofile into the user's home
530      * directory, put up a popup dialog explaining the need to edit it
531      * to allow .login/.profile to work properly
532      */
533
534     arg = getenv("DTNEWPROFILE");
535     if (arg)
536         WarnNewProfile();
537 #endif
538
539     while(1)
540     {
541       XtAppNextEvent(smGD.appCon, &next);
542       if (next.type != 0)
543       {
544 #if defined (USE_X11SSEXT)
545         if (next.type == smGD.ssEventType)
546         {
547          /*
548           * We should simply be calling XtDispatchEvent() but the toolkit
549           * doesn't seem to know how to dispatch a run-time generated
550           * event type.
551           */
552           ProcessEvent(smGD.topLevelWid, NULL, &next, NULL);
553         }
554         else
555         {
556           XtDispatchEvent(&next);
557         }
558 #else
559         XtDispatchEvent(&next);
560 #endif
561       }
562     }
563 }
564
565
566
567 \f
568 /*************************************<->*************************************
569  *
570  *  StopAll
571  *
572  *
573  *  Description:
574  *  -----------
575  *  Signal handler for SIGTERM. Causes dtsession to do a normal shutdown
576  *  procedure without saving any state.
577  *
578  *
579  *  Inputs:
580  *  ------
581  *  shutDown (state flag)
582  *
583  *
584  *  Outputs:
585  *  -------
586  *
587  *
588  *  Comments:
589  *  --------
590  *
591  *  We want to be careful to ignore the TERM signal if we are already
592  *  shutting down when it occurs.
593  *
594  *************************************<->***********************************/
595
596 static void
597 StopAll(int i)
598 {
599     ImmediateExit(-1, 0, True);
600 }
601
602 /*************************************<->*************************************
603  *
604  *  RegisterX11ScreenSaver
605  *
606  *
607  *  Description:
608  *  -----------
609  *  Register with X11 screen saver server extension for screen saver events. 
610  *
611  *  Inputs:
612  *  ------
613  *  display - display from XtOpenDisplay()
614  *  pssEventType - pointer to buffer in which to return ss event type
615  *
616  *  Outputs:
617  *  -------
618  *  pssEventType - (rc=0) screen saver event type, (rc!=0) undefined
619  *
620  *  Returns:
621  *  -------
622  *  0 - successfully registered for screen saver events
623  *  other - failed to register for screen saver events
624  *
625  *  Comments:
626  *  --------
627  *
628  *************************************<->***********************************/
629
630 #if defined (USE_X11SSEXT)
631 static int
632 RegisterX11ScreenSaver(
633   Display *display,
634   int *pssEventType)
635 {
636  /*
637   * Register with X11 screen saver server extension.
638   */
639   int result = -1;
640   int ssErrorBase;
641   int majorVersion;
642   int minorVersion;
643   int screen;
644   Window root;
645   XID xid;
646   XSetWindowAttributes attr;
647   Atom type;
648
649   if (XScreenSaverQueryExtension(display, pssEventType, &ssErrorBase) &&
650       XScreenSaverQueryVersion(display, &majorVersion, &minorVersion) &&
651       majorVersion == 1)
652   {
653    /*
654     * Server supports requested version of X11 screen saver extension.
655     */
656     screen = DefaultScreen(display);
657     root = DefaultRootWindow(display);
658    
659     XGrabServer(display);
660     if (!XScreenSaverGetRegistered(display, screen, &xid, &type))
661     {
662      /* 
663       * No other clients registered with this server so register this one.
664       */
665       XScreenSaverRegister(display, screen, XtWindow(smGD.topLevelWid), XA_WINDOW);
666       result = 0;
667     }
668     XUngrabServer(display);
669
670     if (result == 0)
671     {
672      /* 
673       * Registration successful.
674       */
675       XScreenSaverSelectInput(display, root, 
676                               ScreenSaverNotifyMask|ScreenSaverCycleMask);
677       XScreenSaverSetAttributes(display, root, 0, 0, 1, 1, 0, CopyFromParent,
678                           CopyFromParent, CopyFromParent, CWBackPixel, &attr);
679     }
680   }
681   return(result);   
682 }
683 #endif /* USE_X11SSEXT */
684