Convert uses of XKeycodeToKeysym (deprecated) to XkbKeycodeToKeysym
[oweals/cde.git] / cde / programs / dtaction / Main.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 /* $TOG: Main.c /main/18 1998/07/23 17:56:36 mgreess $ */
24 /*****************************************************************************
25  *****************************************************************************
26  **
27  **   File:         Main.c
28  **
29  **   Project:      DT
30  **
31  **   Description:  This file contains the main program for dtaction.
32  **               
33  **
34  **(c) Copyright 1993, 1994 Hewlett-Packard Company
35  **(c) Copyright 1993, 1994 International Business Machines Corp.
36  **(c) Copyright 1993, 1994 Sun Microsystems, Inc.
37  **(c) Copyright 1993, 1994 Unix System Labs, Inc., a subsidiary of Novell, Inc.
38  **
39  **
40  ****************************************************************************
41  ************************************<+>*************************************/
42
43 #include <stdlib.h>
44 #include <limits.h>
45 #include <stddef.h>
46 #include <unistd.h>
47 #include <nl_types.h>
48 #include <signal.h>
49 #include <locale.h>
50 #include <sys/param.h>          /* for MAXPATHLEN and MAXHOSTNAMELEN */
51
52 #if defined(sun) || defined(__linux__)
53 #include <crypt.h>
54 #include <shadow.h>
55 #endif
56
57 #include <errno.h>
58 #include <grp.h>
59 #include <pwd.h>
60
61 #include <X11/Intrinsic.h>
62 #include <Xm/XmP.h>
63 #include <Xm/Text.h>
64 #include <Xm/TextF.h>
65 #include <Xm/SelectioB.h>
66 #include <Xm/MessageB.h>
67 #include <Xm/Protocols.h>
68 #include <Xm/MwmUtil.h>
69
70 #include <Dt/Dt.h>
71 #include <Dt/DbUtil.h>
72 #include <Dt/CmdInv.h>
73 #include <Dt/Action.h>
74 #include <Dt/EnvControlP.h>
75
76
77 /******************************************************************************/
78
79 #include <time.h>
80
81
82 /* Command line options */
83 XrmOptionDescRec option_list[] =
84 {
85    {  "-user",     "user",          XrmoptionSepArg,   NULL},
86    {  "-contextDir", "contextDir",  XrmoptionSepArg,   NULL},
87    {  "-execHost", "execHost",      XrmoptionSepArg,   NULL},
88    {  "-termOpts", "termOpts",      XrmoptionSepArg,   NULL},
89 };
90
91 typedef struct {
92    char * user;
93    char * contextDir;
94    char * execHost;
95    char * termOpts;
96 } ApplArgs, *ApplArgsPtr;
97
98 #define LOGIN_STR_LEN 15
99 #define STAR ' '
100
101 Widget dlog;
102 char *password;
103 char *stars;
104 int  passwordLength = 0;
105
106 Boolean finished = False;
107 Boolean rootRequest = False;
108 char * toPword = NULL;
109 char * rootPword = NULL;
110 char * origName = "Unknown";
111 int basegid = -1;
112 int newuid = -1;
113
114 /* Dtaction resources */
115 XtResource resources[] =
116 {
117    {
118     "user", "User", XmRString, sizeof(char *),
119     XtOffsetOf(ApplArgs, user), XmRImmediate, (XtPointer) NULL,
120    },
121    {
122     "contextDir", "ContextDir", XmRString, sizeof(char *),
123     XtOffsetOf(ApplArgs, contextDir), XmRImmediate, (XtPointer) NULL,
124    },
125    {
126     "execHost", "ExecHost", XmRString, sizeof(char *),
127     XtOffsetOf(ApplArgs, execHost), XmRImmediate, (XtPointer) NULL,
128    },
129    {
130     "termOpts", "TermParms", XmRString, sizeof(char *),
131     XtOffsetOf(ApplArgs, termOpts), XmRImmediate, (XtPointer) NULL,
132    },
133 };
134
135  /*
136  * macro to get message catalog strings
137  */
138
139 #ifndef NO_MESSAGE_CATALOG
140 # define _CLIENT_CAT_NAME "dtact"
141 extern char *_DtGetMessage(char *filename, int set, int n, char *s);
142 # define GETMESSAGE(set, number, string)\
143     (_DtGetMessage(_CLIENT_CAT_NAME, set, number, string))
144 #else
145 # define GETMESSAGE(set, number, string)\
146     string
147 #endif
148
149 Boolean _DtWmStringsAreEqual( 
150                         char *in_str,
151                         char *test_str) ;
152 void CheckForDone( 
153                         XtPointer clientData,
154                         XtIntervalId id) ;
155 void CheckUserRequest( void ) ;
156 void CheckPasswd( void ) ;
157 void AddSuLog( 
158                         char *FromName,
159                         char *ToName,
160                         char *ChangeType) ;
161 void CleanPath( 
162                         char *Path) ;
163 void OkCallback( 
164                         Widget w,
165                         XtPointer clientData,
166                         XtPointer callData) ;
167 void ErrOkCallback( 
168                         Widget w,
169                         XtPointer clientData,
170                         XtPointer callData) ;
171 void CancelCallback( 
172                         Widget w,
173                         XtPointer clientData,
174                         XtPointer callData) ;
175 void MapCallback( 
176                         Widget w,
177                         XtPointer clientData,
178                         XtPointer callData) ;
179
180 void actionStatusCallback (
181                         DtActionInvocationID id,
182                         XtPointer   client_data,
183                         DtActionArg *aap,
184                         int         aac,
185                         DtActionStatus status );
186
187 void GetUserPrompt( void ) ;
188 void LogSuccess( void ) ;
189 void LogFailure( void ) ;
190 void MyInsert( 
191                         Widget w,
192                         XEvent *event,
193                         char **params,
194                         Cardinal *num_params) ;
195 void MyCancel( 
196                         Widget w,
197                         XEvent *event,
198                         char **params,
199                         Cardinal *num_params) ;
200 void EditPasswdCB( 
201                         Widget w,
202                         XtPointer client,
203                         XtPointer call) ;
204 void UnknownUser( void ) ;
205 void UnknownUserCallback( 
206                         Widget w,
207                         XtPointer clientData,
208                         XtPointer callData) ;
209
210
211 /********    End Forward Function Declarations    ********/
212
213
214 /***************************************************************************
215  *
216  *  Text widget actions and translations
217  *
218  ***************************************************************************/
219
220 XtActionsRec textActions[] = {
221         {"my-insert", (XtActionProc)MyInsert},
222         {"my-cancel", (XtActionProc)MyCancel},
223 };
224
225 char textEventBindings[] = {
226 "Shift <Key>Tab:                        prev-tab-group() \n\
227   Ctrl <Key>Tab:                        next-tab-group() \n\
228  <Key>Tab:                              next-tab-group() \n\
229  <Key>osfEndLine:                       end-of-line() \n\
230  <Key>osfBeginLine:                     beginning-of-line() \n\
231  ~Shift <Key>osfRight:                  forward-character()\n\
232  ~Shift <Key>osfLeft:                   backward-character()\n\
233   Ctrl <Key>osfDelete:                  delete-to-end-of-line()\n\
234  <Key>osfDelete:                        delete-next-character()\n\
235   <Key>osfBackSpace:                    delete-previous-character()\n\
236  <Key>osfActivate:                      activate()\n\
237   Ctrl <Key>Return:                     activate()\n\
238  <Key>Return:                           activate()\n\
239  <Key>osfCancel:                        my-cancel()\n\
240  <Key>:                                 my-insert()\n\
241  ~Ctrl ~Shift ~Meta ~Alt<Btn1Down>:     grab-focus() \n\
242  <EnterWindow>:                         enter()\n\
243  <LeaveWindow>:                         leave()\n\
244  <FocusIn>:                             focusIn()\n\
245  <FocusOut>:                            focusOut()\n\
246  <Unmap>:                               unmap()"
247 };
248
249
250 /****************************************************************************/
251 /****************************************************************************/
252
253 static Widget toplevel;
254 static ApplArgs appArgs;
255 static XtAppContext appContext;
256 static DtActionInvocationID actionId;
257 static Boolean exitAfterInvoked = False; 
258 static int exitStatus = 0;
259
260 /* ARGSUSED */
261 void
262 CheckForDone(
263    XtPointer clientData,
264    XtIntervalId id)
265 {
266     if ( toplevel->core.num_popups ==  0 ) 
267         exit(exitStatus);
268
269     XtAppAddTimeOut(appContext,
270         10, (XtTimerCallbackProc)CheckForDone,
271       NULL);
272 }
273
274
275 int
276 main( 
277      int argc,
278      char **argv ) 
279 {
280     Display *display;
281     Arg args[20];
282     int n=0;
283     char *actionName;
284     int numArgs = 0;
285     DtActionArg *ap = NULL;
286   
287     XtSetLanguageProc(NULL, NULL, NULL);
288     _DtEnvControl(DT_ENV_SET);
289     (void) signal(SIGCHLD, (void (*)())SIG_IGN);
290
291     /*  Initialize the toolkit and open the display  */
292     XtToolkitInitialize() ;
293     appContext = XtCreateApplicationContext() ;
294     if ( !(display = XtOpenDisplay( appContext, NULL, argv[0], "Dtaction", 
295                              option_list, 
296                              sizeof(option_list)/sizeof(XrmOptionDescRec),
297                              &argc, argv)) )
298     {
299         setlocale(LC_ALL, "");
300         fprintf(stderr, "%s", GETMESSAGE(1,11,"Can't open display.\n"));
301         exit(-1);
302     }
303   
304     XtSetArg(args[n], XmNallowShellResize, True); n++;
305     XtSetArg(args[n], XmNmappedWhenManaged, False); n++;
306     XtSetArg(args[n], XmNheight, 1); n++;
307     XtSetArg(args[n], XmNwidth, 1); n++;
308     toplevel = XtAppCreateShell( argv[0], "Dtaction", 
309             topLevelShellWidgetClass, display, args, n) ;
310
311     XtRealizeWidget(toplevel);
312
313     display = XtDisplay (toplevel);
314     XtGetApplicationResources(toplevel, &appArgs, 
315         resources, XtNumber(resources), NULL, 0);
316
317     password = XtMalloc(1);
318     password[0] = '\0';
319     stars = XtMalloc(1);
320     stars[0] = '\0';
321
322    /*  Get Dt initialized  */
323    if (DtInitialize (display, toplevel, argv[0], "Dtaction") == False)
324    {
325       /* Fatal Error: could not connect to the messaging system. */
326       /* DtInitialize() has already logged an appropriate error msg */
327       exit(-1);
328    }
329
330    /*
331     * If the request specified that it wanted to run as a different
332     * user, then take care of prompting for a password, and doing any
333     * necessary verification and logging.
334     */
335    CheckUserRequest();
336    
337    /* Load the filetype/action dbs; DtInvokeAction() requires this */
338    DtDbLoad();
339
340    /*
341     * Get the requested action name
342     */
343     if ( (actionName = argv[1]) == NULL)
344     {
345         fprintf(stderr, "%s", GETMESSAGE(1,10,"No action name specified.\n"));
346         exit(-1);
347     }
348
349     if ( argc > 2 ) 
350     {
351         /*
352          * create an action arg array for the file objects for
353          * this action.  This number of objects should be one
354          * less than the argument count. The returned vector will
355          * be terminated by a null pointer.
356          */
357         numArgs= argc - 2;
358         ap = (DtActionArg *) XtCalloc(numArgs,sizeof(DtActionArg)); 
359     }
360
361         /*
362          * This client is restricted to FILE arguments.
363          * for the time being.
364          */
365     for ( n = 0; n < numArgs; n++) {
366         ap[n].argClass    = DtACTION_FILE;
367         ap[n].u.file.name = argv[n+2];
368     }
369
370     actionId = DtActionInvoke(toplevel, actionName, ap, numArgs,
371         appArgs.termOpts,
372         appArgs.execHost,
373         appArgs.contextDir,
374         True,                   /* use indicator */
375         (DtActionCallbackProc) actionStatusCallback,
376         NULL);
377
378     /*
379      * Set up a timer if we didn't get a valid procId -- since there will
380      * be no invocation update in that case.
381      * We must invoke XtMainLoop() at least once, to force any prompt or
382      * error dialogs to get posted.
383      */
384     if ( !actionId)
385             XtAppAddTimeOut(appContext,
386                 10, (XtTimerCallbackProc)CheckForDone,
387                            NULL);
388
389     XtAppMainLoop(appContext);
390
391     return EXIT_SUCCESS;
392 }
393
394
395 static void
396 SetGidUid ( unsigned short rgid, unsigned short ruid )
397 {
398
399         /* fix process gid */
400 #if defined(SVR4) || defined(_AIX)
401     setgid(rgid);
402 #elif defined(__linux__) || defined(CSRG_BASED)
403     if(-1 == setregid(rgid, rgid)) {
404         fprintf(stderr, "SetGidUid: setregid failed on %d\n", rgid);
405     }
406 #elif defined(__hpux)
407     setresgid(rgid, rgid, rgid);
408 #else
409     setregid(rgid, rgid, rgid);
410 #endif
411
412         /* fix process uid */
413 #if defined (SVR4) || defined (_AIX)
414     setuid(ruid);
415 #elif defined(__linux__) || defined(CSRG_BASED)
416     if(-1 == setreuid(ruid, ruid)) {
417         fprintf(stderr, "SetGidUid: setreuid failed on %d\n", ruid);
418     }
419 #elif defined(__hpux)
420     setresuid(ruid, ruid, ruid);
421 #else
422     setreuid(ruid, ruid, ruid);
423 #endif
424
425 }
426
427
428 /*
429  * This function checks to see if the user has requested that the action
430  * be invoked under a different user Id.  If a different user Id has been
431  * requested, then the user will be prompted to enter either the password
432  * for that user, or the root password.  Once a valid password has been
433  * entered, this function will return.
434  */
435
436 void 
437 CheckUserRequest( void )
438
439 {
440    unsigned short ruid;
441    unsigned short rgid;
442    struct passwd * passwd;
443 #ifdef sun
444    struct spwd * spwd;
445 #endif
446    Boolean notExist = False;
447    Boolean alreadySetToRoot = False;
448
449    rootRequest = False;
450
451         /* get current group id */
452    rgid = getgid();
453         /* get current user id */
454    ruid = getuid();
455
456       /* See if the user wants to run as himself */
457    if (appArgs.user == NULL)
458    {
459       SetGidUid(rgid,ruid);
460       return;
461    }
462
463    /* Get password for the requested user */
464    passwd = getpwnam(appArgs.user);
465    if (passwd) {
466 #ifdef sun
467       spwd = getspnam(appArgs.user);
468       if (spwd)
469       {
470 #endif
471          if (passwd->pw_uid == ruid)
472          {
473             /* 
474              * We are already running as the
475              *  requested user.  So return now.
476              */
477              SetGidUid(rgid,ruid);
478              return;
479           }
480
481 #ifdef sun
482           if (spwd->sp_pwdp)
483              toPword = XtNewString(spwd->sp_pwdp);
484        }
485 #else
486        if (passwd->pw_passwd)
487           toPword = XtNewString(passwd->pw_passwd);
488 #endif /* sun */
489        basegid = passwd->pw_gid;
490        newuid = passwd->pw_uid;
491     }
492    else
493        notExist = True;
494
495    /* Root requests require some extra work later */
496    if (strcmp(appArgs.user, "root") == 0)
497          rootRequest = True;
498
499    /* Get name for the current user */
500    passwd = getpwuid(ruid);
501    if (passwd && passwd->pw_name)
502        origName = XtNewString(passwd->pw_name);
503
504    /* Get password for the root user */
505    passwd = getpwnam("root");
506    if (passwd && passwd->pw_passwd) 
507    {
508 #ifdef sun
509        spwd = getspnam("root");
510        if (spwd && spwd->sp_pwdp) 
511        { 
512            rootPword = XtNewString(spwd->sp_pwdp);
513        }
514 #else
515       rootPword = XtNewString(passwd->pw_passwd);
516 #endif /* sun */
517
518        if (passwd->pw_uid == ruid)
519           alreadySetToRoot = True;
520    }
521
522    /*
523     * If 'alreadySetToRoot' is set to True, then that means that the
524     * user is  currently running as root.
525     */
526
527    if (notExist)
528    {
529       /* Requested user does not exist; this function will exit() */
530        UnknownUser();
531    }
532    else if ((alreadySetToRoot) ||  /* requested users passwd is null */
533       ((toPword && (toPword[0] == '\0')) || (toPword == NULL)))
534    {
535        /* Already there -- no need to check a passwd */
536           LogSuccess();
537    }
538    else
539          CheckPasswd();
540 }
541
542
543 /**********
544  * void CheckPasswd ()
545  *
546  * get a password from the user and check it against an encrypted passwd
547  *
548  * Returns:
549  *      0 if invalid
550  *      True if valid
551  *
552  * Side Effects:
553  *      none.
554  */
555
556 void 
557 CheckPasswd( void )
558
559 {
560     /*
561      * get this users password
562      */
563     GetUserPrompt();
564 }
565
566
567 /**********
568  * void AddSuLog (FromName, ToName, ChangeType)
569  *
570  * add switch from user "FromName" to user "ToName" to sulog.
571  * ChangeType is "+" for success, "-" for failure.
572  *
573  * Parameters:
574  *      char *FromName -- from name (for logging).
575  *      char *ToName -- to name (for logging).
576  *      char *ChangeType -- +/- (for logging).
577  */
578
579 void 
580 AddSuLog(
581         char *FromName,
582         char *ToName,
583         char *ChangeType )
584
585 {
586     char        *toString;
587     struct tm  *localtime ();
588
589        FILE * f;
590     struct stat st;
591     time_t    timenow;
592     struct tm  *now;
593
594 #ifdef hpV4  /* 10.* versions */
595     char * SULog = "/var/adm/sulog";
596 #elif  defined( hpux )  /* 9.* versions */
597     char * SULog = "/usr/adm/sulog";
598 #else
599     char * SULog = "/var/adm/sulog";
600 #endif
601
602     if ((f = fopen (SULog, "a")) == NULL)
603         return;
604
605     (void) time (&timenow);
606     now = localtime (&timenow);
607
608     /* build toString... */
609     if (ToName && *ToName) 
610             toString = ToName;
611     else 
612             toString = FromName;
613
614     fprintf(f, (GETMESSAGE(1,1, 
615            "dtaction %1$.2d/%2$.2d %3$.2d:%4$.2d %5$1.1s %6$s %7$s-%8$s\n")),
616            now -> tm_mon + 1, now -> tm_mday, now -> tm_hour,
617            now -> tm_min, ChangeType, "?", FromName, toString);
618
619     (void) fclose (f);
620
621     /*
622      * take away write access from SULog
623      */
624
625     if(chmod (SULog, (int) (st.st_mode & 07777) & ~0222) == -1) {
626         fprintf(stderr, "Error on chmod of '%s', %s\n", SULog, strerror(errno));
627     }
628
629     return;
630 }
631
632
633 /**********
634  * void CleanPath (Path);
635  *
636  * remove any directories from the path that are
637  *    - null (leading/trailing colon or double colon)
638  *    - not anchored to root (no leading /)
639  *
640  * the returned path is the original path with any such
641  * directories stripped
642  *
643  * Parameters:
644  *      char *Path -- $PATH to clean
645  *
646  * Returns:
647  *      none.
648  *
649  * Side Effects:
650  *      Unanchored paths will be stripped off of Path.
651  */
652
653 void 
654 CleanPath(
655         char *Path )
656
657 {
658     char  *StrippedPath;
659     char  *PathHead;
660
661     StrippedPath = PathHead = Path;
662
663     while (*Path) {
664
665         /*
666          * remove multiple ':'s
667          */
668
669         while (*Path && (*Path == ':')) {
670             (void) Path++;
671         }
672
673         /*
674          * is the first character of this
675          * directory a '/'????
676          */
677
678         if (*Path == '/') {
679
680             /*
681              * copy directory intact;
682              */
683
684             while (*Path && (*Path != ':')) {
685                 *StrippedPath++ = *Path++;
686             }
687
688             if (*Path == ':') {
689                 *StrippedPath++ = *Path++;
690             }
691         }
692         else {
693
694             /*
695              * zip past directory
696              */
697
698             while (*Path && (*Path != ':')) {
699                 (void) Path++;
700             }
701
702             if (*Path == ':') {
703                 (void) Path++;
704             }
705         }
706
707     }
708
709     /*
710      * remove all trailing ':'s
711      */
712
713     while ((StrippedPath > PathHead) && (StrippedPath[-1] == ':')) {
714         StrippedPath--;
715     }
716
717     /*
718      * null terminate the path
719      */
720
721     *StrippedPath = '\0';
722     return;
723 }
724
725
726 /*
727  * This is the Ok callback for the password dialog.  It will attempt to
728  * validate the password.  If invalid, then an error dialog is posted,
729  * and the user is prompted to try again.  If valid, then the process
730  * will change to run as the requested user, and dtaction will continue
731  * on its way, attempting to invoke the requested action.
732  */
733
734 /* ARGSUSED */
735 void 
736 OkCallback(
737         Widget w,
738         XtPointer clientData,
739         XtPointer callData )
740
741 {
742    Boolean valid = False;
743
744    /* Do any verification here */
745
746    /* check for primary passwd... */
747    if (!strcmp (crypt (password, toPword), toPword))
748       valid = True;
749
750    /* check for secondary passwd ... */
751    if (rootPword && *rootPword &&
752        !strcmp (crypt (password, rootPword), rootPword))
753    {
754       valid = True;
755    }
756    else if (((rootPword == NULL) || (*rootPword == '\0')) &&
757             (*password == '\0'))
758    {
759       /* No root password, and the user entered no password */
760       valid = True;
761    }
762
763
764    /* If valid password, then unpost */
765    if (valid)
766    {
767       XtUnmanageChild(dlog);
768       XFlush(XtDisplay(dlog));
769       finished = True;
770       LogSuccess();
771    }
772    else
773    {
774       /* Invalid password */
775       Widget err;
776       int n;
777       Arg args[10];
778       XmString okLabel;
779       XmString message;
780       char * template;
781       char * title;
782       char * master;
783
784       okLabel = XmStringCreateLocalized(GETMESSAGE(1, 2, "OK"));
785       template = (GETMESSAGE(1,3, "The password you entered does not match\nthe password for user %s.\n\nPlease reenter the password, or select the\nCancel button to terminate the operation."));
786       master = XtMalloc(strlen(template) + strlen(appArgs.user) + 10);
787       sprintf(master, template, appArgs.user);
788       message = XmStringCreateLocalized(master);
789       title = (GETMESSAGE(1,4, "Action Invoker - Password Error"));
790
791       /* Post an error dialog */
792       n = 0;
793       XtSetArg(args[n], XmNtitle, title); n++;
794       XtSetArg(args[n], XmNmessageString, message); n++;
795       XtSetArg(args[n], XmNokLabelString, okLabel); n++;
796       err = XmCreateErrorDialog(dlog, "err", args, n);
797       XtUnmanageChild(XmMessageBoxGetChild(err, XmDIALOG_CANCEL_BUTTON));
798       XtUnmanageChild(XmMessageBoxGetChild(err, XmDIALOG_HELP_BUTTON));
799       XtManageChild(err);
800       XtAddCallback(err, XmNokCallback, ErrOkCallback, err);
801
802       XFlush(XtDisplay(dlog));
803       XmUpdateDisplay(dlog);
804       LogFailure();
805       XmStringFree(okLabel);
806       XmStringFree(message);
807       XtFree(master);
808    }
809 }
810
811
812 /*
813  * This is the Cancel callback for the password dialog.  It will unpost
814  * the dialog, and exit.
815  */
816
817 /* ARGSUSED */
818 void 
819 CancelCallback(
820         Widget w,
821         XtPointer clientData,
822         XtPointer callData )
823
824 {
825    XtUnmanageChild(dlog);
826    XFlush(XtDisplay(dlog));
827    exit(-1);
828 }
829
830
831 /*
832  * This is the 'Ok' callback for the invalid password error dialog.
833  * It will simply unpost and destroy the error dialog.
834  */
835
836 /* ARGSUSED */
837 void 
838 ErrOkCallback(
839         Widget w,
840         XtPointer clientData,
841         XtPointer callData )
842
843 {
844    Widget err = (Widget)clientData;
845
846    XtUnmanageChild(err);
847    XFlush(XtDisplay(err));
848    XmUpdateDisplay(err);
849    XtDestroyWidget(err);
850 }
851
852
853 /*
854  * This callback is invoked when the password dialog is posted; it forces
855  * the focus to the text input field.
856  */
857
858 /* ARGSUSED */
859 void 
860 MapCallback(
861         Widget w,
862         XtPointer clientData,
863         XtPointer callData )
864
865 {
866    Widget text;
867    Widget dlog = (Widget)clientData;
868
869    /* Force focus initially to the text field */
870    text = XmSelectionBoxGetChild(dlog, XmDIALOG_TEXT);
871    XmProcessTraversal(text, XmTRAVERSE_CURRENT);
872 }
873
874
875 /*
876  * This function creates the prompt dialog for collecting the password
877  * from the user.  It will not give up control until a valid password
878  * has been entered.  If the user cancels the request, then the cancel
879  * callback will exit.
880  */
881
882 void 
883 GetUserPrompt( void )
884
885 {
886    int n;
887    XmString xmString;
888    XmString xmString2;
889    char prompt[BUFSIZ];
890    Widget help;
891    Widget text;
892    XEvent event;
893    Arg args[10];
894    XtTranslations      textTable;
895    XmString cancelLabel;
896    XmString okLabel;
897
898    snprintf(prompt, sizeof prompt, (GETMESSAGE(1,5, "Enter password for user %s:")), 
899             appArgs.user);
900    xmString = XmStringCreateLocalized(prompt);
901    xmString2 =XmStringCreateLocalized(GETMESSAGE(1,6, "Action Invoker - Password"));
902    cancelLabel = XmStringCreateLocalized(GETMESSAGE(1,7, "Cancel"));
903    okLabel = XmStringCreateLocalized(GETMESSAGE(1,2, "OK"));
904
905    XtAppAddActions(appContext,textActions, 2);
906    textTable = XtParseTranslationTable(textEventBindings);
907
908    /* Create the prompt dialog */
909    n = 0;
910    XtSetArg(args[n], XmNselectionLabelString, xmString);  n++;
911    XtSetArg(args[n], XmNdialogTitle, xmString2);  n++;
912    XtSetArg(args[n], XmNautoUnmanage, False);  n++;
913    XtSetArg(args[n], XmNokLabelString, okLabel);  n++;
914    XtSetArg(args[n], XmNcancelLabelString, cancelLabel);  n++;
915    XtSetArg(args[n], XmNdefaultPosition, False);  n++;
916    dlog = XmCreatePromptDialog(toplevel, "prompt", args, n);
917    XmStringFree(xmString);
918    XmStringFree(xmString2);
919    XmStringFree(okLabel);
920    XmStringFree(cancelLabel);
921    XtAddCallback(dlog, XmNokCallback, OkCallback, NULL);
922    XtAddCallback(dlog, XmNcancelCallback, CancelCallback, NULL);
923
924    text = XmSelectionBoxGetChild(dlog, XmDIALOG_TEXT);
925    n = 0;
926    XtSetArg(args[n], XmNtranslations, textTable); n++;
927    XtSetArg(args[n], XmNverifyBell, False);       n++;
928    XtSetValues(text, args, n);
929    XtAddCallback(text, XmNmodifyVerifyCallback, EditPasswdCB, NULL);
930
931    /* Add callback for forcing traversal to the text field */
932    XtAddCallback (XtParent(dlog), XmNpopupCallback, MapCallback, dlog);
933
934    /* Unmanage the help button */
935    help = XmSelectionBoxGetChild(dlog, XmDIALOG_HELP_BUTTON);
936    XtUnmanageChild(help);
937
938    /* Center the dialog */
939    XtRealizeWidget(dlog);
940    XtSetArg (args[0], XmNx,
941              (Position)(WidthOfScreen(XtScreen(dlog)) -
942                         dlog->core.width) / 2);
943    XtSetArg (args[1], XmNy,
944              (Position)(HeightOfScreen(XtScreen(dlog)) -
945                         dlog->core.height) / 2);
946    XtSetValues (dlog, args, 2);
947
948    /* Set the transient property */
949    XSetTransientForHint (XtDisplay (toplevel),
950                          XtWindow (XtParent (dlog)),
951                          XtWindow (toplevel));
952
953    /*  Adjust the decorations for the dialog shell of the dialog  */
954    n = 0;
955    XtSetArg(args[n], XmNmwmFunctions, 0);          n++;
956    XtSetArg(args[n], XmNmwmDecorations, 
957             MWM_DECOR_BORDER | MWM_DECOR_TITLE);   n++;
958    XtSetValues(XtParent(dlog), args, n);
959
960    /* Post the dialog */
961    XtManageChild(dlog);
962
963    /* Wait for the user to finish with the dialog */
964    while (!finished)
965    {
966       XtAppNextEvent(appContext,&event);
967       XtDispatchEvent(&event);
968    }
969
970    /* Destroy the widget, and return any data back to the appl */
971    XtDestroyWidget(dlog);
972 }
973
974
975 /*
976  * When a user has successfully logged in as another user, we need to set
977  * the uid and gid to the requested user.  In addition, if the user is
978  * changing to 'root', then we need to log this in /usr/adm/sulog, and
979  * we need to do some housekeeping of the $PATH environment variable.
980  */
981
982 void 
983 LogSuccess( void )
984
985 {
986    char * path;
987    char * tmpPath;
988
989    AddSuLog(origName, appArgs.user, "+");
990
991    if (rootRequest)
992    {
993       /* Special stuff for the root user */
994       /* Cleanse the $PATH setting */
995       tmpPath = getenv("PATH");
996       path = XtNewString(tmpPath);
997       CleanPath (path);
998       tmpPath = XtMalloc(strlen(path) + 10);
999       strcpy(tmpPath, "PATH=");
1000       strcat(tmpPath, path);
1001       putenv(tmpPath);
1002    }
1003
1004    /* Set up the user's new id's */
1005    SetGidUid(basegid,newuid);
1006    initgroups(appArgs.user, basegid);
1007
1008 }
1009
1010
1011 /*
1012  * Each time the user enters an invalid password, we need to log this in
1013  * /usr/adm/sulog, if the user is attempting to switch to the 'root' user.
1014  */
1015
1016 void 
1017 LogFailure( void )
1018
1019 {
1020    /* Unable to change to specified user; post error, then exit */
1021    AddSuLog(origName, appArgs.user, "-");
1022 }
1023
1024
1025 /***************************************************************************
1026  *
1027  *  MyInsert
1028  *
1029  *  Local self-insert action for the text widget. The default action
1030  *  discards control characters, which are allowed in password.
1031  ***************************************************************************/
1032
1033 /* ARGSUSED */
1034 void 
1035 MyInsert(
1036         Widget w,
1037         XEvent *event,
1038         char **params,
1039         Cardinal *num_params )
1040 {
1041     char           str[32];
1042     XComposeStatus compstatus;
1043     int            n;
1044
1045     n = XLookupString((XKeyEvent *)event, str, sizeof(str),
1046                       (KeySym *)NULL, &compstatus);
1047
1048     if (n > 0) {
1049        str[n] = '\0';
1050        XmTextFieldInsert(w, XmTextFieldGetInsertionPosition(w), str);
1051     }
1052 }
1053
1054
1055 /***************************************************************************
1056  *
1057  *  MyCancel
1058  *
1059  *  This action catches the 'Escape' key, and following Motif standards,
1060  *  unposts the dialog, as if the 'Cancel' button had been pressed.
1061  ***************************************************************************/
1062
1063 /* ARGSUSED */
1064 void 
1065 MyCancel(
1066         Widget w,
1067         XEvent *event,
1068         char **params,
1069         Cardinal *num_params )
1070 {
1071    CancelCallback(w, NULL, NULL);
1072 }
1073
1074
1075
1076 /***************************************************************************
1077  *
1078  *  EditPasswdCB
1079  *
1080  *  implement no-echo of the password
1081  ***************************************************************************/
1082
1083
1084 /* ARGSUSED */
1085 void 
1086 EditPasswdCB(
1087         Widget w,
1088         XtPointer client,
1089         XtPointer call )
1090 {
1091
1092     static Boolean      allow_flag = False;
1093     int                 replaced_length, i;
1094     char                *src, *dst;
1095     XmTextVerifyPtr     cbData = (XmTextVerifyPtr) call;
1096   
1097     if (!allow_flag)
1098     {
1099       /* 
1100        * we need to keep track of the password ourselves in order to 
1101        * disable echoing of the password...
1102        */
1103       
1104       replaced_length = cbData->endPos - cbData->startPos;
1105       if (replaced_length > cbData->text->length)
1106       {
1107         /* shift the text at and after endPos to the left...  */
1108         for (src = password + cbData->endPos,
1109              dst = src + (cbData->text->length - replaced_length),
1110              i = passwordLength - cbData->endPos;
1111              i > 0;
1112              ++src, ++dst, --i)
1113          {
1114             *dst = *src;
1115          }
1116       }
1117       else if (replaced_length < cbData->text->length)
1118       {
1119         /* Buffer must grow */
1120         password = XtRealloc(password,
1121               passwordLength + cbData->text->length - replaced_length + 5);
1122
1123         /* shift the text at and after endPos to the right...  */
1124         for (src = password + passwordLength - 1,
1125              dst = src + (cbData->text->length - replaced_length),
1126              i = passwordLength - cbData->endPos;
1127              i > 0;
1128              --src, --dst, --i)
1129          {
1130             *dst = *src;
1131          }
1132       }
1133       
1134       /*
1135        * update the password...
1136        */
1137
1138       for (src = cbData->text->ptr,
1139            dst = password + cbData->startPos,
1140            i = cbData->text->length;
1141            i > 0;
1142            ++src, ++dst, --i)
1143       {
1144         *dst = *src;
1145       }
1146
1147       passwordLength += cbData->text->length - replaced_length;
1148       password[passwordLength] = '\0';
1149       stars = XtRealloc(stars, cbData->text->length + 10);
1150       for (i = 0; i < cbData->text->length; i++)
1151          stars[i] = ' ';
1152       stars[cbData->text->length] = '\0';
1153       
1154       /*
1155        * put the appropriate number of stars in the passwd Widget..
1156        */
1157
1158       allow_flag = True;
1159       XmTextFieldReplace(w, cbData->startPos, cbData->endPos, stars);
1160       allow_flag = False;
1161     }
1162   
1163     cbData->doit = allow_flag;
1164 }
1165
1166
1167 /*
1168  * This function posts an error dialog informing the user that they have
1169  * specified an invalid user name.  No further processing will be done; we
1170  * will simply wait for the user to acknowledge the error, and then exit.
1171  */
1172
1173 void 
1174 UnknownUser( void )
1175
1176 {
1177    Widget err;
1178    int n;
1179    Arg args[10];
1180    XmString okLabel;
1181    XmString message;
1182    char * template;
1183    char * title;
1184    char * master;
1185
1186    okLabel = XmStringCreateLocalized(GETMESSAGE(1,2, "OK"));
1187    template = (GETMESSAGE(1,8, "The user '%s' is an unknown user name.\n\nThe requested action will not be executed."));
1188    master = XtMalloc(strlen(template) + strlen(appArgs.user) + 10);
1189    sprintf(master, template, appArgs.user);
1190    message = XmStringCreateLocalized(master);
1191    title = (GETMESSAGE(1,9, "Action Invoker - Unknown User"));
1192
1193    /* Post an error dialog */
1194    n = 0;
1195    XtSetArg(args[n], XmNtitle, title); n++;
1196    XtSetArg(args[n], XmNmessageString, message); n++;
1197    XtSetArg(args[n], XmNokLabelString, okLabel); n++;
1198    XtSetArg(args[n], XmNdefaultPosition, False);  n++;
1199    err = XmCreateErrorDialog(toplevel, "err", args, n);
1200    XtUnmanageChild(XmMessageBoxGetChild(err, XmDIALOG_CANCEL_BUTTON));
1201    XtUnmanageChild(XmMessageBoxGetChild(err, XmDIALOG_HELP_BUTTON));
1202
1203    /* Center the dialog */
1204    XtRealizeWidget(err);
1205    XtSetArg (args[0], XmNx,
1206              (Position)(WidthOfScreen(XtScreen(err)) -
1207                         err->core.width) / 2);
1208    XtSetArg (args[1], XmNy,
1209              (Position)(HeightOfScreen(XtScreen(err)) -
1210                         err->core.height) / 2);
1211    XtSetValues (err, args, 2);
1212
1213    XtManageChild(err);
1214    XtAddCallback(err, XmNokCallback, UnknownUserCallback, err);
1215    XtAddCallback(err, XmNcancelCallback, UnknownUserCallback, err);
1216
1217    XFlush(XtDisplay(toplevel));
1218    XmUpdateDisplay(toplevel);
1219    LogFailure();
1220    XmStringFree(okLabel);
1221    XmStringFree(message);
1222    XtFree(master);
1223    XtAppMainLoop(appContext);
1224 }
1225
1226
1227 /*
1228  * This is the 'Cancel' callback for the 'Invalid User' error dialog.
1229  * It removes the dialog, and then exits.
1230  */
1231
1232 /* ARGSUSED */
1233 void 
1234 UnknownUserCallback(
1235         Widget w,
1236         XtPointer clientData,
1237         XtPointer callData )
1238
1239 {
1240    Widget err = (Widget)clientData;
1241
1242    XtUnmanageChild(err);
1243    XFlush(XtDisplay(err));
1244    XmUpdateDisplay(err);
1245    exit(-1);
1246 }
1247
1248 void actionStatusCallback(
1249                         DtActionInvocationID id,
1250                         XtPointer   client_data,
1251                         DtActionArg *aap,
1252                         int         aac,
1253                         DtActionStatus status )
1254 {
1255
1256     switch( status ) {
1257         case DtACTION_INVOKED:
1258             /*
1259              * There may still be error dialogs to post so we must return
1260              * to mainLoop before exiting.
1261              */
1262             if ( exitAfterInvoked )
1263                     XtAppAddTimeOut(appContext,
1264                         10 , (XtTimerCallbackProc)CheckForDone,
1265                       NULL);
1266             break;
1267
1268         case DtACTION_DONE:
1269             XtAppAddTimeOut(appContext,
1270                 10 , (XtTimerCallbackProc)CheckForDone,
1271               NULL);
1272             break;
1273
1274         case DtACTION_FAILED:
1275         case DtACTION_CANCELED:
1276             exitStatus = 1;
1277             XtAppAddTimeOut(appContext,
1278                 10 , (XtTimerCallbackProc)CheckForDone,
1279               NULL);
1280             break;
1281
1282         default:
1283             break;
1284     }
1285
1286 }