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 or revived.
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
* after succeeded() (after an aborted forced authentication token change),
279
* or after presetEntity() with field -1.
281
virtual void revive() = 0;
284
* Clear any edit widgets, particularly anything set by setUser.
285
* Will be called only when not running.
287
virtual void clear() = 0;
289
typedef QList<QWidget *> WidgetList;
292
* Obtain the QWidget to actually handle the conversation.
294
const WidgetList &getWidgets() const { return widgetList; }
297
KGreeterPluginHandler *handler;
298
WidgetList widgetList;
301
struct KDE_EXPORT KGreeterPluginInfo {
303
* Human readable name of this plugin (should be a little more
304
* informative than just the libary name). Must be I18N_NOOP()ed.
309
* The authentication method to use - the meaning is up to the backend,
310
* but will usually be related to the PAM service.
319
* All users exist on the local system permanently (will be listed
320
* by getpwent()); an entity corresponds to a UNIX user.
324
* The entities consist of multiple fields.
325
* PluginOptions/<plugin>.FocusField is used instead of FocusPasswd.
329
* An entity can be preset, the talker has a widget where a user can
330
* be selected explicitly. If the method is "classic", timed login
332
* This also means that setUser/gplugSetUser can be used and a
333
* userlist can be shown at all - provided Local is set as well.
344
* Call after loading the plugin.
346
* @param method if non-empty and the plugin is unable to handle that
347
* method, return false. If the plugin has a constant method defined
348
* above, it can ignore this parameter.
349
* @param getConf can be used to obtain configuration items from the
350
* greeter; you have to pass it the @p ctx pointer.
351
* The only predefined key (in KDM) is "EchoMode", which is an int
352
* (in fact, QLineEdit::EchoModes).
353
* Other keys are obtained from the PluginOptions option; see kdmrc
355
* If the key is unknown, dflt is returned.
356
* @param ctx context pointer for @p getConf
357
* @return if false, unload the plugin again (don't call done() first)
359
bool (*init)(const QString &method,
360
QVariant(*getConf)(void *ctx, const char *key,
361
const QVariant &dflt),
365
* Call before unloading the plugin.
366
* This pointer can be null.
371
* Factory method to create an instance of the plugin.
372
* Note that multiple instances can exist at one time, but only
373
* one of them is active at any moment (the others would be suspended
374
* or not running at all).
375
* @param handler the object offering the necessary callbacks
376
* @param parent parent widget
377
* @param predecessor the focus widget before the conversation widget
378
* @param fixedEntity see below
379
* @param func see below
380
* @param ctx see below
381
* @return an instance of this conversation plugin
383
* Valid combinations of Function and Context:
384
* - Authenticate:Login - init
385
* - Authenticate:Shutdown - init, for now "root" is passed as fixedEntitiy
386
* and it is not supposed to be displayed. Plugins with Local not set
387
* might have to conjure something up to make getEntity() return a
388
* canonical entitiy. FIXME: don't restrict shutdown to root.
389
* - AuthChAuthTok:Login, AuthChAuthTok:Shutdown - cont/cont,
390
* only relevant for classic method (as it is relevant only for password-
391
* less logins, which always use classic). The login should not be shown -
392
* it is known to the user already; the backend won't ask for it, either.
393
* - ChAuthTok:Login & ChAuthTok:Shutdown - cont
394
* - Authenticate:Unlock & Authenticate:ExUnlock - init,
395
* AuthChAuthTok:ChangeTok & AuthChAuthTok:ExChangeTok - init/cont,
396
* display fixedEntity as labels. The backend does not ask for the UNIX
397
* login, as it already knows it - but it will ask for all components of
398
* the entity if it is no UNIX login.
400
* "init" means that the plugin is supposed to call gplugStart, "cont"
401
* that the backend is already in a cycle of the method the plugin was
402
* initialized with (it does not hurt if gplugStart is still called).
404
KGreeterPlugin *(*create)(KGreeterPluginHandler *handler,
406
const QString &fixedEntity,
407
KGreeterPlugin::Function func,
408
KGreeterPlugin::Context ctx);