~lightdm-team/lightdm/1.4

« back to all changes in this revision

Viewing changes to src/pam-session.c

  • Committer: robert.ancell at gmail
  • Date: 2010-04-29 11:08:26 UTC
  • Revision ID: robert.ancell@gmail.com-20100429110826-eef3w3c9hl80pxxy
Compiles and does something

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (C) 2010 Robert Ancell.
3
 
 * Author: Robert Ancell <robert.ancell@canonical.com>
4
 
 * 
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
9
 
 * license.
10
 
 */
11
 
 
12
 
#include "ldm-marshal.h"
13
 
#include "pam-session.h"
14
 
 
15
 
enum {
16
 
    AUTHENTICATION_STARTED,
17
 
    STARTED,
18
 
    GOT_MESSAGES,
19
 
    AUTHENTICATION_RESULT,
20
 
    ENDED,
21
 
    LAST_SIGNAL
22
 
};
23
 
static guint signals[LAST_SIGNAL] = { 0 };
24
 
 
25
 
struct PAMSessionPrivate
26
 
{
27
 
    /* User being authenticated */
28
 
    gchar *username;
29
 
 
30
 
    /* Authentication thread */
31
 
    GThread *authentication_thread;
32
 
  
33
 
    /* TRUE if the thread is being intentionally stopped */
34
 
    gboolean stop;
35
 
 
36
 
    /* Messages requested */
37
 
    int num_messages;
38
 
    const struct pam_message **messages;
39
 
    int result;
40
 
 
41
 
    /* Queue to feed responses to the authentication thread */
42
 
    GAsyncQueue *authentication_response_queue;
43
 
 
44
 
    /* Authentication handle */
45
 
    pam_handle_t *pam_handle;
46
 
  
47
 
    /* TRUE if in a session */
48
 
    gboolean in_session;
49
 
};
50
 
 
51
 
G_DEFINE_TYPE (PAMSession, pam_session, G_TYPE_OBJECT);
52
 
 
53
 
PAMSession *
54
 
pam_session_new (const gchar *username)
55
 
{
56
 
    PAMSession *self = g_object_new (PAM_SESSION_TYPE, NULL);
57
 
 
58
 
    self->priv->username = g_strdup (username);
59
 
 
60
 
    return self;
61
 
}
62
 
 
63
 
gboolean
64
 
pam_session_get_in_session (PAMSession *session)
65
 
{
66
 
    return session->priv->in_session;
67
 
}
68
 
 
69
 
void
70
 
pam_session_authorize (PAMSession *session)
71
 
{
72
 
    session->priv->in_session = TRUE;
73
 
 
74
 
    // FIXME:
75
 
    //pam_set_item (session->priv->pam_handle, PAM_TTY, &tty);
76
 
    //pam_set_item (session->priv->pam_handle, PAM_XDISPLAY, &display);
77
 
 
78
 
    pam_open_session (session->priv->pam_handle, 0);
79
 
    g_signal_emit (G_OBJECT (session), signals[STARTED], 0);
80
 
}
81
 
 
82
 
static gboolean
83
 
notify_messages_cb (gpointer data)
84
 
{
85
 
    PAMSession *session = data;
86
 
 
87
 
    g_signal_emit (G_OBJECT (session), signals[GOT_MESSAGES], 0, session->priv->num_messages, session->priv->messages);
88
 
 
89
 
    return FALSE;
90
 
}
91
 
 
92
 
static int
93
 
pam_conv_cb (int num_msg, const struct pam_message **msg,
94
 
             struct pam_response **resp, void *app_data)
95
 
{
96
 
    PAMSession *session = app_data;
97
 
    struct pam_response *response;
98
 
 
99
 
    /* Cancelled by user */
100
 
    if (session->priv->stop)
101
 
        return PAM_CONV_ERR;
102
 
 
103
 
    /* Notify user */
104
 
    session->priv->num_messages = num_msg;
105
 
    session->priv->messages = msg;
106
 
    g_idle_add (notify_messages_cb, session);
107
 
 
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;
112
 
  
113
 
    /* Cancelled by user */
114
 
    if (session->priv->stop)
115
 
        return PAM_CONV_ERR;
116
 
 
117
 
    *resp = response;
118
 
 
119
 
    return PAM_SUCCESS;
120
 
}
121
 
 
122
 
static gboolean
123
 
notify_auth_complete_cb (gpointer data)
124
 
{
125
 
    PAMSession *session = data;
126
 
    int result;
127
 
 
128
 
    result = session->priv->result;
129
 
    session->priv->result = 0;
130
 
 
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;
135
 
 
136
 
    /* Authentication was cancelled */
137
 
    if (session->priv->stop)
138
 
        pam_session_end (session);
139
 
    else
140
 
    {
141
 
        g_signal_emit (G_OBJECT (session), signals[AUTHENTICATION_RESULT], 0, result);
142
 
        if (result == PAM_SUCCESS)
143
 
           pam_session_authorize (session);
144
 
    }
145
 
 
146
 
    /* The thread is complete, drop the reference */
147
 
    g_object_unref (session);
148
 
 
149
 
    return FALSE;
150
 
}
151
 
 
152
 
static gpointer
153
 
authenticate_cb (gpointer data)
154
 
{
155
 
    PAMSession *session = data;
156
 
    struct pam_conv conversation = { pam_conv_cb, session };
157
 
 
158
 
    pam_start ("check_pass", session->priv->username, &conversation, &session->priv->pam_handle);
159
 
    session->priv->result = pam_authenticate (session->priv->pam_handle, 0);
160
 
 
161
 
    g_debug ("pam_authenticate -> %s", pam_strerror (session->priv->pam_handle, session->priv->result));
162
 
 
163
 
    /* Notify user */
164
 
    g_idle_add (notify_auth_complete_cb, session);
165
 
 
166
 
    return NULL;
167
 
}
168
 
 
169
 
gboolean
170
 
pam_session_start (PAMSession *session, GError **error)
171
 
{
172
 
    g_return_val_if_fail (session->priv->authentication_thread == NULL, FALSE);
173
 
 
174
 
    g_signal_emit (G_OBJECT (session), signals[AUTHENTICATION_STARTED], 0);
175
 
  
176
 
    /* Hold a reference to this object while the thread may access it */
177
 
    g_object_ref (session);
178
 
 
179
 
    /* Start thread */
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)
183
 
        return FALSE;
184
 
 
185
 
    return TRUE;
186
 
}
187
 
 
188
 
const gchar *
189
 
pam_session_strerror (PAMSession *session, int error)
190
 
{
191
 
    return pam_strerror (session->priv->pam_handle, error);
192
 
}
193
 
 
194
 
const gchar *
195
 
pam_session_get_username (PAMSession *session)
196
 
{
197
 
    return session->priv->username;
198
 
}
199
 
 
200
 
const struct pam_message **
201
 
pam_session_get_messages (PAMSession *session)
202
 
{
203
 
    return session->priv->messages;  
204
 
}
205
 
 
206
 
gint
207
 
pam_session_get_num_messages (PAMSession *session)
208
 
{
209
 
    return session->priv->num_messages;
210
 
}
211
 
 
212
 
void
213
 
pam_session_respond (PAMSession *session, struct pam_response *response)
214
 
{
215
 
    g_return_if_fail (session->priv->authentication_thread != NULL);  
216
 
    g_async_queue_push (session->priv->authentication_response_queue, response);
217
 
}
218
 
 
219
 
void
220
 
pam_session_end (PAMSession *session)
221
 
222
 
    /* If authenticating cancel first */
223
 
    if (session->priv->authentication_thread)
224
 
    {
225
 
        session->priv->stop = TRUE;
226
 
        g_async_queue_push (session->priv->authentication_response_queue, GINT_TO_POINTER (-1));
227
 
    }
228
 
    else if (session->priv->in_session)
229
 
    {
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);
233
 
    }
234
 
}
235
 
 
236
 
static void
237
 
pam_session_init (PAMSession *session)
238
 
{
239
 
    session->priv = G_TYPE_INSTANCE_GET_PRIVATE (session, PAM_SESSION_TYPE, PAMSessionPrivate);
240
 
}
241
 
 
242
 
static void
243
 
pam_session_finalize (GObject *object)
244
 
{
245
 
    PAMSession *self;
246
 
 
247
 
    self = PAM_SESSION (object);
248
 
  
249
 
    pam_session_end (self);
250
 
 
251
 
    g_free (self->priv->username);
252
 
    if (self->priv->pam_handle)
253
 
        pam_end (self->priv->pam_handle, PAM_SUCCESS);
254
 
}
255
 
 
256
 
static void
257
 
pam_session_class_init (PAMSessionClass *klass)
258
 
{
259
 
    GObjectClass *object_class = G_OBJECT_CLASS (klass);
260
 
 
261
 
    object_class->finalize = pam_session_finalize;  
262
 
 
263
 
    g_type_class_add_private (klass, sizeof (PAMSessionPrivate));
264
 
 
265
 
    signals[AUTHENTICATION_STARTED] =
266
 
        g_signal_new ("authentication-started",
267
 
                      G_TYPE_FROM_CLASS (klass),
268
 
                      G_SIGNAL_RUN_LAST,
269
 
                      G_STRUCT_OFFSET (PAMSessionClass, authentication_started),
270
 
                      NULL, NULL,
271
 
                      g_cclosure_marshal_VOID__VOID,
272
 
                      G_TYPE_NONE, 0);
273
 
 
274
 
    signals[STARTED] =
275
 
        g_signal_new ("started",
276
 
                      G_TYPE_FROM_CLASS (klass),
277
 
                      G_SIGNAL_RUN_LAST,
278
 
                      G_STRUCT_OFFSET (PAMSessionClass, started),
279
 
                      NULL, NULL,
280
 
                      g_cclosure_marshal_VOID__VOID,
281
 
                      G_TYPE_NONE, 0);
282
 
 
283
 
    signals[GOT_MESSAGES] =
284
 
        g_signal_new ("got-messages",
285
 
                      G_TYPE_FROM_CLASS (klass),
286
 
                      G_SIGNAL_RUN_LAST,
287
 
                      G_STRUCT_OFFSET (PAMSessionClass, got_messages),
288
 
                      NULL, NULL,
289
 
                      ldm_marshal_VOID__INT_POINTER,
290
 
                      G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_POINTER);
291
 
 
292
 
    signals[AUTHENTICATION_RESULT] =
293
 
        g_signal_new ("authentication-result",
294
 
                      G_TYPE_FROM_CLASS (klass),
295
 
                      G_SIGNAL_RUN_LAST,
296
 
                      G_STRUCT_OFFSET (PAMSessionClass, authentication_result),
297
 
                      NULL, NULL,
298
 
                      g_cclosure_marshal_VOID__INT,
299
 
                      G_TYPE_NONE, 1, G_TYPE_INT);
300
 
 
301
 
    signals[ENDED] =
302
 
        g_signal_new ("ended",
303
 
                      G_TYPE_FROM_CLASS (klass),
304
 
                      G_SIGNAL_RUN_LAST,
305
 
                      G_STRUCT_OFFSET (PAMSessionClass, ended),
306
 
                      NULL, NULL,
307
 
                      g_cclosure_marshal_VOID__VOID,
308
 
                      G_TYPE_NONE, 0);
309
 
}