diff options
author | Alan Coopersmith <Alan.Coopersmith@sun.com> | 2006-06-03 00:05:24 +0000 |
---|---|---|
committer | Alan Coopersmith <Alan.Coopersmith@sun.com> | 2006-06-03 00:05:24 +0000 |
commit | 4010a63ee6e05bee51208d667a0dc7f01f916af8 (patch) | |
tree | 570aa15c80a797d71777bb9d76166d5342efeb9d | |
parent | 1f7dab056c661af97ca7c6a7b61a87b26ca3fa36 (diff) |
Convert PAM code to use full PAM conversation. Modify greeter to allow PAM
to prompt for more than just username and password. Rely on PAM to
initialize Secure RPC & Kerberos credentials when it is being used.
(Based on work begun for Sun bug #6398796 "Solaris-10: Unable to login
thru xdm once password is aged")
-rw-r--r-- | ChangeLog | 14 | ||||
-rw-r--r-- | greeter/Login.c | 1022 | ||||
-rw-r--r-- | greeter/Login.h | 83 | ||||
-rw-r--r-- | greeter/LoginP.h | 60 | ||||
-rw-r--r-- | greeter/greet.c | 268 | ||||
-rw-r--r-- | greeter/verify.c | 126 | ||||
-rw-r--r-- | session.c | 24 |
7 files changed, 1151 insertions, 446 deletions
@@ -1,5 +1,19 @@ 2006-06-02 Alan Coopersmith <alan.coopersmith@sun.com> + * session.c: + * greeter/Login.c: + * greeter/Login.h: + * greeter/LoginP.h: + * greeter/greet.c: + * greeter/verify.c: + Convert PAM code to use full PAM conversation. Modify greeter to + allow PAM to prompt for more than just username and password. + Rely on PAM to initialize Secure RPC & Kerberos credentials when it + is being used. (Based on work begun for Sun bug #6398796 + "Solaris-10: Unable to login thru xdm once password is aged") + +2006-06-02 Alan Coopersmith <alan.coopersmith@sun.com> + * dm.c (WaitForChild): * server.c (serverPause): Drop pre-waitpid() support since all POSIX.1-1990 systems have waitpid. diff --git a/greeter/Login.c b/greeter/Login.c index cd37bd7..1c5bda3 100644 --- a/greeter/Login.c +++ b/greeter/Login.c @@ -1,4 +1,4 @@ -/* $XdotOrg: app/xdm/greeter/Login.c,v 1.4 2006/04/12 01:57:46 alanc Exp $ */ +/* $XdotOrg: app/xdm/greeter/Login.c,v 1.5 2006/04/14 02:52:02 alanc Exp $ */ /* $Xorg: Login.c,v 1.4 2001/02/09 02:05:41 xorgcvs Exp $ */ /* @@ -27,6 +27,34 @@ other dealings in this Software without prior written authorization from The Open Group. */ +/* Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons + * to whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT + * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL + * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING + * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder + * shall not be used in advertising or otherwise to promote the sale, use + * or other dealings in this Software without prior written authorization + * of the copyright holder. + */ + /* $XFree86: xc/programs/xdm/greeter/Login.c,v 3.17tsi Exp $ */ /* @@ -43,9 +71,8 @@ from The Open Group. # include <X11/Xfuncs.h> # include <stdio.h> -#ifdef XPM +# include <ctype.h> # include <time.h> -#endif /* XPM */ # include "dm.h" # include "dm_error.h" @@ -65,9 +92,24 @@ from The Open Group. #include <X11/extensions/Xinerama.h> #endif +#ifndef DEBUG +# define XDM_ASSERT(a) /* do nothing */ +#else +# if defined(__STDC__) && __STDC_VERSION__ - 0 >= 199901L +# define XDM_ASSERT(a) if (!(a)) { \ + Debug("Assertion failed in %s() at file %s line %d\n", \ + __func__, __FILE__, __LINE__); } +# else +# define XDM_ASSERT(a) if (!(a)) { \ + Debug("Assertion failed at file %s line %d\n", __FILE__, __LINE__); } +# endif +#endif + static void RedrawFail (LoginWidget w); static void ResetLogin (LoginWidget w); static void failTimeout (XtPointer client_data, XtIntervalId * id); +static void EraseCursor (LoginWidget w); +static void XorCursor (LoginWidget w); #define offset(field) XtOffsetOf(LoginRec, login.field) #define goffset(field) XtOffsetOf(WidgetRec, core.field) @@ -138,12 +180,16 @@ static XtResource resources[] = { {XtNpasswdPrompt, XtCPasswdPrompt, XtRString, sizeof (char *), offset(passwdPrompt), XtRString, "Password: "}, {XtNfail, XtCFail, XtRString, sizeof (char *), - offset(fail), XtRString, + offset(failMsg), XtRString, #if defined(sun) && defined(SVR4) - "Login incorrect or not on system console if root"}, + "Login incorrect or not on system console if root" #else - "Login incorrect"}, + "Login incorrect" #endif + }, + {XtNchangePasswdMessage, XtCChangePasswdMessage, XtRString, + sizeof (char *), offset(passwdChangeMsg), XtRString, + (XtPointer) "Password Change Required" }, {XtNfailTimeout, XtCFailTimeout, XtRInt, sizeof (int), offset(failTimeout), XtRImmediate, (XtPointer) 10}, {XtNnotifyDone, XtCCallback, XtRFunction, sizeof (XtPointer), @@ -178,27 +224,35 @@ static XtResource resources[] = { # define Y_INC(w) max (TEXT_Y_INC(w), PROMPT_Y_INC(w)) + +# define PROMPT_TEXT(w,n) ((w)->login.prompts[n].promptText) +# define DEF_PROMPT_TEXT(w,n) ((w)->login.prompts[n].defaultPrompt) +# define VALUE_TEXT(w,n) ((w)->login.prompts[n].valueText) +# define VALUE_TEXT_MAX(w,n) ((w)->login.prompts[n].valueTextMax) +# define VALUE_SHOW_START(w,n) ((w)->login.prompts[n].valueShownStart) +# define VALUE_SHOW_END(w,n) ((w)->login.prompts[n].valueShownEnd) +# define PROMPT_STATE(w,n) ((w)->login.prompts[n].state) +# define PROMPT_CURSOR(w,n) ((w)->login.prompts[n].cursor) + +# define CUR_PROMPT_CURSOR(w) PROMPT_CURSOR(w,w->login.activePrompt) + +# define CUR_PROMPT_TEXT(w, n) (PROMPT_TEXT(w,n) != NULL ? \ + PROMPT_TEXT(w,n) : DEF_PROMPT_TEXT(w,n)) + #ifndef XPM -# define LOGIN_PROMPT_W(w) (XTextWidth (w->login.promptFont,\ - w->login.namePrompt,\ - strlen (w->login.namePrompt))) -#else -# define LOGIN_PROMPT_W(w) (XTextWidth (w->login.promptFont,\ - w->login.namePrompt,\ - strlen (w->login.namePrompt)) + \ - w->login.inframeswidth) -#endif /* XPM */ -#ifndef XPM -# define PASS_PROMPT_W(w) (XTextWidth (w->login.promptFont,\ - w->login.passwdPrompt,\ - strlen (w->login.passwdPrompt))) +# define TEXT_PROMPT_W(w, m) (XTextWidth (w->login.promptFont,\ + m, strlen (m))) #else -# define PASS_PROMPT_W(w) (XTextWidth (w->login.promptFont,\ - w->login.passwdPrompt,\ - strlen (w->login.passwdPrompt)) + \ - w->login.inframeswidth) +# define TEXT_PROMPT_W(w, m) (XTextWidth (w->login.promptFont,\ + m, strlen (m)) + w->login.inframeswidth) #endif /* XPM */ -# define PROMPT_W(w) (max(LOGIN_PROMPT_W(w), PASS_PROMPT_W(w))) + +# define DEF_PROMPT_W(w,n) TEXT_PROMPT_W(w, w->login.prompts[n].defaultPrompt) +# define CUR_PROMPT_W(w,n) (max(MAX_DEF_PROMPT_W(w), PROMPT_TEXT(w,n) ? \ + TEXT_PROMPT_W(w, PROMPT_TEXT(w,n)) : 0)) + +# define MAX_DEF_PROMPT_W(w) (max(DEF_PROMPT_W(w,0), DEF_PROMPT_W(w,1))) + # define GREETING(w) ((w)->login.secure_session && !(w)->login.allow_access ?\ (w)->login.greeting : (w)->login.unsecure_greet) # define GREET_X(w) ((int)(w->core.width - XTextWidth (w->login.greetFont,\ @@ -215,34 +269,34 @@ static XtResource resources[] = { XTextWidth (w->login.greetFont,\ w->login.unsecure_greet, strlen (w->login.unsecure_greet)))) + w->login.logoWidth + (2*w->login.logoPadding) #endif /* XPM */ -# define LOGIN_X(w) (2 * PROMPT_X_INC(w)) -# define LOGIN_Y(w) (GREET_Y(w) + GREET_Y_INC(w) +\ - w->login.greetFont->max_bounds.ascent + Y_INC(w)) -# define LOGIN_W(w) (w->core.width - 6 * TEXT_X_INC(w)) -# define LOGIN_H(w) (3 * Y_INC(w) / 2) -# define LOGIN_TEXT_X(w)(LOGIN_X(w) + PROMPT_W(w)) -# define PASS_X(w) (LOGIN_X(w)) +# define PROMPT_X(w) (2 * PROMPT_X_INC(w)) +# define PROMPT_Y(w,n) ((GREET_Y(w) + GREET_Y_INC(w) +\ + w->login.greetFont->max_bounds.ascent + Y_INC(w)) + \ + (n * PROMPT_SPACE_Y(w))) +# define PROMPT_W(w) (w->core.width - 6 * TEXT_X_INC(w)) +# define PROMPT_H(w) (3 * Y_INC(w) / 2) +# define VALUE_X(w,n) (PROMPT_X(w) + CUR_PROMPT_W(w,n)) #ifndef XPM -# define PASS_Y(w) (LOGIN_Y(w) + 8 * Y_INC(w) / 5) +# define PROMPT_SPACE_Y(w) (8 * Y_INC(w) / 5) #else -# define PASS_Y(w) (LOGIN_Y(w) + 10 * Y_INC(w) / 5) +# define PROMPT_SPACE_Y(w) (10 * Y_INC(w) / 5) #endif /* XPM */ -# define PASS_W(w) (LOGIN_W(w)) -# define PASS_H(w) (LOGIN_H(w)) -# define PASS_TEXT_X(w) (PASS_X(w) + PROMPT_W(w)) -# define FAIL_X(w) ((int)(w->core.width - XTextWidth (w->login.failFont,\ - w->login.fail, strlen (w->login.fail))) / 2) -# define FAIL_Y(w) (PASS_Y(w) + 2 * FAIL_Y_INC (w) +\ +# define ERROR_X(w,m) ((int)(w->core.width - XTextWidth (w->login.failFont,\ + m, strlen (m))) / 2) +# define FAIL_X(w) ERROR_X(w, w->login.fail) +# define FAIL_Y(w) (PROMPT_Y(w,1) + 2 * FAIL_Y_INC (w) +\ w->login.failFont->max_bounds.ascent) #ifndef XPM -# define FAIL_W(w) (XTextWidth (w->login.failFont,\ - w->login.fail, strlen (w->login.fail))) +# define ERROR_W(w,m) (XTextWidth (w->login.failFont, m, strlen(m))) #else -# define FAIL_W(w) (XTextWidth (w->login.failFont,\ - w->login.fail, strlen (w->login.fail))) + w->login.logoWidth + (2*w->login.logoPadding) +# define ERROR_W(w,m) (XTextWidth (w->login.failFont, m, strlen(m))\ + + w->login.logoWidth + (2*w->login.logoPadding)) #endif /* XPM */ -# define PAD_X(w) (2 * (LOGIN_X(w) + max (GREET_X_INC(w), FAIL_X_INC(w)))) +# define FAIL_W(w) max(ERROR_W(w, w->login.failMsg), \ + ERROR_W(w, w->login.passwdChangeMsg)) + +# define PAD_X(w) (2 * (PROMPT_X(w) + max (GREET_X_INC(w), FAIL_X_INC(w)))) # define PAD_Y(w) (max (max (Y_INC(w), GREET_Y_INC(w)),\ FAIL_Y_INC(w))) @@ -252,32 +306,88 @@ static inline int max (int a, int b) { return a > b ? a : b; } #endif static void -EraseName (LoginWidget w, int cursor) +realizeValue (LoginWidget w, int cursor, int promptNum, GC gc) { - int x; + loginPromptState state = w->login.prompts[promptNum].state; + char *text = VALUE_TEXT(w, promptNum); + int x, y, height, width, curoff; + + XDM_ASSERT(promptNum >= 0 && promptNum <= LAST_PROMPT); + + x = VALUE_X (w,promptNum); + y = PROMPT_Y (w,promptNum); + + height = PROMPT_H(w); + width = PROMPT_W(w) - x - 3; + +#ifdef XPM + height -= (w->login.inframeswidth * 2); + width -= (w->login.inframeswidth * 2) + + (w->login.logoWidth + 2*(w->login.logoPadding)); +#endif + if (cursor > VALUE_SHOW_START(w, promptNum)) + curoff = XTextWidth (w->login.font, text, cursor); + else + curoff = 0; - x = LOGIN_TEXT_X (w); - if (cursor > 0) - x += XTextWidth (w->login.font, w->login.data.name, cursor); - XDrawString (XtDisplay(w), XtWindow (w), w->login.bgGC, x, LOGIN_Y(w), - w->login.data.name + cursor, strlen (w->login.data.name + cursor)); + + if (gc == w->login.bgGC) { + if (curoff < width) { + XFillRectangle (XtDisplay (w), XtWindow (w), gc, + x + curoff, y - TEXT_Y_INC(w), + width - curoff, height); + } + } else if ((state == LOGIN_PROMPT_ECHO_ON) || (state == LOGIN_TEXT_INFO)) { + int textwidth; + int offset = max(cursor, VALUE_SHOW_START(w, promptNum)); + int textlen = strlen (text + offset); + + textwidth = XTextWidth (w->login.font, text + offset, textlen); + + if (textwidth > (width - curoff)) { + /* Recalculate amount of text that can fit in field */ + offset = VALUE_SHOW_START(w, promptNum); + textlen = strlen (text + offset); + + do + { + if (offset < PROMPT_CURSOR(w, promptNum)) { + offset++; + } + textlen--; + textwidth = XTextWidth (w->login.font, text + offset, textlen); + } while ((textlen > 0) && (textwidth > width)); + + VALUE_SHOW_START(w, promptNum) = offset; + VALUE_SHOW_END(w, promptNum) = offset + textlen; + + /* Erase old string */ + XFillRectangle (XtDisplay (w), XtWindow (w), w->login.bgGC, + x, y - TEXT_Y_INC(w), width, height); + + XDrawString (XtDisplay(w), XtWindow (w), gc, + x, y, text + offset, textlen); + } else { + XDrawString (XtDisplay(w), XtWindow (w), gc, + x + curoff, y, text + offset, textlen); + } + } } static void -DrawName (LoginWidget w, int cursor) +EraseValue (LoginWidget w, int cursor, int promptNum) { - int x; - - x = LOGIN_TEXT_X (w); - if (cursor > 0) - x += XTextWidth (w->login.font, w->login.data.name, cursor); - XDrawString (XtDisplay(w), XtWindow (w), w->login.textGC, x, LOGIN_Y(w), - w->login.data.name + cursor, strlen (w->login.data.name + cursor)); + realizeValue(w, cursor, promptNum, w->login.bgGC); +} +static void +DrawValue (LoginWidget w, int cursor, int promptNum) +{ + realizeValue(w, cursor, promptNum, w->login.textGC); #ifdef XPM - /*as good a place as any Caolan begin*/ - w->login.lastEventTime = time(NULL); - /*as good a place as any Caolan end*/ + /*as good a place as any Caolan begin*/ + w->login.lastEventTime = time(NULL); + /*as good a place as any Caolan end*/ #endif /* XPM */ } @@ -287,28 +397,43 @@ realizeCursor (LoginWidget w, GC gc) int x, y; int height, width; - switch (w->login.state) { - case GET_NAME: - x = LOGIN_TEXT_X (w); - y = LOGIN_Y (w); - height = w->login.font->max_bounds.ascent + w->login.font->max_bounds.descent; - width = 1; - if (w->login.cursor > 0) - x += XTextWidth (w->login.font, w->login.data.name, w->login.cursor); + static int lastx, lasty; + static struct timeval lastFlash; + struct timeval now, timeout; + int sinceLastFlash; + + if (w->login.state != PROMPTING) { + return; + } + + x = VALUE_X (w, w->login.activePrompt); + y = PROMPT_Y (w, w->login.activePrompt); + height = w->login.font->max_bounds.ascent + w->login.font->max_bounds.descent; + width = 1; + + switch (PROMPT_STATE(w, w->login.activePrompt)) { + case LOGIN_PROMPT_NOT_SHOWN: + case LOGIN_TEXT_INFO: + return; + case LOGIN_PROMPT_ECHO_ON: + if (CUR_PROMPT_CURSOR(w) > 0) { + x += XTextWidth (w->login.font, + VALUE_TEXT(w, w->login.activePrompt) + + VALUE_SHOW_START(w, w->login.activePrompt), + PROMPT_CURSOR(w, w->login.activePrompt) + - VALUE_SHOW_START(w, w->login.activePrompt) ); + } break; - case GET_PASSWD: - x = PASS_TEXT_X (w); - y = PASS_Y (w); - height = w->login.font->max_bounds.ascent + w->login.font->max_bounds.descent; - width = 1; + case LOGIN_PROMPT_ECHO_OFF: + /* Nothing special needed */ break; - default: - return; } - XFillRectangle (XtDisplay (w), XtWindow (w), gc, + #ifndef XPM + XFillRectangle (XtDisplay (w), XtWindow (w), gc, x, y - w->login.font->max_bounds.ascent, width, height); #else + XFillRectangle (XtDisplay (w), XtWindow (w), gc, x, y+1 - w->login.font->max_bounds.ascent, width, height-1); XDrawPoint (XtDisplay (w), XtWindow (w), gc, x-1 , y - w->login.font->max_bounds.ascent); @@ -327,19 +452,42 @@ realizeCursor (LoginWidget w, GC gc) XDrawPoint (XtDisplay (w), XtWindow (w), gc, x+2 , y - w->login.font->max_bounds.ascent+height); #endif /* XPM */ + + + /* Force cursor to flash briefly to give user feedback */ +#define FLASH_MILLIS 100000 /* 0.10 seconds */ +#define MILLIS_PER_SEC 1000000 + X_GETTIMEOFDAY (&now); + + if ((lastx == x) && (lasty == y)) { + if (lastFlash.tv_sec == 0) + sinceLastFlash = 0; + else if ((lastFlash.tv_sec + 1) == now.tv_sec) + sinceLastFlash = + (now.tv_usec + MILLIS_PER_SEC) - lastFlash.tv_usec; + else if (lastFlash.tv_sec == now.tv_sec) + sinceLastFlash = now.tv_usec - lastFlash.tv_usec; + else + sinceLastFlash = (now.tv_sec - lastFlash.tv_sec) * MILLIS_PER_SEC; + + if (sinceLastFlash < FLASH_MILLIS) { + timeout.tv_sec = 0; + timeout.tv_usec = FLASH_MILLIS - sinceLastFlash; + select(0, NULL, NULL, NULL, &timeout); + } + } else { + lastx = x; lasty = y; + } + XFlush (XtDisplay(w)); + X_GETTIMEOFDAY (&lastFlash); } static void EraseFail (LoginWidget w) { - int x = FAIL_X(w); - int y = FAIL_Y(w); - XSetForeground (XtDisplay (w), w->login.failGC, w->core.background_pixel); - XDrawString (XtDisplay (w), XtWindow (w), w->login.failGC, - x, y, - w->login.fail, strlen (w->login.fail)); + RedrawFail(w); w->login.failUp = 0; XSetForeground (XtDisplay (w), w->login.failGC, w->login.failpixel); @@ -370,6 +518,7 @@ static void failTimeout (XtPointer client_data, XtIntervalId * id) LoginWidget w = (LoginWidget)client_data; Debug ("failTimeout\n"); + w->login.interval_id = 0; EraseFail (w); } @@ -382,14 +531,7 @@ DrawFail (Widget ctx) XorCursor (w); ResetLogin (w); XorCursor (w); - w->login.failUp = 1; - RedrawFail (w); - if (w->login.failTimeout > 0) { - Debug ("failTimeout: %d\n", w->login.failTimeout); - XtAppAddTimeOut(XtWidgetToApplicationContext ((Widget)w), - w->login.failTimeout * 1000, - failTimeout, (XtPointer) w); - } + ErrorMessage(ctx, w->login.failMsg, True); } static void @@ -397,18 +539,104 @@ RedrawFail (LoginWidget w) { int x = FAIL_X(w); int y = FAIL_Y(w); + int maxw = w->core.width - PAD_X(w); + + if (w->login.failUp) { + Debug("RedrawFail('%s')\n", w->login.fail); + + if (ERROR_W(w, w->login.fail) > maxw) { + /* Too long to fit on one line, break into multiple lines */ + char *tempCopy = strdup(w->login.fail); + if (tempCopy != NULL) { + char *start, *next; + char lastspace; + + y = PROMPT_Y(w,LAST_PROMPT) + (2 * PROMPT_Y_INC(w)); + + for (start = next = tempCopy; start != NULL ; start = next) { + /* search for longest string broken by whitespace that + will fit on a single line */ + do { + if (next != start) { + *next = lastspace; + } + for (next = next + 1; + (*next != '\0') && !isspace(*next) ; next++) + { + /* this loop intentionally left blank */ + } + if (*next != '\0') { + lastspace = *next; + *next = '\0'; + } else { + next = NULL; + } + } while ((next != NULL) && ERROR_W(w, start) < maxw); + + x = ERROR_X(w, start); + XDrawString (XtDisplay (w), XtWindow (w), w->login.failGC, + x, y, start, strlen(start)); + + if (next != NULL) { + next++; + y += FAIL_Y_INC(w); + } + } + free(tempCopy); + return; + } + /* if strdup failed, fall through to draw all at once, even + though we know it can't all fit */ + LogOutOfMem("RedrawFail"); + } - if (w->login.failUp) - XDrawString (XtDisplay (w), XtWindow (w), w->login.failGC, - x, y, - w->login.fail, strlen (w->login.fail)); + XDrawString (XtDisplay (w), XtWindow (w), w->login.failGC, + x, y, + w->login.fail, strlen (w->login.fail)); + } +} + +void +ErrorMessage(Widget ctx, const char *message, Bool timeout) +{ + LoginWidget w = (LoginWidget) ctx; + +/* Debug("ErrorMessage: %s\n", message); */ + if (w->login.interval_id != 0) { + XtRemoveTimeOut(w->login.interval_id); + w->login.interval_id = 0; + } + RemoveFail(w); + if (w->login.fail != w->login.failMsg) + free(w->login.fail); + w->login.fail = strdup(message); + if (w->login.fail == NULL) + w->login.fail = (char *) w->login.failMsg; + w->login.failUp = 1; + RedrawFail (w); + if (timeout && (w->login.failTimeout > 0)) { + Debug ("failTimeout: %d\n", w->login.failTimeout); + w->login.interval_id = + XtAppAddTimeOut(XtWidgetToApplicationContext ((Widget)w), + w->login.failTimeout * 1000, + failTimeout, (XtPointer) w); + } +} + +void +ShowChangePasswdMessage(Widget ctx) +{ + LoginWidget w = (LoginWidget) ctx; + + ErrorMessage(ctx, w->login.passwdChangeMsg, False); } static void draw_it (LoginWidget w) { + int p; #ifdef XPM - int i,in_frame_x,in_login_y,in_pass_y,in_width,in_height; + int i; int gr_line_x, gr_line_y, gr_line_w; #endif /* XPM */ @@ -444,50 +672,47 @@ draw_it (LoginWidget w) gr_line_x, gr_line_y + 2*(w->login.inframeswidth) -i, gr_line_x+gr_line_w, gr_line_y + 2*(w->login.inframeswidth) -i); } - - in_frame_x = LOGIN_TEXT_X(w) - w->login.inframeswidth - 3; - in_login_y = LOGIN_Y(w) - w->login.inframeswidth - 1 - TEXT_Y_INC(w); - in_pass_y = PASS_Y(w) - w->login.inframeswidth - 1 - TEXT_Y_INC(w); - - in_width = LOGIN_W(w) - PROMPT_W(w) - - (w->login.logoWidth + 2*(w->login.logoPadding)); - in_height = LOGIN_H(w) + w->login.inframeswidth + 2; - for(i=1;i<=(w->login.inframeswidth);i++) + for (p = 0; p < NUM_PROMPTS ; p++) { - /* Make top/left sides */ - XDrawLine(XtDisplay (w), XtWindow (w), w->login.shdGC, - in_frame_x + i-1, in_login_y + i-1, - in_frame_x + in_width-i, in_login_y + i-1); - - XDrawLine(XtDisplay (w), XtWindow (w), w->login.shdGC, - in_frame_x + i-1, in_login_y + i-1, - in_frame_x + i-1, in_login_y + in_height-i); - - XDrawLine(XtDisplay (w), XtWindow (w), w->login.hiGC, - in_frame_x + in_width-i, in_login_y + i-1, - in_frame_x + in_width-i, in_login_y + in_height-i); - - XDrawLine(XtDisplay (w), XtWindow (w), w->login.hiGC, - in_frame_x + i-1, in_login_y + in_height-i, - in_frame_x + in_width-i, in_login_y + in_height-i); - - /* Make bottom/right sides */ - XDrawLine(XtDisplay (w), XtWindow (w), w->login.shdGC, - in_frame_x + i-1, in_pass_y + i-1, - in_frame_x + in_width-i, in_pass_y + i-1); - - XDrawLine(XtDisplay (w), XtWindow (w), w->login.shdGC, - in_frame_x + i-1, in_pass_y + i-1, - in_frame_x + i-1, in_pass_y + in_height-i); + int in_frame_x = VALUE_X(w,p) - w->login.inframeswidth - 3; + int in_frame_y + = PROMPT_Y(w,p) - w->login.inframeswidth - 1 - TEXT_Y_INC(w); + + int in_width = PROMPT_W(w) - VALUE_X(w,p) - + (w->login.logoWidth + 2*(w->login.logoPadding)); + int in_height = PROMPT_H(w) + w->login.inframeswidth + 2; + + GC topLeftGC, botRightGC; + + if ((PROMPT_STATE(w, p) == LOGIN_PROMPT_ECHO_ON) || + (PROMPT_STATE(w, p) == LOGIN_PROMPT_ECHO_OFF)) { + topLeftGC = w->login.shdGC; + botRightGC = w->login.hiGC; + } else { + topLeftGC = botRightGC = w->login.bgGC; + } - XDrawLine(XtDisplay (w), XtWindow (w), w->login.hiGC, - in_frame_x + in_width-i, in_pass_y + i-1, - in_frame_x + in_width-i, in_pass_y + in_height-i); - - XDrawLine(XtDisplay (w), XtWindow (w), w->login.hiGC, - in_frame_x + i-1, in_pass_y + in_height-i, - in_frame_x + in_width-i, in_pass_y + in_height-i); + for (i=1; i<=(w->login.inframeswidth); i++) + { + /* Make top/left sides */ + XDrawLine(XtDisplay (w), XtWindow (w), topLeftGC, + in_frame_x + i-1, in_frame_y + i-1, + in_frame_x + in_width-i, in_frame_y + i-1); + + XDrawLine(XtDisplay (w), XtWindow (w), topLeftGC, + in_frame_x + i-1, in_frame_y + i-1, + in_frame_x + i-1, in_frame_y + in_height-i); + + /* Make bottom/right sides */ + XDrawLine(XtDisplay (w), XtWindow (w), botRightGC, + in_frame_x + in_width-i, in_frame_y + i-1, + in_frame_x + in_width-i, in_frame_y + in_height-i); + + XDrawLine(XtDisplay (w), XtWindow (w), botRightGC, + in_frame_x + i-1, in_frame_y + in_height-i, + in_frame_x + in_width-i, in_frame_y + in_height-i); + } } #endif /* XPM */ @@ -501,14 +726,15 @@ draw_it (LoginWidget w) GREET_Y(w), #endif /* XPM */ GREETING(w), strlen (GREETING(w))); - XDrawString (XtDisplay (w), XtWindow (w), w->login.promptGC, - LOGIN_X(w), LOGIN_Y(w), - w->login.namePrompt, strlen (w->login.namePrompt)); - XDrawString (XtDisplay (w), XtWindow (w), w->login.promptGC, - PASS_X(w), PASS_Y(w), - w->login.passwdPrompt, strlen (w->login.passwdPrompt)); + for (p = 0; p < NUM_PROMPTS ; p++) { + if (PROMPT_STATE(w, p) != LOGIN_PROMPT_NOT_SHOWN) { + XDrawString (XtDisplay (w), XtWindow (w), w->login.promptGC, + PROMPT_X(w), PROMPT_Y(w,p), + CUR_PROMPT_TEXT(w,p), strlen (CUR_PROMPT_TEXT(w,p))); + DrawValue (w, 0, p); + } + } RedrawFail (w); - DrawName (w, 0); XorCursor (w); /* * The GrabKeyboard here is needed only because of @@ -526,28 +752,189 @@ draw_it (LoginWidget w) } } +/* Returns 0 on success, -1 on failure */ +int +SetPrompt (Widget ctx, int promptNum, const char *message, + loginPromptState state, Boolean minimumTime) +{ + LoginWidget w = (LoginWidget) ctx; + char *prompt; + int messageLen, e; + const char *stateNames[4] = { + "LOGIN_PROMPT_NOT_SHOWN", "LOGIN_PROMPT_ECHO_ON", + "LOGIN_PROMPT_ECHO_OFF", "LOGIN_TEXT_INFO" }; + loginPromptState priorState; + + Debug("SetPrompt(%d, %s, %s(%d))\n", promptNum, + message ? message : "<NULL>", stateNames[state], state); + + XDM_ASSERT(promptNum >= 0 && promptNum <= LAST_PROMPT); + + if (PROMPT_TEXT(w, promptNum) != NULL) { + XtFree(PROMPT_TEXT(w, promptNum)); + PROMPT_TEXT(w, promptNum) = NULL; + } + + priorState = PROMPT_STATE(w, promptNum); + PROMPT_STATE(w, promptNum) = state; + + if (state == LOGIN_PROMPT_NOT_SHOWN) { + return 0; + } + + if (message == NULL) { + message = DEF_PROMPT_TEXT(w, promptNum); + } + + messageLen = strlen(message); + + prompt = XtMalloc(messageLen + 3); + if (prompt == NULL) { + LogOutOfMem ("SetPrompt"); + return -1; + } + + strncpy(prompt, message, messageLen); + + /* Make sure text prompts have at least two spaces at end */ + e = messageLen; + + if (!isspace(message[messageLen - 2])) { + prompt[e] = ' '; + e++; + } + if (!isspace(message[messageLen - 1])) { + prompt[e] = ' '; + e++; + } + prompt[e] = '\0'; + + PROMPT_TEXT(w, promptNum) = prompt; + + if (w->login.state == INITIALIZING) { + return 0; + } + + if ((priorState == LOGIN_TEXT_INFO) && (w->login.msgTimeout != 0)) { + time_t now = time(NULL); + int timeleft = w->login.msgTimeout - now; + + if (timeleft > 0) { + sleep(timeleft); + } + w->login.msgTimeout = 0; + } + + if (state == LOGIN_TEXT_INFO) { + if (minimumTime) { + time_t now = time(NULL); + w->login.msgTimeout = now + w->login.failTimeout; + } + w->login.state = SHOW_MESSAGE; + } else { + w->login.activePrompt = promptNum; + w->login.state = PROMPTING; + } + + PROMPT_CURSOR(w, promptNum) = 0; + XClearArea (XtDisplay(w), XtWindow(w), 0, 0, 0, 0, FALSE); + draw_it(w); + return 0; +} + +const char *GetPrompt(Widget ctx, int promptNum) +{ + LoginWidget w = (LoginWidget) ctx; + + XDM_ASSERT(promptNum >= 0 && promptNum <= LAST_PROMPT); + + return CUR_PROMPT_TEXT(w,promptNum); +} + +int +SetValue(Widget ctx, int promptNum, char *value) +{ + LoginWidget w = (LoginWidget) ctx; + + XDM_ASSERT(promptNum >= 0 && promptNum <= LAST_PROMPT); + + if ((promptNum < 0) || (promptNum > LAST_PROMPT)) + return -1; + + XDM_ASSERT(VALUE_TEXT(w, promptNum) != NULL); + + if (VALUE_TEXT(w, promptNum) == NULL) + return -1; + + if (value == NULL) { + bzero(VALUE_TEXT(w, promptNum), VALUE_TEXT_MAX(w, promptNum)); + } else { + strncpy(VALUE_TEXT(w, promptNum), value, VALUE_TEXT_MAX(w, promptNum)); + VALUE_TEXT(w, promptNum)[VALUE_TEXT_MAX(w, promptNum)] = '\0'; + } + + VALUE_SHOW_START(w, promptNum) = 0; + VALUE_SHOW_END(w, promptNum) = 0; + PROMPT_CURSOR(w, promptNum) = 0; + + return 0; +} + +const char * +GetValue(Widget ctx, int promptNum) +{ + LoginWidget w = (LoginWidget) ctx; + + XDM_ASSERT(promptNum >= 0 && promptNum <= LAST_PROMPT); + + if ((promptNum < 0) || (promptNum > LAST_PROMPT)) + return NULL; + + XDM_ASSERT(VALUE_TEXT(w, promptNum) != NULL); + + return VALUE_TEXT(w, promptNum); +} + + +static void +realizeDeleteChar (LoginWidget ctx) +{ + if (ctx->login.state == PROMPTING) { + int promptNum = ctx->login.activePrompt; + int redrawFrom = PROMPT_CURSOR(ctx, promptNum); + + if (PROMPT_CURSOR(ctx,promptNum) < (int)strlen(VALUE_TEXT(ctx,promptNum))) { + if (redrawFrom < VALUE_SHOW_START(ctx, ctx->login.activePrompt)) { + redrawFrom = 0; + EraseValue (ctx, redrawFrom, promptNum); + VALUE_SHOW_START(ctx, ctx->login.activePrompt) + = PROMPT_CURSOR(ctx,promptNum); + } else { + EraseValue (ctx, redrawFrom, promptNum); + } + strcpy(VALUE_TEXT(ctx, promptNum) + PROMPT_CURSOR(ctx, promptNum), + VALUE_TEXT(ctx, promptNum) + PROMPT_CURSOR(ctx, promptNum) + 1); + DrawValue (ctx, redrawFrom, promptNum); + } + } +} + /*ARGSUSED*/ static void DeleteBackwardChar (Widget ctxw, XEvent *event, String *params, Cardinal *num_params) { LoginWidget ctx = (LoginWidget)ctxw; - XorCursor (ctx); RemoveFail (ctx); - if (ctx->login.cursor > 0) { - ctx->login.cursor--; - switch (ctx->login.state) { - case GET_NAME: - EraseName (ctx, ctx->login.cursor); - strcpy (ctx->login.data.name + ctx->login.cursor, - ctx->login.data.name + ctx->login.cursor + 1); - DrawName (ctx, ctx->login.cursor); - break; - case GET_PASSWD: - strcpy (ctx->login.data.passwd + ctx->login.cursor, - ctx->login.data.passwd + ctx->login.cursor + 1); - break; - } + + if (ctx->login.state != PROMPTING) { + return; + } + + XorCursor (ctx); + if (CUR_PROMPT_CURSOR(ctx) > 0) { + CUR_PROMPT_CURSOR(ctx) -= 1; + realizeDeleteChar(ctx); } XorCursor (ctx); } @@ -558,24 +945,14 @@ DeleteForwardChar (Widget ctxw, XEvent *event, String *params, Cardinal *num_par { LoginWidget ctx = (LoginWidget)ctxw; - XorCursor (ctx); RemoveFail (ctx); - switch (ctx->login.state) { - case GET_NAME: - if (ctx->login.cursor < (int)strlen (ctx->login.data.name)) { - EraseName (ctx, ctx->login.cursor); - strcpy (ctx->login.data.name + ctx->login.cursor, - ctx->login.data.name + ctx->login.cursor + 1); - DrawName (ctx, ctx->login.cursor); - } - break; - case GET_PASSWD: - if (ctx->login.cursor < (int)strlen (ctx->login.data.passwd)) { - strcpy (ctx->login.data.passwd + ctx->login.cursor, - ctx->login.data.passwd + ctx->login.cursor + 1); - } - break; + + if (ctx->login.state != PROMPTING) { + return; } + + XorCursor (ctx); + realizeDeleteChar(ctx); XorCursor (ctx); } @@ -589,10 +966,21 @@ MoveBackwardChar ( { LoginWidget ctx = (LoginWidget)ctxw; - XorCursor (ctx); RemoveFail (ctx); - if (ctx->login.cursor > 0) - ctx->login.cursor--; + + if (ctx->login.state != PROMPTING) { + return; + } + + XorCursor (ctx); + if (CUR_PROMPT_CURSOR(ctx) > 0) + CUR_PROMPT_CURSOR(ctx) -= 1; + if (CUR_PROMPT_CURSOR(ctx) < VALUE_SHOW_START(ctx, ctx->login.activePrompt)) { + EraseValue(ctx, 0, ctx->login.activePrompt); + VALUE_SHOW_START(ctx, ctx->login.activePrompt) + = CUR_PROMPT_CURSOR(ctx); + DrawValue(ctx, 0, ctx->login.activePrompt); + } XorCursor (ctx); } @@ -606,17 +994,21 @@ MoveForwardChar ( { LoginWidget ctx = (LoginWidget)ctxw; - XorCursor (ctx); RemoveFail (ctx); - switch (ctx->login.state) { - case GET_NAME: - if (ctx->login.cursor < (int)strlen(ctx->login.data.name)) - ++ctx->login.cursor; - break; - case GET_PASSWD: - if (ctx->login.cursor < (int)strlen(ctx->login.data.passwd)) - ++ctx->login.cursor; - break; + + if (ctx->login.state != PROMPTING) { + return; + } + + XorCursor (ctx); + if (CUR_PROMPT_CURSOR(ctx) < + (int)strlen(VALUE_TEXT(ctx,ctx->login.activePrompt))) { + CUR_PROMPT_CURSOR(ctx) += 1; + if (VALUE_SHOW_END(ctx, ctx->login.activePrompt) + < CUR_PROMPT_CURSOR(ctx)) { + EraseValue(ctx, 0, ctx->login.activePrompt); + DrawValue(ctx, 0, ctx->login.activePrompt); + } } XorCursor (ctx); } @@ -631,9 +1023,19 @@ MoveToBegining ( { LoginWidget ctx = (LoginWidget)ctxw; - XorCursor (ctx); RemoveFail (ctx); - ctx->login.cursor = 0; + + if (ctx->login.state != PROMPTING) { + return; + } + + XorCursor (ctx); + CUR_PROMPT_CURSOR(ctx) = 0; + if (VALUE_SHOW_START(ctx, ctx->login.activePrompt) > 0) { + EraseValue(ctx, 0, ctx->login.activePrompt); + VALUE_SHOW_START(ctx, ctx->login.activePrompt) = 0; + DrawValue(ctx, 0, ctx->login.activePrompt); + } XorCursor (ctx); } @@ -647,15 +1049,17 @@ MoveToEnd ( { LoginWidget ctx = (LoginWidget)ctxw; - XorCursor (ctx); RemoveFail (ctx); - switch (ctx->login.state) { - case GET_NAME: - ctx->login.cursor = strlen (ctx->login.data.name); - break; - case GET_PASSWD: - ctx->login.cursor = strlen (ctx->login.data.passwd); - break; + + if (ctx->login.state != PROMPTING) { + return; + } + + XorCursor (ctx); + CUR_PROMPT_CURSOR(ctx) = strlen (VALUE_TEXT(ctx, ctx->login.activePrompt)); + if (VALUE_SHOW_END(ctx, ctx->login.activePrompt) < CUR_PROMPT_CURSOR(ctx)) { + EraseValue(ctx, 0, ctx->login.activePrompt); + DrawValue(ctx, 0, ctx->login.activePrompt); } XorCursor (ctx); } @@ -670,17 +1074,18 @@ EraseToEndOfLine ( { LoginWidget ctx = (LoginWidget)ctxw; - XorCursor (ctx); RemoveFail (ctx); - switch (ctx->login.state) { - case GET_NAME: - EraseName (ctx, ctx->login.cursor); - bzero (ctx->login.data.name, NAME_LEN); - break; - case GET_PASSWD: - bzero (ctx->login.data.passwd, PASSWORD_LEN); - break; + + if (ctx->login.state != PROMPTING) { + return; } + + XorCursor (ctx); + EraseValue (ctx, CUR_PROMPT_CURSOR(ctx), ctx->login.activePrompt); + bzero(VALUE_TEXT(ctx, ctx->login.activePrompt) + + CUR_PROMPT_CURSOR(ctx), + VALUE_TEXT_MAX(ctx, ctx->login.activePrompt) - + CUR_PROMPT_CURSOR(ctx)); XorCursor (ctx); } @@ -705,45 +1110,64 @@ FinishField ( Cardinal *num_params) { LoginWidget ctx = (LoginWidget)ctxw; + int promptNum = ctx->login.activePrompt; + int nextPrompt; - XorCursor (ctx); RemoveFail (ctx); - switch (ctx->login.state) { - case GET_NAME: - ctx->login.state = GET_PASSWD; - ctx->login.cursor = 0; - break; - case GET_PASSWD: + + if (ctx->login.state != PROMPTING) { + return; + } + + XorCursor (ctx); + + for (nextPrompt = promptNum + 1; nextPrompt <= LAST_PROMPT; nextPrompt++) { + if ((PROMPT_STATE(ctx, nextPrompt) == LOGIN_PROMPT_ECHO_ON) || + (PROMPT_STATE(ctx, nextPrompt) == LOGIN_PROMPT_ECHO_OFF)) { + ctx->login.activePrompt = nextPrompt; + break; + } + } + if (nextPrompt > LAST_PROMPT) { ctx->login.state = DONE; - ctx->login.cursor = 0; (*ctx->login.notify_done) (ctx, &ctx->login.data, NOTIFY_OK); - break; + Debug("FinishField #%d: now DONE\n", promptNum); + } else { + Debug("FinishField #%d: %d next\n", promptNum, nextPrompt); } + XorCursor (ctx); } -#ifdef XPM /*ARGSUSED*/ static void TabField(Widget ctxw, XEvent *event, String *params, Cardinal *num_params) { LoginWidget ctx = (LoginWidget)ctxw; + int promptNum = ctx->login.activePrompt; + int nextPrompt; - XorCursor (ctx); RemoveFail (ctx); - switch (ctx->login.state) { - case GET_NAME: - ctx->login.state = GET_PASSWD; - ctx->login.cursor = 0; - break; - case GET_PASSWD: - ctx->login.state = GET_NAME; - ctx->login.cursor = 0; - break; + + if (ctx->login.state != PROMPTING) { + return; + } + + XorCursor (ctx); + + for (nextPrompt = promptNum + 1; nextPrompt != promptNum; nextPrompt++) { + if (nextPrompt > LAST_PROMPT) { + nextPrompt = 0; + } + + if ((PROMPT_STATE(ctx, nextPrompt) == LOGIN_PROMPT_ECHO_ON) || + (PROMPT_STATE(ctx, nextPrompt) == LOGIN_PROMPT_ECHO_OFF)) { + ctx->login.activePrompt = nextPrompt; + break; + } } XorCursor (ctx); } -#endif /* XPM */ /*ARGSUSED*/ static void @@ -800,7 +1224,6 @@ RestartSession ( XorCursor (ctx); RemoveFail (ctx); ctx->login.state = DONE; - ctx->login.cursor = 0; (*ctx->login.notify_done) (ctx, &ctx->login.data, NOTIFY_RESTART); XorCursor (ctx); } @@ -818,7 +1241,6 @@ AbortSession ( XorCursor (ctx); RemoveFail (ctx); ctx->login.state = DONE; - ctx->login.cursor = 0; (*ctx->login.notify_done) (ctx, &ctx->login.data, NOTIFY_ABORT); XorCursor (ctx); } @@ -836,7 +1258,6 @@ AbortDisplay ( XorCursor (ctx); RemoveFail (ctx); ctx->login.state = DONE; - ctx->login.cursor = 0; (*ctx->login.notify_done) (ctx, &ctx->login.data, NOTIFY_ABORT_DISPLAY); XorCursor (ctx); } @@ -844,11 +1265,16 @@ AbortDisplay ( static void ResetLogin (LoginWidget w) { - EraseName (w, 0); - w->login.cursor = 0; - bzero (w->login.data.name, NAME_LEN); - bzero (w->login.data.passwd, PASSWORD_LEN); - w->login.state = GET_NAME; + int i; + + for (i = 0; i < NUM_PROMPTS ; i++) { + EraseValue(w, 0, i); + bzero(VALUE_TEXT(w, i), VALUE_TEXT_MAX(w, i)); + VALUE_SHOW_START(w, i) = 0; + PROMPT_CURSOR(w, i) = 0; + } + w->login.state = PROMPTING; + w->login.activePrompt = 0; } static void @@ -891,11 +1317,7 @@ InsertChar ( LoginWidget ctx = (LoginWidget)ctxw; char strbuf[128]; -#ifndef XPM - int len; -#else - int len,pixels; -#endif /* XPM */ + int len, promptNum = ctx->login.activePrompt;; KeySym keysym = 0; if (ctx->login.xic) { @@ -909,14 +1331,6 @@ InsertChar ( } strbuf[len] = '\0'; -#ifdef XPM - pixels = 3 + ctx->login.font->max_bounds.width * len + - XTextWidth(ctx->login.font, - ctx->login.data.name, - strlen(ctx->login.data.name)); - /* pixels to be added */ -#endif /* XPM */ - /* * Note: You can override this default key handling * by the settings in the translation table @@ -963,52 +1377,27 @@ InsertChar ( break; } - switch (ctx->login.state) { - case GET_NAME: -#ifndef XPM - if (len + (int)strlen(ctx->login.data.name) >= NAME_LEN - 1) -#else - if ( - (len + (int)strlen(ctx->login.data.name) >= NAME_LEN - 1)/* && - (pixels <= LOGIN_W(ctx) - PROMPT_W(ctx))*/ - ) -#endif /* XPM */ - len = NAME_LEN - strlen(ctx->login.data.name) - 2; - case GET_PASSWD: - if (len + (int)strlen(ctx->login.data.passwd) >= PASSWORD_LEN - 1) - len = PASSWORD_LEN - strlen(ctx->login.data.passwd) - 2; + if (ctx->login.state == PROMPTING) { + if ((len + (int)strlen(VALUE_TEXT(ctx, promptNum)) >= + (VALUE_TEXT_MAX(ctx,promptNum) - 1))) { + len = VALUE_TEXT_MAX(ctx,promptNum) - + strlen(VALUE_TEXT(ctx, promptNum)) - 2; + } } -#ifndef XPM - if (len == 0) -#else - if (len == 0 || pixels >= LOGIN_W(ctx) - PROMPT_W(ctx)) -#endif /* XPM */ - return; - XorCursor (ctx); + EraseCursor (ctx); RemoveFail (ctx); - switch (ctx->login.state) { - case GET_NAME: - EraseName (ctx, ctx->login.cursor); - memmove( ctx->login.data.name + ctx->login.cursor + len, - ctx->login.data.name + ctx->login.cursor, - strlen (ctx->login.data.name + ctx->login.cursor) + 1); - memmove( ctx->login.data.name + ctx->login.cursor, strbuf, len); - DrawName (ctx, ctx->login.cursor); - ctx->login.cursor += len; - break; - case GET_PASSWD: - memmove( ctx->login.data.passwd + ctx->login.cursor + len, - ctx->login.data.passwd + ctx->login.cursor, - strlen (ctx->login.data.passwd + ctx->login.cursor) + 1); - memmove( ctx->login.data.passwd + ctx->login.cursor, strbuf, len); - ctx->login.cursor += len; - -#ifdef XPM - /*as good a place as any Caolan begin*/ - ctx->login.lastEventTime = time(NULL); - /*as good a place as any Caolan end*/ -#endif /* XPM */ - break; + if (len != 0) + { + if (ctx->login.state == PROMPTING) { + EraseValue (ctx, PROMPT_CURSOR(ctx, promptNum), promptNum); + memmove(VALUE_TEXT(ctx, promptNum) + PROMPT_CURSOR(ctx, promptNum) + len, + VALUE_TEXT(ctx, promptNum) + PROMPT_CURSOR(ctx, promptNum), + strlen (VALUE_TEXT(ctx, promptNum) + PROMPT_CURSOR(ctx, promptNum))+1); + memmove(VALUE_TEXT(ctx, promptNum) + PROMPT_CURSOR(ctx, promptNum), + strbuf, len); + DrawValue (ctx, PROMPT_CURSOR(ctx, promptNum), promptNum); + PROMPT_CURSOR(ctx, promptNum) += len; + } } XorCursor (ctx); } @@ -1032,6 +1421,7 @@ static void Initialize ( #ifdef XPM int rv = 0; + XRectangle cliprect[1]; myXGCV.foreground = w->login.hipixel; myXGCV.background = w->core.background_pixel; @@ -1155,11 +1545,29 @@ static void Initialize ( SkipXpmLoad: #endif /* XPM */ - bzero (w->login.data.name, NAME_LEN); - bzero (w->login.data.passwd, PASSWORD_LEN); - w->login.state = GET_NAME; - w->login.cursor = 0; + w->login.data.name[0] = '\0'; + w->login.data.passwd[0] = '\0'; + w->login.state = INITIALIZING; + w->login.activePrompt = LOGIN_PROMPT_USERNAME; w->login.failUp = 0; + w->login.fail = (char *) w->login.failMsg; + + /* Set prompt defaults */ + PROMPT_TEXT(w, LOGIN_PROMPT_USERNAME) = NULL; + DEF_PROMPT_TEXT(w, LOGIN_PROMPT_USERNAME) = w->login.namePrompt; + VALUE_TEXT(w, LOGIN_PROMPT_USERNAME) = w->login.data.name; + VALUE_TEXT_MAX(w, LOGIN_PROMPT_USERNAME) = sizeof(w->login.data.name); + VALUE_SHOW_START(w, LOGIN_PROMPT_USERNAME) = 0; + + PROMPT_TEXT(w, LOGIN_PROMPT_PASSWORD) = NULL; + DEF_PROMPT_TEXT(w, LOGIN_PROMPT_PASSWORD) = w->login.passwdPrompt; + VALUE_TEXT(w, LOGIN_PROMPT_PASSWORD) = w->login.data.passwd; + VALUE_TEXT_MAX(w, LOGIN_PROMPT_PASSWORD) = sizeof(w->login.data.passwd); + VALUE_SHOW_START(w, LOGIN_PROMPT_PASSWORD) = 0; + + SetPrompt(gnew, LOGIN_PROMPT_PASSWORD, NULL, LOGIN_PROMPT_ECHO_OFF, False); + SetPrompt(gnew, LOGIN_PROMPT_USERNAME, NULL, LOGIN_PROMPT_ECHO_ON, False); + if (w->core.width == 0) w->core.width = max (GREET_W(w), FAIL_W(w)) + PAD_X(w); if (w->core.height == 0) { @@ -1200,6 +1608,10 @@ SkipXpmLoad: XtSetArg (position[0], XtNx, x); XtSetArg (position[1], XtNy, y); XtSetValues (XtParent (w), position, (Cardinal) 2); + + + + w->login.state = PROMPTING; } @@ -1271,6 +1683,12 @@ static void Destroy (Widget gw) LoginWidget w = (LoginWidget)gw; bzero (w->login.data.name, NAME_LEN); bzero (w->login.data.passwd, PASSWORD_LEN); + + if (PROMPT_TEXT(w,0) != NULL) + XtFree(PROMPT_TEXT(w,0)); + if (PROMPT_TEXT(w,1) != NULL) + XtFree(PROMPT_TEXT(w,1)); + XtReleaseGC(gw, w->login.textGC); XtReleaseGC(gw, w->login.bgGC); XtReleaseGC(gw, w->login.xorGC); @@ -1318,6 +1736,7 @@ static Boolean SetValues ( return False; } +static char defaultLoginTranslations [] = "Ctrl<Key>H: delete-previous-character() \n" "Ctrl<Key>D: delete-character() \n" @@ -1338,14 +1757,11 @@ char defaultLoginTranslations [] = "<Key>Delete: delete-previous-character() \n" #endif "<Key>Return: finish-field() \n" -#ifndef XPM -"<KeyPress>: insert-char()" -#else "<Key>Tab: tab-field() \n" "<KeyPress>: insert-char()" -#endif /* XPM */ ; +static XtActionsRec loginActionsTable [] = { {"delete-previous-character", DeleteBackwardChar}, {"delete-character", DeleteForwardChar}, @@ -1356,9 +1772,7 @@ XtActionsRec loginActionsTable [] = { {"erase-to-end-of-line", EraseToEndOfLine}, {"erase-line", EraseLine}, {"finish-field", FinishField}, -#ifdef XPM {"tab-field", TabField}, -#endif /* XPM */ {"abort-session", AbortSession}, {"abort-display", AbortDisplay}, {"restart-session", RestartSession}, diff --git a/greeter/Login.h b/greeter/Login.h index 3da7fb2..0002895 100644 --- a/greeter/Login.h +++ b/greeter/Login.h @@ -1,3 +1,4 @@ +/* $XdotOrg: $ */ /* $Xorg: Login.h,v 1.4 2001/02/09 02:05:41 xorgcvs Exp $ */ /* @@ -26,6 +27,33 @@ other dealings in this Software without prior written authorization from The Open Group. */ +/* Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons + * to whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT + * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL + * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING + * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder + * shall not be used in advertising or otherwise to promote the sale, use + * or other dealings in this Software without prior written authorization + * of the copyright holder. + */ /* $XFree86: xc/programs/xdm/greeter/Login.h,v 3.7 2002/10/06 20:42:16 herrb Exp $ */ /* @@ -112,23 +140,36 @@ from The Open Group. # define XtCAllowNullPasswd "AllowNullPasswd" # define XtCAllowRootLogin "AllowRootLogin" +# define XtNchangePasswdMessage "changePasswdMessage" +# define XtCChangePasswdMessage "ChangePasswdMessage" + /* notifyDone interface definition */ #ifdef __OpenBSD__ -#include <sys/param.h> +# include <sys/param.h> /* 2.8 (200012) doesn't have _PW_NAME_LEN */ -#if OpenBSD > 200012 -#define HAVE_PW_NAME_LEN +# if OpenBSD > 200012 +# include <pwd.h> +# define NAME_LEN (_PW_NAME_LEN + 2) +# define PASSWORD_LEN (_PASSWORD_LEN + 2) +# endif #endif + +#ifdef USE_PAM +# define NAME_LEN PAM_MAX_RESP_SIZE +# define PASSWORD_LEN PAM_MAX_RESP_SIZE #endif -#ifndef HAVE_PW_NAME_LEN -#define NAME_LEN 32 -#define PASSWORD_LEN 32 -#else -#include <pwd.h> -#define NAME_LEN (_PW_NAME_LEN + 2) -#define PASSWORD_LEN (_PASSWORD_LEN + 2) +#ifndef NAME_LEN +# define NAME_LEN 32 +#endif + +#ifndef PASSWORD_LEN +# ifdef PASS_MAX +# define PASSWORD_LEN PASS_MAX +# else +# define PASSWORD_LEN 32 +# endif #endif typedef struct _LoginData { @@ -145,5 +186,27 @@ typedef struct _LoginClassRec *LoginWidgetClass; /* completely defined in Log extern WidgetClass loginWidgetClass; +extern void ErrorMessage(Widget ctx, const char *message, Bool timeout); +extern void ShowChangePasswdMessage(Widget ctx); + +typedef enum { + LOGIN_PROMPT_NOT_SHOWN, /* Neither prompt nor input shown */ + LOGIN_PROMPT_ECHO_ON, /* Both prompt and input shown */ + LOGIN_PROMPT_ECHO_OFF, /* Prompt shown, input accepted but not + shown (bullets may be shown instead) */ + LOGIN_TEXT_INFO /* Prompt shown, no input area */ +} loginPromptState; + +/* Default prompt meanings for simple username/password auth systems */ +#define LOGIN_PROMPT_USERNAME 0 +#define LOGIN_PROMPT_PASSWORD 1 + +extern int SetPrompt(Widget ctx, int promptId, const char *message, + loginPromptState state, Boolean minimumTime); +extern const char *GetPrompt(Widget ctx, int promptId); + +extern int SetValue(Widget ctx, int promptId, char *value); +extern const char *GetValue(Widget ctx, int promptId); + #endif /* _XtLogin_h */ /* DON'T ADD STUFF AFTER THIS #endif */ diff --git a/greeter/LoginP.h b/greeter/LoginP.h index 9fc2640..0c63f89 100644 --- a/greeter/LoginP.h +++ b/greeter/LoginP.h @@ -1,3 +1,4 @@ +/* $XdotOrg: $ */ /* $Xorg: LoginP.h,v 1.4 2001/02/09 02:05:41 xorgcvs Exp $ */ /* @@ -26,7 +27,34 @@ other dealings in this Software without prior written authorization from The Open Group. */ -/* $XFree86: xc/programs/xdm/greeter/LoginP.h,v 3.7 2001/01/17 23:45:25 dawes Exp $ */ +/* Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons + * to whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT + * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL + * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING + * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder + * shall not be used in advertising or otherwise to promote the sale, use + * or other dealings in this Software without prior written authorization + * of the copyright holder. + */ +/* $XFree86: xc/programs/xdm/greeter/LoginP.h,v 3.8 2001/12/14 20:01:29 dawes Exp $ */ /* * xdm - display manager daemon @@ -37,17 +65,33 @@ from The Open Group. #define _LoginP_h #include "Login.h" +#include <X11/IntrinsicP.h> #include <X11/CoreP.h> #ifdef XPM #include <X11/Xlib.h> #endif /* XPM */ -#define GET_NAME 0 -#define GET_PASSWD 1 -#define DONE 2 +#define INITIALIZING 0 +#define PROMPTING 1 +#define SHOW_MESSAGE 2 +#define DONE 3 typedef void (*LoginFunc)(LoginWidget, LoginData *, int); +typedef struct { + char * promptText; /* Prompt displayed */ + const char * defaultPrompt; /* Default text for prompt */ + char * valueText; /* Value entered for prompt */ + size_t valueTextMax; /* Size of valueText buffer */ + int valueShownStart;/* Amount of string shown if too */ + int valueShownEnd; /* long to fit in field */ + int cursor; /* current cursor position */ + loginPromptState state; +} loginPromptData; + +#define NUM_PROMPTS 2 /* Currently only 2 prompt fields supported */ +#define LAST_PROMPT (NUM_PROMPTS - 1) + /* New fields for the login widget instance record */ typedef struct { Pixel textpixel; /* foreground pixel */ @@ -72,13 +116,15 @@ typedef struct { char *unsecure_greet;/* message displayed when insecure */ char *namePrompt; /* name prompt */ char *passwdPrompt; /* password prompt */ - char *fail; /* failure message */ + char *failMsg; /* failure message */ + char *fail; /* current error message */ + char *passwdChangeMsg; /* message when passwd expires */ XFontStruct *font; /* font for text */ XFontStruct *promptFont; /* font for prompts */ XFontStruct *greetFont; /* font for greeting */ XFontStruct *failFont; /* font for failure message */ int state; /* state */ - int cursor; /* current cursor position */ + int activePrompt; /* which prompt is active */ int failUp; /* failure message displayed */ LoginData data; /* name/passwd */ char *sessionArg; /* argument passed to session */ @@ -90,6 +136,8 @@ typedef struct { Boolean allow_null_passwd; /* allow null password on login */ Boolean allow_root_login; /* allow root login */ XIC xic; /* input method of input context */ + loginPromptData prompts[NUM_PROMPTS]; + time_t msgTimeout; #ifdef XPM /*caolan begin*/ int lastEventTime; diff --git a/greeter/greet.c b/greeter/greet.c index 2bc32e7..7c4a1fd 100644 --- a/greeter/greet.c +++ b/greeter/greet.c @@ -27,6 +27,34 @@ other dealings in this Software without prior written authorization from The Open Group. */ +/* Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons + * to whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT + * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL + * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING + * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder + * shall not be used in advertising or otherwise to promote the sale, use + * or other dealings in this Software without prior written authorization + * of the copyright holder. + */ + /* $XFree86: xc/programs/xdm/greeter/greet.c,v 3.16tsi Exp $ */ /* @@ -118,12 +146,34 @@ pam_handle_t **(*__xdm_thepamhp)(void) = NULL; extern Display *dpy; static int done, code; -static char name[128], password[128]; +#ifndef USE_PAM +static char name[NAME_LEN], password[PASSWORD_LEN]; +#endif static Widget toplevel; static Widget login; static XtAppContext context; static XtIntervalId pingTimeout; +#ifdef USE_PAM +static int pamconv(int num_msg, +#ifndef sun + const +#endif + struct pam_message **msg, + struct pam_response **response, void *appdata_ptr); + +# define PAM_ERROR_PRINT(pamfunc, pamh) \ + LogError("%s failure: %s\n", pamfunc, pam_strerror(pamh, pam_error)) + + +struct myconv_data { + struct display *d; + struct greet_info *greet; + char *username_display; +}; +#endif + + /*ARGSUSED*/ static void GreetPingServer ( @@ -150,11 +200,12 @@ GreetDone ( data->name, strlen (data->passwd)); switch (status) { case NOTIFY_OK: +#ifndef USE_PAM strncpy (name, data->name, sizeof(name)); name[sizeof(name)-1] = '\0'; strncpy (password, data->passwd, sizeof(password)); password[sizeof(password)-1] = '\0'; - bzero (data->passwd, PASSWORD_LEN); +#endif code = 0; done = 1; break; @@ -174,6 +225,12 @@ GreetDone ( done = 1; break; } +#ifndef USE_PAM + if (done) { + bzero (data->name, NAME_LEN); + bzero (data->passwd, PASSWORD_LEN); + } +#endif } static Display * @@ -316,6 +373,7 @@ Greet (struct display *d, struct greet_info *greet) Debug ("Done dispatch %s\n", d->name); if (code == 0) { +#ifndef USE_PAM char *ptr; unsigned int c,state = WHITESPACE; @@ -334,6 +392,7 @@ Greet (struct display *d, struct greet_info *greet) greet->name = ptr; greet->password = password; +#endif /* USE_PAM */ XtSetArg (arglist[0], XtNsessionArgument, (char *) &(greet->string)); XtSetArg (arglist[1], XtNallowNullPasswd, (char *) &(greet->allow_null_passwd)); XtSetArg (arglist[2], XtNallowRootLogin, (char *) &(greet->allow_root_login)); @@ -355,8 +414,10 @@ FailedLogin (struct display *d, struct greet_info *greet) d->name, greet->name); #endif DrawFail (login); +#ifndef USE_PAM bzero (greet->name, strlen(greet->name)); bzero (greet->password, strlen(greet->password)); +#endif } @@ -423,7 +484,108 @@ greet_user_rtn GreetUser( #ifdef __OpenBSD__ openlog("xdm", LOG_ODELAY, LOG_AUTH); #endif + for (;;) { +#ifdef USE_PAM + + /* Run PAM conversation */ + pam_handle_t **pamhp = thepamhp(); + int pam_error; + unsigned int pam_flags = 0; + struct myconv_data pcd = { d, greet, NULL }; + struct pam_conv pc = { pamconv, &pcd }; + const char * pam_fname; + char * username; + const char * login_prompt; + + + login_prompt = GetPrompt(login, LOGIN_PROMPT_USERNAME); + SetPrompt(login, 1, NULL, LOGIN_PROMPT_NOT_SHOWN, False); + +#define RUN_AND_CHECK_PAM_ERROR(function, args) \ + do { \ + pam_error = function args; \ + if (pam_error != PAM_SUCCESS) { \ + PAM_ERROR_PRINT(#function, *pamhp); \ + goto pam_done; \ + } \ + } while (0) + + + RUN_AND_CHECK_PAM_ERROR(pam_start, + ("xdm", NULL, &pc, pamhp)); + + /* Set default login prompt to xdm's default from Xresources */ + if (login_prompt != NULL) { + RUN_AND_CHECK_PAM_ERROR(pam_set_item, + (*pamhp, PAM_USER_PROMPT, login_prompt)); + } + + if (d->name[0] != ':') { /* Displaying to remote host */ + char *hostname = strdup(d->name); + + if (hostname == NULL) { + LogOutOfMem("GreetUser"); + } else { + char *colon = strrchr(d->name, ':'); + + if (colon != NULL) + *colon = '\0'; + + RUN_AND_CHECK_PAM_ERROR(pam_set_item, + (*pamhp, PAM_RHOST, hostname)); + free(hostname); + } + } + + if (!greet->allow_null_passwd) { + pam_flags |= PAM_DISALLOW_NULL_AUTHTOK; + } + RUN_AND_CHECK_PAM_ERROR(pam_authenticate, + (*pamhp, pam_flags)); + + /* handle expired passwords */ + pam_error = pam_acct_mgmt(*pamhp, pam_flags); + pam_fname = "pam_acct_mgmt"; + if (pam_error == PAM_NEW_AUTHTOK_REQD) { + ShowChangePasswdMessage(login); + do { + pam_error = pam_chauthtok(*pamhp, PAM_CHANGE_EXPIRED_AUTHTOK); + } while ((pam_error == PAM_AUTHTOK_ERR) || + (pam_error == PAM_TRY_AGAIN)); + pam_fname = "pam_chauthtok"; + } + if (pam_error != PAM_SUCCESS) { + PAM_ERROR_PRINT(pam_fname, *pamhp); + goto pam_done; + } + + RUN_AND_CHECK_PAM_ERROR(pam_setcred, + (*pamhp, 0)); + RUN_AND_CHECK_PAM_ERROR(pam_get_item, + (*pamhp, PAM_USER, (void *) &username)); + if (username != NULL) { + Debug("PAM_USER: %s\n", username); + greet->name = username; + greet->password = NULL; + } + + pam_done: + if (code != 0) + { + CloseGreet (d); + SessionExit (d, code, FALSE); + } + if ((pam_error == PAM_SUCCESS) && (Verify (d, greet, verify))) { + SetPrompt (login, 1, "Login Successful", PAM_TEXT_INFO, False); + SetValue (login, 1, NULL); + break; + } else { + RUN_AND_CHECK_PAM_ERROR(pam_end, + (*pamhp, pam_error)); + FailedLogin (d, greet); + } +#else /* not PAM */ /* * Greet user, requesting name/password */ @@ -440,6 +602,7 @@ greet_user_rtn GreetUser( break; else FailedLogin (d, greet); +#endif } DeleteXloginResources (d, *dpy); CloseGreet (d); @@ -496,3 +659,104 @@ greet_user_rtn GreetUser( return Greet_Success; } + + +#ifdef USE_PAM +static int pamconv(int num_msg, +#ifndef sun + const +#endif + struct pam_message **msg, + struct pam_response **response, void *appdata_ptr) +{ + int i; + int greetCode; + int status = PAM_SUCCESS; + const char *pam_msg_styles[5] + = { "<invalid pam msg style>", + "PAM_PROMPT_ECHO_OFF", "PAM_PROMPT_ECHO_ON", + "PAM_ERROR_MSG", "PAM_TEXT_INFO" } ; + + struct pam_message *m; + struct pam_response *r; + + struct myconv_data *d = (struct myconv_data *) appdata_ptr; + + pam_handle_t **pamhp = thepamhp(); + + *response = calloc(num_msg, sizeof (struct pam_response)); + if (*response == NULL) + return (PAM_BUF_ERR); + + m = *msg; + r = *response; + + for (i = 0; i < num_msg; i++ , m++ , r++) { + char *username; + int promptId = 0; + loginPromptState pStyle = LOGIN_PROMPT_ECHO_OFF; + + if ((pam_get_item(*pamhp, PAM_USER, (void *) &username) == PAM_SUCCESS) + && (username != NULL) && (*username != '\0')) { + SetPrompt(login, LOGIN_PROMPT_USERNAME, + NULL, LOGIN_TEXT_INFO, False); + SetValue(login, LOGIN_PROMPT_USERNAME, username); + promptId = 1; + } + + Debug("pam_msg: %s (%d): '%s'\n", + ((m->msg_style > 0) && (m->msg_style <= 4)) ? + pam_msg_styles[m->msg_style] : pam_msg_styles[0], + m->msg_style, m->msg); + + switch (m->msg_style) { + case PAM_ERROR_MSG: + ErrorMessage(login, m->msg, True); + break; + + case PAM_TEXT_INFO: + SetPrompt (login, promptId, m->msg, LOGIN_TEXT_INFO, True); + SetValue (login, promptId, NULL); + break; + + case PAM_PROMPT_ECHO_ON: + pStyle = LOGIN_PROMPT_ECHO_ON; + /* FALLTHROUGH */ + case PAM_PROMPT_ECHO_OFF: + SetPrompt (login, promptId, m->msg, pStyle, False); + SetValue (login, promptId, NULL); + greetCode = Greet (d->d, d->greet); + if (greetCode != 0) { + status = PAM_CONV_ERR; + goto pam_error; + } else { + r->resp = strdup(GetValue(login, promptId)); + SetValue(login, promptId, NULL); + if (r->resp == NULL) { + status = PAM_BUF_ERR; + goto pam_error; + } + /* Debug("pam_resp: '%s'\n", r->resp); */ + } + break; + + default: + LogError("Unknown PAM msg_style: %d\n", m->msg_style); + } + } + pam_error: + if (status != PAM_SUCCESS) { + /* free responses */ + r = *response; + for (i = 0; i < num_msg; i++, r++) { + if (r->resp) { + bzero(r->resp, strlen(r->resp)); + free(r->resp); + } + } + free(*response); + *response = NULL; + } + return status; +} +#endif diff --git a/greeter/verify.c b/greeter/verify.c index c4d1546..672237d 100644 --- a/greeter/verify.c +++ b/greeter/verify.c @@ -1,5 +1,5 @@ /* $Xorg: verify.c,v 1.4 2001/02/09 02:05:41 xorgcvs Exp $ */ -/* $XdotOrg: app/xdm/greeter/verify.c,v 1.7 2006/03/01 15:48:06 mhopf Exp $ */ +/* $XdotOrg: app/xdm/greeter/verify.c,v 1.8 2006/04/14 20:17:31 alanc Exp $ */ /* Copyright 1988, 1998 The Open Group @@ -120,76 +120,6 @@ userEnv (struct display *d, int useSystemPath, char *user, char *home, char *she return env; } -#ifdef USE_PAM -static char *PAM_password; -static int pam_error; - -static int PAM_conv (int num_msg, -#ifdef sun - struct pam_message **msg, -#else - const struct pam_message **msg, -#endif - struct pam_response **resp, - void *appdata_ptr) { - int count = 0, replies = 0; - struct pam_response *reply = NULL; - -#define PAM_RESPONSE_SIZE sizeof(struct pam_response) - size_t size = PAM_RESPONSE_SIZE; - -#define COPY_STRING(s) (s) ? strdup(s) : (char*)NULL - - for (count = 0; count < num_msg; count++) { - switch (msg[count]->msg_style) { - case PAM_PROMPT_ECHO_ON: - /* user name given to PAM already */ - return PAM_CONV_ERR; - case PAM_PROMPT_ECHO_OFF: - /* wants password */ - if (reply) { - void *r2 = reply; - if (! (reply = realloc(reply, size))) { - free (r2); - return PAM_CONV_ERR; - } - bzero(reply + size - PAM_RESPONSE_SIZE, PAM_RESPONSE_SIZE); - } else { - if (! (reply = (struct pam_response*)malloc(size))) - return PAM_CONV_ERR; - bzero(reply, size); - } - - if (!reply) - return PAM_CONV_ERR; - - size += PAM_RESPONSE_SIZE; - - reply[replies].resp_retcode = PAM_SUCCESS; - reply[replies].resp = COPY_STRING(PAM_password); - /* PAM frees resp */ - break; - case PAM_TEXT_INFO: - /* ignore the informational mesage */ - break; - default: - /* unknown or PAM_ERROR_MSG */ - if (reply) free (reply); - return PAM_CONV_ERR; - } - } - -#undef COPY_STRING - if (reply) *resp = reply; - return PAM_SUCCESS; -} - -static struct pam_conv PAM_conversation = { - PAM_conv, - NULL -}; -#endif /* USE_PAM */ - #ifdef USE_BSDAUTH int Verify (struct display *d, struct greet_info *greet, struct verify_info *verify) @@ -395,9 +325,7 @@ int Verify (struct display *d, struct greet_info *greet, struct verify_info *verify) { struct passwd *p; -#ifdef USE_PAM - pam_handle_t **pamhp = thepamhp(); -#else +#ifndef USE_PAM #ifdef USESHADOW struct spwd *sp; #endif @@ -417,7 +345,8 @@ Verify (struct display *d, struct greet_info *greet, struct verify_info *verify) if (!p || strlen (greet->name) == 0) { Debug ("getpwnam() failed.\n"); - bzero(greet->password, strlen(greet->password)); + if (greet->password != NULL) + bzero(greet->password, strlen(greet->password)); return 0; } @@ -448,11 +377,12 @@ Verify (struct display *d, struct greet_info *greet, struct verify_info *verify) (strncmp(d->name,":0",2) != 0) ) { Debug("Not on system console\n"); - bzero(greet->password, strlen(greet->password)); - XFree(console); + if (greet->password != NULL) + bzero(greet->password, strlen(greet->password)); + free(console); return 0; } - XFree(console); + free(console); } else { @@ -461,7 +391,7 @@ Verify (struct display *d, struct greet_info *greet, struct verify_info *verify) } #endif -#ifndef USE_PAM +#ifndef USE_PAM /* PAM authentication happened in GreetUser already */ #ifdef linux if (!strcmp(p->pw_passwd, "!") || !strcmp(p->pw_passwd, "*")) { Debug ("The account is locked, no login allowed.\n"); @@ -470,7 +400,6 @@ Verify (struct display *d, struct greet_info *greet, struct verify_info *verify) } #endif user_pass = p->pw_passwd; -#endif #ifdef KERBEROS if(strcmp(greet->name, "root") != 0){ char name[ANAME_SZ]; @@ -510,7 +439,6 @@ Verify (struct display *d, struct greet_info *greet, struct verify_info *verify) } } #endif -#ifndef USE_PAM #ifdef USESHADOW errno = 0; sp = getspnam(greet->name); @@ -522,7 +450,7 @@ Verify (struct display *d, struct greet_info *greet, struct verify_info *verify) #ifndef QNX4 endspent(); #endif /* QNX4 doesn't need endspent() to end shadow passwd ops */ -#endif +#endif /* USESHADOW */ #if defined(ultrix) || defined(__ultrix__) if (authenticate_user(p, greet->password, NULL) < 0) #else @@ -588,40 +516,6 @@ done: #endif /* __OpenBSD__ */ bzero(user_pass, strlen(user_pass)); /* in case shadow password */ -#else /* USE_PAM */ -#define PAM_BAIL \ - if (pam_error != PAM_SUCCESS) goto pam_failed; - - PAM_password = greet->password; - pam_error = pam_start("xdm", greet->name, &PAM_conversation, pamhp); - PAM_BAIL; - pam_error = pam_set_item(*pamhp, PAM_TTY, d->name); - PAM_BAIL; - pam_error = pam_set_item(*pamhp, PAM_RHOST, ""); - PAM_BAIL; - pam_error = pam_authenticate(*pamhp, 0); - PAM_BAIL; - pam_error = pam_acct_mgmt(*pamhp, 0); - /* really should do password changing, but it doesn't fit well */ - PAM_BAIL; - pam_error = pam_setcred(*pamhp, 0); - PAM_BAIL; - p = getpwnam (greet->name); - endpwent(); - - if (!p || strlen (greet->name) == 0) { - Debug ("getpwnam() failed.\n"); - bzero(greet->password, strlen(greet->password)); - return 0; - } - - if (pam_error != PAM_SUCCESS) { - pam_failed: - pam_end(*pamhp, PAM_SUCCESS); - *pamhp = NULL; - return 0; - } -#undef PAM_BAIL #endif /* USE_PAM */ #endif /* USE_BSDAUTH */ @@ -1,4 +1,4 @@ -/* $XdotOrg: app/xdm/session.c,v 1.5 2006/03/16 21:46:55 alanc Exp $ */ +/* $XdotOrg: app/xdm/session.c,v 1.6 2006/04/08 00:22:23 alanc Exp $ */ /* $Xorg: session.c,v 1.8 2001/02/09 02:05:40 xorgcvs Exp $ */ /* @@ -52,6 +52,8 @@ from The Open Group. #ifdef AIXV3 # include <usersec.h> #endif + +#ifndef USE_PAM /* PAM modules should handle these */ #ifdef SECURE_RPC # include <rpc/rpc.h> # include <rpc/key_prot.h> @@ -62,6 +64,7 @@ extern int key_setnet(struct key_netstarg *arg); #ifdef K5AUTH # include <krb5/krb5.h> #endif +#endif /* USE_PAM */ #ifdef __SCO__ #include <prot.h> @@ -473,9 +476,8 @@ void SessionExit (struct display *d, int status, int removeAuth) { #ifdef USE_PAM - pam_handle_t *pamh = thepamh(); -#endif -#ifdef USE_PAM + pam_handle_t *pamh = thepamh(); + if (pamh) { /* shutdown PAM session */ pam_close_session(pamh, 0); @@ -493,7 +495,7 @@ SessionExit (struct display *d, int status, int removeAuth) setgid (verify.gid); setuid (verify.uid); RemoveUserAuthorization (d, &verify); -#ifdef K5AUTH +#if defined(K5AUTH) && !defined(USE_PAM) /* PAM modules should handle this */ /* do like "kdestroy" program */ { krb5_error_code code; @@ -673,6 +675,7 @@ StartClient ( } #endif /* AIXV3 */ +#ifndef USE_PAM /* PAM modules should handle these */ /* * for user-based authorization schemes, * use the password to get the user's credentials. @@ -759,7 +762,10 @@ StartClient ( } } #endif /* K5AUTH */ - bzero(passwd, strlen(passwd)); +#endif /* !USE_PAM */ + if (passwd != NULL) + bzero(passwd, strlen(passwd)); + SetUserAuthorization (d, verify); home = getEnv (verify->userEnviron, "HOME"); if (home) @@ -781,13 +787,15 @@ StartClient ( execute (failsafeArgv, verify->userEnviron); exit (1); case -1: - bzero(passwd, strlen(passwd)); + if (passwd != NULL) + bzero(passwd, strlen(passwd)); Debug ("StartSession, fork failed\n"); LogError ("can't start session on \"%s\", fork failed, errno=%d\n", d->name, errno); return 0; default: - bzero(passwd, strlen(passwd)); + if (passwd != NULL) + bzero(passwd, strlen(passwd)); Debug ("StartSession, fork succeeded %d\n", pid); *pidp = pid; return 1; |