diff options
Diffstat (limited to 'kdmlib/kgreeterplugin.h')
-rw-r--r-- | kdmlib/kgreeterplugin.h | 401 |
1 files changed, 401 insertions, 0 deletions
diff --git a/kdmlib/kgreeterplugin.h b/kdmlib/kgreeterplugin.h new file mode 100644 index 000000000..e7677415c --- /dev/null +++ b/kdmlib/kgreeterplugin.h @@ -0,0 +1,401 @@ +/* + + Authentication method specific conversation plugin for KDE's greeter widgets + + Copyright (C) 2003 Oswald Buddenhagen <ossi@kde.org> + Copyright (C) 2003 Fabian Kaiser <xfk@softpro.de> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KGREETERPLUGIN_H +#define KGREETERPLUGIN_H + +#include <qvariant.h> +#include <qmessagebox.h> +#include <kdemacros.h> + +class KdmThemer; + +class QWidget; +class QLayoutItem; + +class KGreeterPluginHandler { +public: + /* keep in sync with V_IS_* */ + enum { IsSecret = 1, IsUser = 2, IsPassword = 4, IsOldPassword = 8, + IsNewPassword = 16 }; + /** + * Reply to textPrompt(). + * @param text text to return to core; null to abort auth cycle + * @param tag zero or one of Is* + */ + virtual void gplugReturnText( const char *text, int tag ) = 0; + /** + * Reply to binaryPrompt(). + * @param data data in pam_client format to return to the core; + * null to abort auth cycle + */ + virtual void gplugReturnBinary( const char *data ) = 0; + /** + * Tell the greeter who is logging in. + * Call this preferably before gplugStart, as otherwise the .dmrc + * load will be delayed. Don't call at all if your plugin doesn't + * have the Local flag set. Call only for internally generated + * user changes. + * @param user the user logging in + */ + virtual void gplugSetUser( const QString &user ) = 0; + /** + * Start processing. + */ + virtual void gplugStart() = 0; + /** + * Plugins that expect user input from a different device than the mouse or + * keyboard must call this when user activity is detected to prevent the + * greeter from resetting/going away. Events should be compressed to no + * more than ten per second; one every five seconds is actually enough. + * Events should be actual changes to the input fields, not random motion. + */ + virtual void gplugActivity() = 0; + /** + * Show a message box on behalf of the talker. + * @param type message severity + * @param text message text + */ + virtual void gplugMsgBox( QMessageBox::Icon type, const QString &text ) = 0; +}; + +/** + * Abstract base class for conversation plugins ("talkers") to be used with + * KDM, kdesktop_lock, etc. + * The authentication method used by a particular instance of a plugin + * may be configurable, but the instance must handle exactly one method, + * i.e., info->method must be determined at the latest at init() time. + */ +class KGreeterPlugin { +public: + KGreeterPlugin( KGreeterPluginHandler *h ) : handler( h ) {} + virtual ~KGreeterPlugin() {} + + /** + * Variations of the talker: + * - Authenticate: authentication + * - AuthChAuthTok: authentication and password change + * - ChAuthTok: password change + */ + enum Function { Authenticate, AuthChAuthTok, ChAuthTok }; + + /** + * Contexts the talker can be used in: + * - Login: kdm login dialog + * - Shutdown: kdm shutdown dialog + * - Unlock: kdm unlock dialog (TODO) + * - ChangeTok: kdm password change dialog (TODO) + * - ExUnlock: kdesktop_lock unlock dialog + * - ExChangeTok: kdepasswd password change dialog (TODO) + * + * The Ex* contexts exist within a running session; the talker must know + * how to obtain the currently logged in user (+ domain/realm, etc.) + * itself (i.e., fixedEntity will be null). The non-Ex variants will have + * a fixedEntity passed in. + */ + enum Context { Login, Shutdown, Unlock, ChangeTok, + ExUnlock, ExChangeTok }; + + /** + * Provide the talker with a list of selectable users. This can be used + * for autocompletion, etc. + * Will be called only when not running. + * @param users the users to load. + */ + virtual void loadUsers( const QStringList &users ) = 0; + + /** + * Preload the talker with an (opaque to the greeter) entity. + * Will be called only when not running. + * @param entity the entity to preload the talker with. That + * will usually be something like "user" or "user@domain". + * @param field the sub-widget (probably line edit) to put the cursor into. + * If -1, preselect the user for timed login. This means pre-filling + * the password field with anything, disabling it, and placing the + * cursor in the user name field. + */ + virtual void presetEntity( const QString &entity, int field ) = 0; + + /** + * Obtain the actually logged in entity. + * Will be called only after succeeded() was called. + */ + virtual QString getEntity() const = 0; + + /** + * "Push" a user into the talker. That can be a click into the user list + * or successful authentication without the talker calling gplugSetUser. + * Will be called only when running. + * @param user the user to set. Note that this is a UNIX login, not a + * canonical entity + */ + virtual void setUser( const QString &user ) = 0; + + /** + * En-/disable any widgets contained in the talker. + * Will be called only when not running. + * @param on the state to set + */ + virtual void setEnabled( bool on ) = 0; + + /** + * Called when a message from the authentication backend arrives. + * @param message the message received from the backend + * @param error if true, @p message is an error message, otherwise it's + * an informational message + * @return true means that the talker already handled the message, false + * that the greeter should display it in a message box + * + * FIXME: Filtering a message usually means that the backend issued a + * prompt and obtains the authentication data itself. However, in that + * state the backend is unresponsive, e.g., no shutdown is possible. + * The frontend could send the backend a signal, but the "escape path" + * within the backend is unclear (PAM won't like simply longjmp()ing + * out of it). + */ + virtual bool textMessage( const char *message, bool error ) = 0; + + /** + * Prompt the user for data. Reply by calling handler->gplugReturnText(). + * @param propmt the prompt to display. It may be null, in which case + * "Username"/"Password" should be shown and the replies should be tagged + * with the respective Is* flag. + * @param echo if true, a normal input widget can be used, otherwise one that + * visually obscures the user's input. + * @param nonBlocking if true, report whatever is already available, + * otherwise wait for user input. + */ + virtual void textPrompt( const char *prompt, bool echo, bool nonBlocking ) = 0; + + /** + * Request binary authentication data from the talker. Reply by calling + * handler->gplugReturnBinary(). + * @param prompt prompt in pam_client format + * @param nonBlocking if true, report whatever is already available, + * otherwise wait for user input. + * @return always true for now + * + * TODO: + * @return if true, the prompt was handled by the talker, otherwise the + * handler has to use libpam_client to obtain the authentication data. + * In that state the talker still can abort the data fetch by + * gplugReturn()ing a null array. When the data was obtained, another + * binaryPrompt with a null prompt will be issued. + */ + virtual bool binaryPrompt( const char *prompt, bool nonBlocking ) = 0; + + /** + * This can either + * - Start a processing cycle. Will be called only when not running. + * - Restart authTok cycle - will be called while running and implies + * revive(). PAM is a bit too clever, so we need this. + * In any case the talker is running afterwards. + */ + virtual void start() = 0; + + /** + * Request to suspend the auth. Make sure that a second talker of any + * type will be able to operate while this one is suspended (no busy + * device nodes, etc.). + * Will be called only if running within Login context. (Actually it + * won't be called at all, but be prepared.) + */ + virtual void suspend() = 0; + + /** + * Request to resume the auth from the point it was suspended at. + * Will be called only when suspended. + */ + virtual void resume() = 0; + + /** + * The "login" button was pressed in the greeter. + * This might call gplugReturn* or gplugStart. + * Will be called only when running. + */ + virtual void next() = 0; + + /** + * Abort auth cycle. Note that this should _not_ clear out already + * entered auth tokens if they are still on the screen. + * Will be called only when running and stops it. + */ + virtual void abort() = 0; + + /** + * Indicate successful end of the current phase. + * This is more or less a request to disable editable widgets + * responsible for the that phase. + * There will be no further attempt to enter that phase until the + * widget is destroyed. + * Will be called only when running and stops it. + */ + virtual void succeeded() = 0; + + /** + * Indicate unsuccessful end of the current phase. + * This is mostly a request to disable all editable widgets. + * The widget will be treated as dead until revive() is called. + * Will be called only when running and stops it. + */ + virtual void failed() = 0; + + /** + * Prepare retrying the previously failed phase. + * This is mostly a request to re-enable all editable widgets failed() + * disabled previously, clear the probably incorrect authentication tokens + * and to set the input focus appropriately. + * Will be called only after failed() (possibly with clear() in between), + * or after presetEntity() with field -1. + */ + virtual void revive() = 0; + + /** + * Clear any edit widgets, particularily anything set by setUser. + * Will be called only when not running. + */ + virtual void clear() = 0; + + /** + * Obtain the QLayoutItem containg the widget(s) to actually handle the + * conversation. See QLayout and QWidgetItem for possible implementations. + */ + QLayoutItem *getLayoutItem() const { return layoutItem; } + +protected: + KGreeterPluginHandler *handler; + QLayoutItem *layoutItem; +}; + +struct KDE_EXPORT kgreeterplugin_info { + /** + * Human readable name of this plugin (should be a little more + * informative than just the libary name). Must be I18N_NOOP()ed. + */ + const char *name; + + /** + * The authentication method to use - the meaning is up to the backend, + * but will usually be related to the PAM service. + */ + const char *method; + + /** + * Capabilities. + */ + enum { + /** + * All users exist on the local system permanently (will be listed + * by getpwent()); an entity corresponds to a UNIX user. + */ + Local = 1, + /** + * The entities consist of multiple fields. + * PluginOptions/<plugin>.FocusField is used instead of FocusPasswd. + */ + Fielded = 2, + /** + * An entity can be preset, the talker has a widget where a user can + * be selected explicitly. If the method is "classic", timed login + * is possible, too. + * This also means that setUser/gplugSetUser can be used and a + * userlist can be shown at all - provided Local is set as well. + */ + Presettable = 4 + }; + + /* + * Capability flags. + */ + int flags; + + /** + * Call after loading the plugin. + * + * @param method if non-empty and the plugin is unable to handle that + * method, return false. If the plugin has a constant method defined + * above, it can ignore this parameter. + * @param getConf can be used to obtain configuration items from the + * greeter; you have to pass it the @p ctx pointer. + * The only predefined key (in KDM) is "EchoMode", which is an int + * (in fact, KPasswordEdit::EchoModes). + * Other keys are obtained from the PluginOptions option; see kdmrc + * for details. + * If the key is unknown, dflt is returned. + * @param ctx context pointer for @p getConf + * @return if false, unload the plugin again (don't call done() first) + */ + bool (*init)( const QString &method, + QVariant (*getConf)( void *ctx, const char *key, + const QVariant &dflt ), + void *ctx ); + + /** + * Call before unloading the plugin. + * This pointer can be null. + */ + void (*done)( void ); + + /** + * Factory method to create an instance of the plugin. + * Note that multiple instances can exist at one time, but only + * one of them is active at any moment (the others would be suspended + * or not running at all). + * @param handler the object offering the necessary callbacks + * @param parent parent widget + * @param predecessor the focus widget before the conversation widget + * @param fixedEntity see below + * @param func see below + * @param ctx see below + * @return an instance of this conversation plugin + * + * Valid combinations of Function and Context: + * - Authenticate:Login - init + * - Authenticate:Shutdown - init, for now "root" is passed as fixedEntitiy + * and it is not supposed to be displayed. Plugins with Local not set + * might have to conjure something up to make getEntity() return a + * canonical entitiy. FIXME: don't restrict shutdown to root. + * - AuthChAuthTok:Login, AuthChAuthTok:Shutdown - cont/cont, + * only relevant for classic method (as it is relevant only for password- + * less logins, which always use classic). The login should not be shown - + * it is known to the user already; the backend won't ask for it, either. + * - ChAuthTok:Login & ChAuthTok:Shutdown - cont + * - Authenticate:Unlock & Authenticate:ExUnlock - init, + * AuthChAuthTok:ChangeTok & AuthChAuthTok:ExChangeTok - init/cont, + * display fixedEntity as labels. The backend does not ask for the UNIX + * login, as it already knows it - but it will ask for all components of + * the entity if it is no UNIX login. + * + * "init" means that the plugin is supposed to call gplugStart, "cont" + * that the backend is already in a cycle of the method the plugin was + * initialized with. + */ + KGreeterPlugin *(*create)( KGreeterPluginHandler *handler, + KdmThemer *themer, + QWidget *parent, QWidget *predecessor, + const QString &fixedEntity, + KGreeterPlugin::Function func, + KGreeterPlugin::Context ctx ); +}; + +#endif |