2
* Copyright (C) 2010 Robert Ancell.
3
* Author: Robert Ancell <robert.ancell@canonical.com>
5
* This program is free software: you can redistribute it and/or modify it under
6
* the terms of the GNU General Public License as published by the Free Software
7
* Foundation, either version 3 of the License, or (at your option) any later
8
* version. See http://www.gnu.org/copyleft/gpl.html the full text of the
12
#include "ldm-marshal.h"
13
#include "pam-session.h"
16
AUTHENTICATION_STARTED,
19
AUTHENTICATION_RESULT,
23
static guint signals[LAST_SIGNAL] = { 0 };
25
struct PAMSessionPrivate
27
/* User being authenticated */
30
/* Authentication thread */
31
GThread *authentication_thread;
33
/* TRUE if the thread is being intentionally stopped */
36
/* Messages requested */
38
const struct pam_message **messages;
41
/* Queue to feed responses to the authentication thread */
42
GAsyncQueue *authentication_response_queue;
44
/* Authentication handle */
45
pam_handle_t *pam_handle;
47
/* TRUE if in a session */
51
G_DEFINE_TYPE (PAMSession, pam_session, G_TYPE_OBJECT);
54
pam_session_new (const gchar *username)
56
PAMSession *self = g_object_new (PAM_SESSION_TYPE, NULL);
58
self->priv->username = g_strdup (username);
64
pam_session_get_in_session (PAMSession *session)
66
return session->priv->in_session;
70
pam_session_authorize (PAMSession *session)
72
session->priv->in_session = TRUE;
75
//pam_set_item (session->priv->pam_handle, PAM_TTY, &tty);
76
//pam_set_item (session->priv->pam_handle, PAM_XDISPLAY, &display);
78
pam_open_session (session->priv->pam_handle, 0);
79
g_signal_emit (G_OBJECT (session), signals[STARTED], 0);
83
notify_messages_cb (gpointer data)
85
PAMSession *session = data;
87
g_signal_emit (G_OBJECT (session), signals[GOT_MESSAGES], 0, session->priv->num_messages, session->priv->messages);
93
pam_conv_cb (int num_msg, const struct pam_message **msg,
94
struct pam_response **resp, void *app_data)
96
PAMSession *session = app_data;
97
struct pam_response *response;
99
/* Cancelled by user */
100
if (session->priv->stop)
104
session->priv->num_messages = num_msg;
105
session->priv->messages = msg;
106
g_idle_add (notify_messages_cb, session);
108
/* Wait for response */
109
response = g_async_queue_pop (session->priv->authentication_response_queue);
110
session->priv->num_messages = 0;
111
session->priv->messages = NULL;
113
/* Cancelled by user */
114
if (session->priv->stop)
123
notify_auth_complete_cb (gpointer data)
125
PAMSession *session = data;
128
result = session->priv->result;
129
session->priv->result = 0;
131
g_thread_join (session->priv->authentication_thread);
132
session->priv->authentication_thread = NULL;
133
g_async_queue_unref (session->priv->authentication_response_queue);
134
session->priv->authentication_response_queue = NULL;
136
/* Authentication was cancelled */
137
if (session->priv->stop)
138
pam_session_end (session);
141
g_signal_emit (G_OBJECT (session), signals[AUTHENTICATION_RESULT], 0, result);
142
if (result == PAM_SUCCESS)
143
pam_session_authorize (session);
146
/* The thread is complete, drop the reference */
147
g_object_unref (session);
153
authenticate_cb (gpointer data)
155
PAMSession *session = data;
156
struct pam_conv conversation = { pam_conv_cb, session };
158
pam_start ("check_pass", session->priv->username, &conversation, &session->priv->pam_handle);
159
session->priv->result = pam_authenticate (session->priv->pam_handle, 0);
161
g_debug ("pam_authenticate -> %s", pam_strerror (session->priv->pam_handle, session->priv->result));
164
g_idle_add (notify_auth_complete_cb, session);
170
pam_session_start (PAMSession *session, GError **error)
172
g_return_val_if_fail (session->priv->authentication_thread == NULL, FALSE);
174
g_signal_emit (G_OBJECT (session), signals[AUTHENTICATION_STARTED], 0);
176
/* Hold a reference to this object while the thread may access it */
177
g_object_ref (session);
180
session->priv->authentication_response_queue = g_async_queue_new ();
181
session->priv->authentication_thread = g_thread_create (authenticate_cb, session, TRUE, error);
182
if (!session->priv->authentication_thread)
189
pam_session_strerror (PAMSession *session, int error)
191
return pam_strerror (session->priv->pam_handle, error);
195
pam_session_get_username (PAMSession *session)
197
return session->priv->username;
200
const struct pam_message **
201
pam_session_get_messages (PAMSession *session)
203
return session->priv->messages;
207
pam_session_get_num_messages (PAMSession *session)
209
return session->priv->num_messages;
213
pam_session_respond (PAMSession *session, struct pam_response *response)
215
g_return_if_fail (session->priv->authentication_thread != NULL);
216
g_async_queue_push (session->priv->authentication_response_queue, response);
220
pam_session_end (PAMSession *session)
222
/* If authenticating cancel first */
223
if (session->priv->authentication_thread)
225
session->priv->stop = TRUE;
226
g_async_queue_push (session->priv->authentication_response_queue, GINT_TO_POINTER (-1));
228
else if (session->priv->in_session)
230
pam_close_session (session->priv->pam_handle, 0);
231
session->priv->in_session = FALSE;
232
g_signal_emit (G_OBJECT (session), signals[ENDED], 0);
237
pam_session_init (PAMSession *session)
239
session->priv = G_TYPE_INSTANCE_GET_PRIVATE (session, PAM_SESSION_TYPE, PAMSessionPrivate);
243
pam_session_finalize (GObject *object)
247
self = PAM_SESSION (object);
249
pam_session_end (self);
251
g_free (self->priv->username);
252
if (self->priv->pam_handle)
253
pam_end (self->priv->pam_handle, PAM_SUCCESS);
257
pam_session_class_init (PAMSessionClass *klass)
259
GObjectClass *object_class = G_OBJECT_CLASS (klass);
261
object_class->finalize = pam_session_finalize;
263
g_type_class_add_private (klass, sizeof (PAMSessionPrivate));
265
signals[AUTHENTICATION_STARTED] =
266
g_signal_new ("authentication-started",
267
G_TYPE_FROM_CLASS (klass),
269
G_STRUCT_OFFSET (PAMSessionClass, authentication_started),
271
g_cclosure_marshal_VOID__VOID,
275
g_signal_new ("started",
276
G_TYPE_FROM_CLASS (klass),
278
G_STRUCT_OFFSET (PAMSessionClass, started),
280
g_cclosure_marshal_VOID__VOID,
283
signals[GOT_MESSAGES] =
284
g_signal_new ("got-messages",
285
G_TYPE_FROM_CLASS (klass),
287
G_STRUCT_OFFSET (PAMSessionClass, got_messages),
289
ldm_marshal_VOID__INT_POINTER,
290
G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_POINTER);
292
signals[AUTHENTICATION_RESULT] =
293
g_signal_new ("authentication-result",
294
G_TYPE_FROM_CLASS (klass),
296
G_STRUCT_OFFSET (PAMSessionClass, authentication_result),
298
g_cclosure_marshal_VOID__INT,
299
G_TYPE_NONE, 1, G_TYPE_INT);
302
g_signal_new ("ended",
303
G_TYPE_FROM_CLASS (klass),
305
G_STRUCT_OFFSET (PAMSessionClass, ended),
307
g_cclosure_marshal_VOID__VOID,