/* * CDE - Common Desktop Environment * * Copyright (c) 1993-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with these libraries and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA */ /* $TOG: Main.c /main/18 1998/07/23 17:56:36 mgreess $ */ /***************************************************************************** ***************************************************************************** ** ** File: Main.c ** ** Project: DT ** ** Description: This file contains the main program for dtaction. ** ** **(c) Copyright 1993, 1994 Hewlett-Packard Company **(c) Copyright 1993, 1994 International Business Machines Corp. **(c) Copyright 1993, 1994 Sun Microsystems, Inc. **(c) Copyright 1993, 1994 Unix System Labs, Inc., a subsidiary of Novell, Inc. ** ** **************************************************************************** ************************************<+>*************************************/ #include #include #include #include #include
#include #include #include /* for MAXPATHLEN and MAXHOSTNAMELEN */ #if defined(sun) || defined(__linux__) #include #include #endif #include #include #include #include #include #include #include #include #include #include #include #include
#include
#include
#include
#include
/******************************************************************************/ #include /* Command line options */ XrmOptionDescRec option_list[] = { { "-user", "user", XrmoptionSepArg, NULL}, { "-contextDir", "contextDir", XrmoptionSepArg, NULL}, { "-execHost", "execHost", XrmoptionSepArg, NULL}, { "-termOpts", "termOpts", XrmoptionSepArg, NULL}, }; typedef struct { char * user; char * contextDir; char * execHost; char * termOpts; } ApplArgs, *ApplArgsPtr; #define LOGIN_STR_LEN 15 #define STAR ' ' Widget dlog; char *password; char *stars; int passwordLength = 0; Boolean finished = False; Boolean rootRequest = False; char * toPword = NULL; char * rootPword = NULL; char * origName = "Unknown"; int basegid = -1; int newuid = -1; /* Dtaction resources */ XtResource resources[] = { { "user", "User", XmRString, sizeof(char *), XtOffsetOf(ApplArgs, user), XmRImmediate, (XtPointer) NULL, }, { "contextDir", "ContextDir", XmRString, sizeof(char *), XtOffsetOf(ApplArgs, contextDir), XmRImmediate, (XtPointer) NULL, }, { "execHost", "ExecHost", XmRString, sizeof(char *), XtOffsetOf(ApplArgs, execHost), XmRImmediate, (XtPointer) NULL, }, { "termOpts", "TermParms", XmRString, sizeof(char *), XtOffsetOf(ApplArgs, termOpts), XmRImmediate, (XtPointer) NULL, }, }; /* * macro to get message catalog strings */ #ifndef NO_MESSAGE_CATALOG # define _CLIENT_CAT_NAME "dtact" extern char *_DtGetMessage(char *filename, int set, int n, char *s); # define GETMESSAGE(set, number, string)\ (_DtGetMessage(_CLIENT_CAT_NAME, set, number, string)) #else # define GETMESSAGE(set, number, string)\ string #endif Boolean _DtWmStringsAreEqual( char *in_str, char *test_str) ; void CheckForDone( XtPointer clientData, XtIntervalId id) ; void CheckUserRequest( void ) ; void CheckPasswd( void ) ; void AddSuLog( char *FromName, char *ToName, char *ChangeType) ; void CleanPath( char *Path) ; void OkCallback( Widget w, XtPointer clientData, XtPointer callData) ; void ErrOkCallback( Widget w, XtPointer clientData, XtPointer callData) ; void CancelCallback( Widget w, XtPointer clientData, XtPointer callData) ; void MapCallback( Widget w, XtPointer clientData, XtPointer callData) ; void actionStatusCallback ( DtActionInvocationID id, XtPointer client_data, DtActionArg *aap, int aac, DtActionStatus status ); void GetUserPrompt( void ) ; void LogSuccess( void ) ; void LogFailure( void ) ; void MyInsert( Widget w, XEvent *event, char **params, Cardinal *num_params) ; void MyCancel( Widget w, XEvent *event, char **params, Cardinal *num_params) ; void EditPasswdCB( Widget w, XtPointer client, XtPointer call) ; void UnknownUser( void ) ; void UnknownUserCallback( Widget w, XtPointer clientData, XtPointer callData) ; /******** End Forward Function Declarations ********/ /*************************************************************************** * * Text widget actions and translations * ***************************************************************************/ XtActionsRec textActions[] = { {"my-insert", (XtActionProc)MyInsert}, {"my-cancel", (XtActionProc)MyCancel}, }; char textEventBindings[] = { "Shift Tab: prev-tab-group() \n\ Ctrl Tab: next-tab-group() \n\ Tab: next-tab-group() \n\ osfEndLine: end-of-line() \n\ osfBeginLine: beginning-of-line() \n\ ~Shift osfRight: forward-character()\n\ ~Shift osfLeft: backward-character()\n\ Ctrl osfDelete: delete-to-end-of-line()\n\ osfDelete: delete-next-character()\n\ osfBackSpace: delete-previous-character()\n\ osfActivate: activate()\n\ Ctrl Return: activate()\n\ Return: activate()\n\ osfCancel: my-cancel()\n\ : my-insert()\n\ ~Ctrl ~Shift ~Meta ~Alt: grab-focus() \n\ : enter()\n\ : leave()\n\ : focusIn()\n\ : focusOut()\n\ : unmap()" }; /****************************************************************************/ /****************************************************************************/ static Widget toplevel; static ApplArgs appArgs; static XtAppContext appContext; static DtActionInvocationID actionId; static Boolean exitAfterInvoked = False; static int exitStatus = 0; /* ARGSUSED */ void CheckForDone( XtPointer clientData, XtIntervalId id) { if ( toplevel->core.num_popups == 0 ) exit(exitStatus); XtAppAddTimeOut(appContext, 10, (XtTimerCallbackProc)CheckForDone, NULL); } int main( int argc, char **argv ) { Display *display; Arg args[20]; int n=0; char *actionName; int numArgs = 0; DtActionArg *ap = NULL; XtSetLanguageProc(NULL, NULL, NULL); _DtEnvControl(DT_ENV_SET); (void) signal(SIGCHLD, (void (*)())SIG_IGN); /* Initialize the toolkit and open the display */ XtToolkitInitialize() ; appContext = XtCreateApplicationContext() ; if ( !(display = XtOpenDisplay( appContext, NULL, argv[0], "Dtaction", option_list, sizeof(option_list)/sizeof(XrmOptionDescRec), &argc, argv)) ) { setlocale(LC_ALL, ""); fprintf(stderr, "%s", GETMESSAGE(1,11,"Can't open display.\n")); exit(-1); } XtSetArg(args[n], XmNallowShellResize, True); n++; XtSetArg(args[n], XmNmappedWhenManaged, False); n++; XtSetArg(args[n], XmNheight, 1); n++; XtSetArg(args[n], XmNwidth, 1); n++; toplevel = XtAppCreateShell( argv[0], "Dtaction", topLevelShellWidgetClass, display, args, n) ; XtRealizeWidget(toplevel); display = XtDisplay (toplevel); XtGetApplicationResources(toplevel, &appArgs, resources, XtNumber(resources), NULL, 0); password = XtMalloc(1); password[0] = '\0'; stars = XtMalloc(1); stars[0] = '\0'; /* Get Dt initialized */ if (DtInitialize (display, toplevel, argv[0], "Dtaction") == False) { /* Fatal Error: could not connect to the messaging system. */ /* DtInitialize() has already logged an appropriate error msg */ exit(-1); } /* * If the request specified that it wanted to run as a different * user, then take care of prompting for a password, and doing any * necessary verification and logging. */ CheckUserRequest(); /* Load the filetype/action dbs; DtInvokeAction() requires this */ DtDbLoad(); /* * Get the requested action name */ if ( (actionName = argv[1]) == NULL) { fprintf(stderr, "%s", GETMESSAGE(1,10,"No action name specified.\n")); exit(-1); } if ( argc > 2 ) { /* * create an action arg array for the file objects for * this action. This number of objects should be one * less than the argument count. The returned vector will * be terminated by a null pointer. */ numArgs= argc - 2; ap = (DtActionArg *) XtCalloc(numArgs,sizeof(DtActionArg)); } /* * This client is restricted to FILE arguments. * for the time being. */ for ( n = 0; n < numArgs; n++) { ap[n].argClass = DtACTION_FILE; ap[n].u.file.name = argv[n+2]; } actionId = DtActionInvoke(toplevel, actionName, ap, numArgs, appArgs.termOpts, appArgs.execHost, appArgs.contextDir, True, /* use indicator */ (DtActionCallbackProc) actionStatusCallback, NULL); /* * Set up a timer if we didn't get a valid procId -- since there will * be no invocation update in that case. * We must invoke XtMainLoop() at least once, to force any prompt or * error dialogs to get posted. */ if ( !actionId) XtAppAddTimeOut(appContext, 10, (XtTimerCallbackProc)CheckForDone, NULL); XtAppMainLoop(appContext); return EXIT_SUCCESS; } static void SetGidUid ( unsigned short rgid, unsigned short ruid ) { /* fix process gid */ #if defined(SVR4) || defined(_AIX) setgid(rgid); #elif defined(__linux__) || defined(CSRG_BASED) if(-1 == setregid(rgid, rgid)) { fprintf(stderr, "SetGidUid: setregid failed on %d\n", rgid); } setregid(rgid, rgid); #endif /* fix process uid */ #if defined (SVR4) || defined (_AIX) setuid(ruid); #elif defined(__linux__) || defined(CSRG_BASED) if(-1 == setreuid(ruid, ruid)) { fprintf(stderr, "SetGidUid: setreuid failed on %d\n", ruid); } setreuid(ruid, ruid); #endif } /* * This function checks to see if the user has requested that the action * be invoked under a different user Id. If a different user Id has been * requested, then the user will be prompted to enter either the password * for that user, or the root password. Once a valid password has been * entered, this function will return. */ void CheckUserRequest( void ) { unsigned short ruid; unsigned short rgid; struct passwd * passwd; #ifdef sun struct spwd * spwd; #endif Boolean notExist = False; Boolean alreadySetToRoot = False; rootRequest = False; /* get current group id */ rgid = getgid(); /* get current user id */ ruid = getuid(); /* See if the user wants to run as himself */ if (appArgs.user == NULL) { SetGidUid(rgid,ruid); return; } /* Get password for the requested user */ passwd = getpwnam(appArgs.user); if (passwd) { #ifdef sun spwd = getspnam(appArgs.user); if (spwd) { #endif if (passwd->pw_uid == ruid) { /* * We are already running as the * requested user. So return now. */ SetGidUid(rgid,ruid); return; } #ifdef sun if (spwd->sp_pwdp) toPword = XtNewString(spwd->sp_pwdp); } #else if (passwd->pw_passwd) toPword = XtNewString(passwd->pw_passwd); #endif /* sun */ basegid = passwd->pw_gid; newuid = passwd->pw_uid; } else notExist = True; /* Root requests require some extra work later */ if (strcmp(appArgs.user, "root") == 0) rootRequest = True; /* Get name for the current user */ passwd = getpwuid(ruid); if (passwd && passwd->pw_name) origName = XtNewString(passwd->pw_name); /* Get password for the root user */ passwd = getpwnam("root"); if (passwd && passwd->pw_passwd) { #ifdef sun spwd = getspnam("root"); if (spwd && spwd->sp_pwdp) { rootPword = XtNewString(spwd->sp_pwdp); } #else rootPword = XtNewString(passwd->pw_passwd); #endif /* sun */ if (passwd->pw_uid == ruid) alreadySetToRoot = True; } /* * If 'alreadySetToRoot' is set to True, then that means that the * user is currently running as root. */ if (notExist) { /* Requested user does not exist; this function will exit() */ UnknownUser(); } else if ((alreadySetToRoot) || /* requested users passwd is null */ ((toPword && (toPword[0] == '\0')) || (toPword == NULL))) { /* Already there -- no need to check a passwd */ LogSuccess(); } else CheckPasswd(); } /********** * void CheckPasswd () * * get a password from the user and check it against an encrypted passwd * * Returns: * 0 if invalid * True if valid * * Side Effects: * none. */ void CheckPasswd( void ) { /* * get this users password */ GetUserPrompt(); } /********** * void AddSuLog (FromName, ToName, ChangeType) * * add switch from user "FromName" to user "ToName" to sulog. * ChangeType is "+" for success, "-" for failure. * * Parameters: * char *FromName -- from name (for logging). * char *ToName -- to name (for logging). * char *ChangeType -- +/- (for logging). */ void AddSuLog( char *FromName, char *ToName, char *ChangeType ) { char *toString; FILE * f; struct stat st; time_t timenow; struct tm *now; char * SULog = "/var/adm/sulog"; if ((f = fopen (SULog, "a")) == NULL) return; (void) time (&timenow); now = localtime (&timenow); /* build toString... */ if (ToName && *ToName) toString = ToName; else toString = FromName; fprintf(f, (GETMESSAGE(1,1, "dtaction %1$.2d/%2$.2d %3$.2d:%4$.2d %5$1.1s %6$s %7$s-%8$s\n")), now -> tm_mon + 1, now -> tm_mday, now -> tm_hour, now -> tm_min, ChangeType, "?", FromName, toString); (void) fclose (f); /* * take away write access from SULog */ if(chmod (SULog, 0400) == -1) { fprintf(stderr, "Error on chmod of '%s', %s\n", SULog, strerror(errno)); } return; } /********** * void CleanPath (Path); * * remove any directories from the path that are * - null (leading/trailing colon or double colon) * - not anchored to root (no leading /) * * the returned path is the original path with any such * directories stripped * * Parameters: * char *Path -- $PATH to clean * * Returns: * none. * * Side Effects: * Unanchored paths will be stripped off of Path. */ void CleanPath( char *Path ) { char *StrippedPath; char *PathHead; StrippedPath = PathHead = Path; while (*Path) { /* * remove multiple ':'s */ while (*Path && (*Path == ':')) { (void) Path++; } /* * is the first character of this * directory a '/'???? */ if (*Path == '/') { /* * copy directory intact; */ while (*Path && (*Path != ':')) { *StrippedPath++ = *Path++; } if (*Path == ':') { *StrippedPath++ = *Path++; } } else { /* * zip past directory */ while (*Path && (*Path != ':')) { (void) Path++; } if (*Path == ':') { (void) Path++; } } } /* * remove all trailing ':'s */ while ((StrippedPath > PathHead) && (StrippedPath[-1] == ':')) { StrippedPath--; } /* * null terminate the path */ *StrippedPath = '\0'; return; } /* * This is the Ok callback for the password dialog. It will attempt to * validate the password. If invalid, then an error dialog is posted, * and the user is prompted to try again. If valid, then the process * will change to run as the requested user, and dtaction will continue * on its way, attempting to invoke the requested action. */ /* ARGSUSED */ void OkCallback( Widget w, XtPointer clientData, XtPointer callData ) { Boolean valid = False; /* Do any verification here */ /* check for primary passwd... */ if (!strcmp (crypt (password, toPword), toPword)) valid = True; /* check for secondary passwd ... */ if (rootPword && *rootPword && !strcmp (crypt (password, rootPword), rootPword)) { valid = True; } else if (((rootPword == NULL) || (*rootPword == '\0')) && (*password == '\0')) { /* No root password, and the user entered no password */ valid = True; } /* If valid password, then unpost */ if (valid) { XtUnmanageChild(dlog); XFlush(XtDisplay(dlog)); finished = True; LogSuccess(); } else { /* Invalid password */ Widget err; int n; Arg args[10]; XmString okLabel; XmString message; char * template; char * title; char * master; okLabel = XmStringCreateLocalized(GETMESSAGE(1, 2, "OK")); 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.")); master = XtMalloc(strlen(template) + strlen(appArgs.user) + 10); sprintf(master, template, appArgs.user); message = XmStringCreateLocalized(master); title = (GETMESSAGE(1,4, "Action Invoker - Password Error")); /* Post an error dialog */ n = 0; XtSetArg(args[n], XmNtitle, title); n++; XtSetArg(args[n], XmNmessageString, message); n++; XtSetArg(args[n], XmNokLabelString, okLabel); n++; err = XmCreateErrorDialog(dlog, "err", args, n); XtUnmanageChild(XmMessageBoxGetChild(err, XmDIALOG_CANCEL_BUTTON)); XtUnmanageChild(XmMessageBoxGetChild(err, XmDIALOG_HELP_BUTTON)); XtManageChild(err); XtAddCallback(err, XmNokCallback, ErrOkCallback, err); XFlush(XtDisplay(dlog)); XmUpdateDisplay(dlog); LogFailure(); XmStringFree(okLabel); XmStringFree(message); XtFree(master); } } /* * This is the Cancel callback for the password dialog. It will unpost * the dialog, and exit. */ /* ARGSUSED */ void CancelCallback( Widget w, XtPointer clientData, XtPointer callData ) { XtUnmanageChild(dlog); XFlush(XtDisplay(dlog)); exit(-1); } /* * This is the 'Ok' callback for the invalid password error dialog. * It will simply unpost and destroy the error dialog. */ /* ARGSUSED */ void ErrOkCallback( Widget w, XtPointer clientData, XtPointer callData ) { Widget err = (Widget)clientData; XtUnmanageChild(err); XFlush(XtDisplay(err)); XmUpdateDisplay(err); XtDestroyWidget(err); } /* * This callback is invoked when the password dialog is posted; it forces * the focus to the text input field. */ /* ARGSUSED */ void MapCallback( Widget w, XtPointer clientData, XtPointer callData ) { Widget text; Widget dlog = (Widget)clientData; /* Force focus initially to the text field */ text = XmSelectionBoxGetChild(dlog, XmDIALOG_TEXT); XmProcessTraversal(text, XmTRAVERSE_CURRENT); } /* * This function creates the prompt dialog for collecting the password * from the user. It will not give up control until a valid password * has been entered. If the user cancels the request, then the cancel * callback will exit. */ void GetUserPrompt( void ) { int n; XmString xmString; XmString xmString2; char prompt[BUFSIZ]; Widget help; Widget text; XEvent event; Arg args[10]; XtTranslations textTable; XmString cancelLabel; XmString okLabel; snprintf(prompt, sizeof prompt, (GETMESSAGE(1,5, "Enter password for user %s:")), appArgs.user); xmString = XmStringCreateLocalized(prompt); xmString2 =XmStringCreateLocalized(GETMESSAGE(1,6, "Action Invoker - Password")); cancelLabel = XmStringCreateLocalized(GETMESSAGE(1,7, "Cancel")); okLabel = XmStringCreateLocalized(GETMESSAGE(1,2, "OK")); XtAppAddActions(appContext,textActions, 2); textTable = XtParseTranslationTable(textEventBindings); /* Create the prompt dialog */ n = 0; XtSetArg(args[n], XmNselectionLabelString, xmString); n++; XtSetArg(args[n], XmNdialogTitle, xmString2); n++; XtSetArg(args[n], XmNautoUnmanage, False); n++; XtSetArg(args[n], XmNokLabelString, okLabel); n++; XtSetArg(args[n], XmNcancelLabelString, cancelLabel); n++; XtSetArg(args[n], XmNdefaultPosition, False); n++; dlog = XmCreatePromptDialog(toplevel, "prompt", args, n); XmStringFree(xmString); XmStringFree(xmString2); XmStringFree(okLabel); XmStringFree(cancelLabel); XtAddCallback(dlog, XmNokCallback, OkCallback, NULL); XtAddCallback(dlog, XmNcancelCallback, CancelCallback, NULL); text = XmSelectionBoxGetChild(dlog, XmDIALOG_TEXT); n = 0; XtSetArg(args[n], XmNtranslations, textTable); n++; XtSetArg(args[n], XmNverifyBell, False); n++; XtSetValues(text, args, n); XtAddCallback(text, XmNmodifyVerifyCallback, EditPasswdCB, NULL); /* Add callback for forcing traversal to the text field */ XtAddCallback (XtParent(dlog), XmNpopupCallback, MapCallback, dlog); /* Unmanage the help button */ help = XmSelectionBoxGetChild(dlog, XmDIALOG_HELP_BUTTON); XtUnmanageChild(help); /* Center the dialog */ XtRealizeWidget(dlog); XtSetArg (args[0], XmNx, (Position)(WidthOfScreen(XtScreen(dlog)) - dlog->core.width) / 2); XtSetArg (args[1], XmNy, (Position)(HeightOfScreen(XtScreen(dlog)) - dlog->core.height) / 2); XtSetValues (dlog, args, 2); /* Set the transient property */ XSetTransientForHint (XtDisplay (toplevel), XtWindow (XtParent (dlog)), XtWindow (toplevel)); /* Adjust the decorations for the dialog shell of the dialog */ n = 0; XtSetArg(args[n], XmNmwmFunctions, 0); n++; XtSetArg(args[n], XmNmwmDecorations, MWM_DECOR_BORDER | MWM_DECOR_TITLE); n++; XtSetValues(XtParent(dlog), args, n); /* Post the dialog */ XtManageChild(dlog); /* Wait for the user to finish with the dialog */ while (!finished) { XtAppNextEvent(appContext,&event); XtDispatchEvent(&event); } /* Destroy the widget, and return any data back to the appl */ XtDestroyWidget(dlog); } /* * When a user has successfully logged in as another user, we need to set * the uid and gid to the requested user. In addition, if the user is * changing to 'root', then we need to log this in /usr/adm/sulog, and * we need to do some housekeeping of the $PATH environment variable. */ void LogSuccess( void ) { char * path; char * tmpPath; AddSuLog(origName, appArgs.user, "+"); if (rootRequest) { /* Special stuff for the root user */ /* Cleanse the $PATH setting */ tmpPath = getenv("PATH"); path = XtNewString(tmpPath); CleanPath (path); tmpPath = XtMalloc(strlen(path) + 10); strcpy(tmpPath, "PATH="); strcat(tmpPath, path); putenv(tmpPath); } /* Set up the user's new id's */ SetGidUid(basegid,newuid); initgroups(appArgs.user, basegid); } /* * Each time the user enters an invalid password, we need to log this in * /usr/adm/sulog, if the user is attempting to switch to the 'root' user. */ void LogFailure( void ) { /* Unable to change to specified user; post error, then exit */ AddSuLog(origName, appArgs.user, "-"); } /*************************************************************************** * * MyInsert * * Local self-insert action for the text widget. The default action * discards control characters, which are allowed in password. ***************************************************************************/ /* ARGSUSED */ void MyInsert( Widget w, XEvent *event, char **params, Cardinal *num_params ) { char str[32]; XComposeStatus compstatus; int n; n = XLookupString((XKeyEvent *)event, str, sizeof(str), (KeySym *)NULL, &compstatus); if (n > 0) { str[n] = '\0'; XmTextFieldInsert(w, XmTextFieldGetInsertionPosition(w), str); } } /*************************************************************************** * * MyCancel * * This action catches the 'Escape' key, and following Motif standards, * unposts the dialog, as if the 'Cancel' button had been pressed. ***************************************************************************/ /* ARGSUSED */ void MyCancel( Widget w, XEvent *event, char **params, Cardinal *num_params ) { CancelCallback(w, NULL, NULL); } /*************************************************************************** * * EditPasswdCB * * implement no-echo of the password ***************************************************************************/ /* ARGSUSED */ void EditPasswdCB( Widget w, XtPointer client, XtPointer call ) { static Boolean allow_flag = False; int replaced_length, i; char *src, *dst; XmTextVerifyPtr cbData = (XmTextVerifyPtr) call; if (!allow_flag) { /* * we need to keep track of the password ourselves in order to * disable echoing of the password... */ replaced_length = cbData->endPos - cbData->startPos; if (replaced_length > cbData->text->length) { /* shift the text at and after endPos to the left... */ for (src = password + cbData->endPos, dst = src + (cbData->text->length - replaced_length), i = passwordLength - cbData->endPos; i > 0; ++src, ++dst, --i) { *dst = *src; } } else if (replaced_length < cbData->text->length) { /* Buffer must grow */ password = XtRealloc(password, passwordLength + cbData->text->length - replaced_length + 5); /* shift the text at and after endPos to the right... */ for (src = password + passwordLength - 1, dst = src + (cbData->text->length - replaced_length), i = passwordLength - cbData->endPos; i > 0; --src, --dst, --i) { *dst = *src; } } /* * update the password... */ for (src = cbData->text->ptr, dst = password + cbData->startPos, i = cbData->text->length; i > 0; ++src, ++dst, --i) { *dst = *src; } passwordLength += cbData->text->length - replaced_length; password[passwordLength] = '\0'; stars = XtRealloc(stars, cbData->text->length + 10); for (i = 0; i < cbData->text->length; i++) stars[i] = ' '; stars[cbData->text->length] = '\0'; /* * put the appropriate number of stars in the passwd Widget.. */ allow_flag = True; XmTextFieldReplace(w, cbData->startPos, cbData->endPos, stars); allow_flag = False; } cbData->doit = allow_flag; } /* * This function posts an error dialog informing the user that they have * specified an invalid user name. No further processing will be done; we * will simply wait for the user to acknowledge the error, and then exit. */ void UnknownUser( void ) { Widget err; int n; Arg args[10]; XmString okLabel; XmString message; char * template; char * title; char * master; okLabel = XmStringCreateLocalized(GETMESSAGE(1,2, "OK")); template = (GETMESSAGE(1,8, "The user '%s' is an unknown user name.\n\nThe requested action will not be executed.")); master = XtMalloc(strlen(template) + strlen(appArgs.user) + 10); sprintf(master, template, appArgs.user); message = XmStringCreateLocalized(master); title = (GETMESSAGE(1,9, "Action Invoker - Unknown User")); /* Post an error dialog */ n = 0; XtSetArg(args[n], XmNtitle, title); n++; XtSetArg(args[n], XmNmessageString, message); n++; XtSetArg(args[n], XmNokLabelString, okLabel); n++; XtSetArg(args[n], XmNdefaultPosition, False); n++; err = XmCreateErrorDialog(toplevel, "err", args, n); XtUnmanageChild(XmMessageBoxGetChild(err, XmDIALOG_CANCEL_BUTTON)); XtUnmanageChild(XmMessageBoxGetChild(err, XmDIALOG_HELP_BUTTON)); /* Center the dialog */ XtRealizeWidget(err); XtSetArg (args[0], XmNx, (Position)(WidthOfScreen(XtScreen(err)) - err->core.width) / 2); XtSetArg (args[1], XmNy, (Position)(HeightOfScreen(XtScreen(err)) - err->core.height) / 2); XtSetValues (err, args, 2); XtManageChild(err); XtAddCallback(err, XmNokCallback, UnknownUserCallback, err); XtAddCallback(err, XmNcancelCallback, UnknownUserCallback, err); XFlush(XtDisplay(toplevel)); XmUpdateDisplay(toplevel); LogFailure(); XmStringFree(okLabel); XmStringFree(message); XtFree(master); XtAppMainLoop(appContext); } /* * This is the 'Cancel' callback for the 'Invalid User' error dialog. * It removes the dialog, and then exits. */ /* ARGSUSED */ void UnknownUserCallback( Widget w, XtPointer clientData, XtPointer callData ) { Widget err = (Widget)clientData; XtUnmanageChild(err); XFlush(XtDisplay(err)); XmUpdateDisplay(err); exit(-1); } void actionStatusCallback( DtActionInvocationID id, XtPointer client_data, DtActionArg *aap, int aac, DtActionStatus status ) { switch( status ) { case DtACTION_INVOKED: /* * There may still be error dialogs to post so we must return * to mainLoop before exiting. */ if ( exitAfterInvoked ) XtAppAddTimeOut(appContext, 10 , (XtTimerCallbackProc)CheckForDone, NULL); break; case DtACTION_DONE: XtAppAddTimeOut(appContext, 10 , (XtTimerCallbackProc)CheckForDone, NULL); break; case DtACTION_FAILED: case DtACTION_CANCELED: exitStatus = 1; XtAppAddTimeOut(appContext, 10 , (XtTimerCallbackProc)CheckForDone, NULL); break; default: break; } }