3 Authentication method specific conversation plugin for KDE's greeter widgets
5 Copyright (C) 2003 Oswald Buddenhagen <ossi@kde.org>
6 Copyright (C) 2003 Fabian Kaiser <xfk@softpro.de>
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
18 You should have received a copy of the GNU Library General Public License
19 along with this library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA.
24 #ifndef KGREETERPLUGIN_H
25 #define KGREETERPLUGIN_H
27 #include <QtCore/QVariant>
28 #include <QtGui/QMessageBox>
29 #include <kdemacros.h>
33 class KGreeterPluginHandler
{
35 virtual ~KGreeterPluginHandler() {}
36 /* keep in sync with V_IS_* */
37 enum { IsSecret
= 1, IsUser
= 2, IsPassword
= 4, IsOldPassword
= 8,
40 * Reply to textPrompt().
41 * @param text text to return to core; null to abort auth cycle
42 * @param tag zero or one of Is*
44 virtual void gplugReturnText( const char *text
, int tag
) = 0;
46 * Reply to binaryPrompt().
47 * @param data data in pam_client format to return to the core;
48 * null to abort auth cycle
50 virtual void gplugReturnBinary( const char *data
) = 0;
52 * Tell the greeter who is logging in.
53 * Call this preferably before gplugStart, as otherwise the .dmrc
54 * load will be delayed. Don't call at all if your plugin doesn't
55 * have the Local flag set. Call only for internally generated
57 * @param user the user logging in
59 virtual void gplugSetUser( const QString
&user
) = 0;
63 virtual void gplugStart() = 0;
65 * This should be called each time the talker changes in any way from the
66 * pristine state after an authentication cycle starts, so the greeter
67 * knows it must reset the fields after some time of inactivity.
69 virtual void gplugChanged() = 0;
71 * Plugins that expect user input from a different device than the mouse or
72 * keyboard must call this when user activity is detected to prevent the
73 * greeter from resetting/going away. Events should be compressed to no
74 * more than ten per second; one every five seconds is actually enough.
75 * Events should be actual changes to the input fields, not random motion.
77 virtual void gplugActivity() = 0;
79 * Show a message box on behalf of the talker.
80 * @param type message severity
81 * @param text message text
83 virtual void gplugMsgBox( QMessageBox::Icon type
, const QString
&text
) = 0;
85 * Determine if the named widget is welcomed.
86 * @param id the widget name
88 virtual bool gplugHasNode( const QString
&id
) = 0;
92 * Abstract base class for conversation plugins ("talkers") to be used with
93 * KDM, kdesktop_lock, etc.
94 * The authentication method used by a particular instance of a plugin
95 * may be configurable, but the instance must handle exactly one method,
96 * i.e., info->method must be determined at the latest at init() time.
98 class KGreeterPlugin
{
100 KGreeterPlugin( KGreeterPluginHandler
*h
) : handler( h
) {}
101 virtual ~KGreeterPlugin() {}
104 * Variations of the talker:
105 * - Authenticate: authentication
106 * - AuthChAuthTok: authentication and password change
107 * - ChAuthTok: password change
109 enum Function
{ Authenticate
, AuthChAuthTok
, ChAuthTok
};
112 * Contexts the talker can be used in:
113 * - Login: kdm login dialog
114 * - Shutdown: kdm shutdown dialog
115 * - Unlock: kdm unlock dialog (TODO)
116 * - ChangeTok: kdm password change dialog (TODO)
117 * - ExUnlock: kdesktop_lock unlock dialog
118 * - ExChangeTok: kdepasswd password change dialog (TODO)
120 * The Ex* contexts exist within a running session; the talker must know
121 * how to obtain the currently logged in user (+ domain/realm, etc.)
122 * itself (i.e., fixedEntity will be null). The non-Ex variants will have
123 * a fixedEntity passed in.
125 enum Context
{ Login
, Shutdown
, Unlock
, ChangeTok
,
126 ExUnlock
, ExChangeTok
};
129 * Provide the talker with a list of selectable users. This can be used
130 * for autocompletion, etc.
131 * Will be called only when not running.
132 * @param users the users to load.
134 virtual void loadUsers( const QStringList
&users
) = 0;
137 * Preload the talker with an (opaque to the greeter) entity.
138 * Will be called only when not running.
139 * @param entity the entity to preload the talker with. That
140 * will usually be something like "user" or "user@domain".
141 * @param field the sub-widget (probably line edit) to put the cursor into.
142 * If -1, preselect the user for timed login. This means pre-filling
143 * the password field with anything, disabling it, and placing the
144 * cursor in the user name field.
146 virtual void presetEntity( const QString
&entity
, int field
) = 0;
149 * Obtain the actually logged in entity.
150 * Will be called only after succeeded() was called.
152 virtual QString
getEntity() const = 0;
155 * "Push" a user into the talker. That can be a click into the user list
156 * or successful authentication without the talker calling gplugSetUser.
157 * Will be called only when running.
158 * @param user the user to set. Note that this is a UNIX login, not a
161 virtual void setUser( const QString
&user
) = 0;
164 * En-/disable any widgets contained in the talker.
165 * Will be called only when not running.
166 * @param on the state to set
168 virtual void setEnabled( bool on
) = 0;
171 * Called when a message from the authentication backend arrives.
172 * @param message the message received from the backend
173 * @param error if true, @p message is an error message, otherwise it's
174 * an informational message
175 * @return true means that the talker already handled the message, false
176 * that the greeter should display it in a message box
178 * FIXME: Filtering a message usually means that the backend issued a
179 * prompt and obtains the authentication data itself. However, in that
180 * state the backend is unresponsive, e.g., no shutdown is possible.
181 * The frontend could send the backend a signal, but the "escape path"
182 * within the backend is unclear (PAM won't like simply longjmp()ing
185 virtual bool textMessage( const char *message
, bool error
) = 0;
188 * Prompt the user for data. Reply by calling handler->gplugReturnText().
189 * @param propmt the prompt to display. It may be null, in which case
190 * "Username"/"Password" should be shown and the replies should be tagged
191 * with the respective Is* flag.
192 * @param echo if true, a normal input widget can be used, otherwise one that
193 * visually obscures the user's input.
194 * @param nonBlocking if true, report whatever is already available,
195 * otherwise wait for user input.
197 virtual void textPrompt( const char *prompt
, bool echo
, bool nonBlocking
) = 0;
200 * Request binary authentication data from the talker. Reply by calling
201 * handler->gplugReturnBinary().
202 * @param prompt prompt in pam_client format
203 * @param nonBlocking if true, report whatever is already available,
204 * otherwise wait for user input.
205 * @return always true for now
208 * @return if true, the prompt was handled by the talker, otherwise the
209 * handler has to use libpam_client to obtain the authentication data.
210 * In that state the talker still can abort the data fetch by
211 * gplugReturn()ing a null array. When the data was obtained, another
212 * binaryPrompt with a null prompt will be issued.
214 virtual bool binaryPrompt( const char *prompt
, bool nonBlocking
) = 0;
218 * - Start a processing cycle. Will be called only when not running.
219 * - Restart authTok cycle - will be called while running and implies
220 * revive(). PAM is a bit too clever, so we need this.
221 * In any case the talker is running afterwards.
223 virtual void start() = 0;
226 * Request to suspend the auth. Make sure that a second talker of any
227 * type will be able to operate while this one is suspended (no busy
228 * device nodes, etc.).
229 * Will be called only if running within Login context. (Actually it
230 * won't be called at all, but be prepared.)
232 virtual void suspend() = 0;
235 * Request to resume the auth from the point it was suspended at.
236 * Will be called only when suspended.
238 virtual void resume() = 0;
241 * The "login" button was pressed in the greeter.
242 * This might call gplugReturn* or gplugStart.
243 * Will be called only when running.
245 virtual void next() = 0;
248 * Abort auth cycle. Note that this should _not_ clear out already
249 * entered auth tokens if they are still on the screen.
250 * Will be called only when running and stops it.
252 virtual void abort() = 0;
255 * Indicate successful end of the current phase.
256 * This is more or less a request to disable editable widgets
257 * responsible for the that phase.
258 * There will be no further attempt to enter that phase until the
259 * widget is destroyed.
260 * Will be called only when running and stops it.
262 virtual void succeeded() = 0;
265 * Indicate unsuccessful end of the current phase.
266 * This is mostly a request to disable all editable widgets.
267 * The widget will be treated as dead until revive() is called.
268 * Will be called only when running and stops it.
270 virtual void failed() = 0;
273 * Prepare retrying the previously failed phase.
274 * This is mostly a request to re-enable all editable widgets failed()
275 * disabled previously, clear the probably incorrect authentication tokens
276 * and to set the input focus appropriately.
277 * Will be called only after failed() (possibly with clear() in between),
278 * or after presetEntity() with field -1.
280 virtual void revive() = 0;
283 * Clear any edit widgets, particularly anything set by setUser.
284 * Will be called only when not running.
286 virtual void clear() = 0;
288 typedef QList
<QWidget
*> WidgetList
;
291 * Obtain the QWidget to actually handle the conversation.
293 const WidgetList
&getWidgets() const { return widgetList
; }
296 KGreeterPluginHandler
*handler
;
297 WidgetList widgetList
;
300 struct KDE_EXPORT KGreeterPluginInfo
{
302 * Human readable name of this plugin (should be a little more
303 * informative than just the libary name). Must be I18N_NOOP()ed.
308 * The authentication method to use - the meaning is up to the backend,
309 * but will usually be related to the PAM service.
318 * All users exist on the local system permanently (will be listed
319 * by getpwent()); an entity corresponds to a UNIX user.
323 * The entities consist of multiple fields.
324 * PluginOptions/<plugin>.FocusField is used instead of FocusPasswd.
328 * An entity can be preset, the talker has a widget where a user can
329 * be selected explicitly. If the method is "classic", timed login
331 * This also means that setUser/gplugSetUser can be used and a
332 * userlist can be shown at all - provided Local is set as well.
343 * Call after loading the plugin.
345 * @param method if non-empty and the plugin is unable to handle that
346 * method, return false. If the plugin has a constant method defined
347 * above, it can ignore this parameter.
348 * @param getConf can be used to obtain configuration items from the
349 * greeter; you have to pass it the @p ctx pointer.
350 * The only predefined key (in KDM) is "EchoMode", which is an int
351 * (in fact, QLineEdit::EchoModes).
352 * Other keys are obtained from the PluginOptions option; see kdmrc
354 * If the key is unknown, dflt is returned.
355 * @param ctx context pointer for @p getConf
356 * @return if false, unload the plugin again (don't call done() first)
358 bool (*init
)( const QString
&method
,
359 QVariant (*getConf
)( void *ctx
, const char *key
,
360 const QVariant
&dflt
),
364 * Call before unloading the plugin.
365 * This pointer can be null.
367 void (*done
)( void );
370 * Factory method to create an instance of the plugin.
371 * Note that multiple instances can exist at one time, but only
372 * one of them is active at any moment (the others would be suspended
373 * or not running at all).
374 * @param handler the object offering the necessary callbacks
375 * @param parent parent widget
376 * @param predecessor the focus widget before the conversation widget
377 * @param fixedEntity see below
378 * @param func see below
379 * @param ctx see below
380 * @return an instance of this conversation plugin
382 * Valid combinations of Function and Context:
383 * - Authenticate:Login - init
384 * - Authenticate:Shutdown - init, for now "root" is passed as fixedEntitiy
385 * and it is not supposed to be displayed. Plugins with Local not set
386 * might have to conjure something up to make getEntity() return a
387 * canonical entitiy. FIXME: don't restrict shutdown to root.
388 * - AuthChAuthTok:Login, AuthChAuthTok:Shutdown - cont/cont,
389 * only relevant for classic method (as it is relevant only for password-
390 * less logins, which always use classic). The login should not be shown -
391 * it is known to the user already; the backend won't ask for it, either.
392 * - ChAuthTok:Login & ChAuthTok:Shutdown - cont
393 * - Authenticate:Unlock & Authenticate:ExUnlock - init,
394 * AuthChAuthTok:ChangeTok & AuthChAuthTok:ExChangeTok - init/cont,
395 * display fixedEntity as labels. The backend does not ask for the UNIX
396 * login, as it already knows it - but it will ask for all components of
397 * the entity if it is no UNIX login.
399 * "init" means that the plugin is supposed to call gplugStart, "cont"
400 * that the backend is already in a cycle of the method the plugin was
401 * initialized with (it does not hurt if gplugStart is still called).
403 KGreeterPlugin
*(*create
)( KGreeterPluginHandler
*handler
,
405 const QString
&fixedEntity
,
406 KGreeterPlugin::Function func
,
407 KGreeterPlugin::Context ctx
);