File: | rc/gs-auth-pam.c |
Warning: | line 405, column 2 Value stored to 'status' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- |
2 | * |
3 | * Copyright (C) 2006 William Jon McCann <mccann@jhu.edu> |
4 | * Copyright (C) 2006 Ray Strode <rstrode@redhat.com> |
5 | * Copyright (C) 2003 Bill Nottingham <notting@redhat.com> |
6 | * Copyright (c) 1993-2003 Jamie Zawinski <jwz@jwz.org> |
7 | * |
8 | * This program is free software; you can redistribute it and/or |
9 | * modify it under the terms of the GNU General Public License as |
10 | * published by the Free Software Foundation; either version 2 of the |
11 | * License, or (at your option) any later version. |
12 | * |
13 | * This program is distributed in the hope that it will be useful, but |
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | * General Public License for more details. |
17 | * |
18 | * You should have received a copy of the GNU General Public License |
19 | * along with this program; if not, write to the Free Software |
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA |
21 | * 02110-1301, USA. |
22 | * |
23 | */ |
24 | |
25 | #include "config.h" |
26 | |
27 | #include <stdlib.h> |
28 | #ifdef HAVE_UNISTD_H1 |
29 | # include <unistd.h> |
30 | #endif |
31 | |
32 | #include <fcntl.h> |
33 | #include <stdio.h> |
34 | #include <string.h> |
35 | #include <sys/types.h> |
36 | #include <pwd.h> |
37 | #include <grp.h> |
38 | #include <security/pam_appl.h> |
39 | #include <signal.h> |
40 | #include <errno(*__errno_location ()).h> |
41 | |
42 | #include <glib.h> |
43 | #include <glib/gstdio.h> |
44 | #include <glib/gi18n.h> |
45 | #include <ctk/ctk.h> |
46 | |
47 | #include "gs-auth.h" |
48 | |
49 | #include "subprocs.h" |
50 | |
51 | /* Some time between Red Hat 4.2 and 7.0, the words were transposed |
52 | in the various PAM_x_CRED macro names. Yay! |
53 | */ |
54 | #ifndef PAM_REFRESH_CRED0x0010U |
55 | # define PAM_REFRESH_CRED0x0010U PAM_CRED_REFRESH |
56 | #endif |
57 | |
58 | #ifdef HAVE_PAM_FAIL_DELAY |
59 | /* We handle delays ourself.*/ |
60 | /* Don't set this to 0 (Linux bug workaround.) */ |
61 | # define PAM_NO_DELAY(pamh)pam_fail_delay ((pamh), 1) pam_fail_delay ((pamh), 1) |
62 | #else /* !HAVE_PAM_FAIL_DELAY */ |
63 | # define PAM_NO_DELAY(pamh)pam_fail_delay ((pamh), 1) /* */ |
64 | #endif /* !HAVE_PAM_FAIL_DELAY */ |
65 | |
66 | |
67 | /* On SunOS 5.6, and on Linux with PAM 0.64, pam_strerror() takes two args. |
68 | On some other Linux systems with some other version of PAM (e.g., |
69 | whichever Debian release comes with a 2.2.5 kernel) it takes one arg. |
70 | I can't tell which is more "recent" or "correct" behavior, so configure |
71 | figures out which is in use for us. Shoot me! |
72 | */ |
73 | #ifdef PAM_STRERROR_TWO_ARGS1 |
74 | # define PAM_STRERROR(pamh, status)pam_strerror((pamh), (status)) pam_strerror((pamh), (status)) |
75 | #else /* !PAM_STRERROR_TWO_ARGS */ |
76 | # define PAM_STRERROR(pamh, status)pam_strerror((pamh), (status)) pam_strerror((status)) |
77 | #endif /* !PAM_STRERROR_TWO_ARGS */ |
78 | |
79 | static gboolean verbose_enabled = FALSE(0); |
80 | static pam_handle_t *pam_handle = NULL((void*)0); |
81 | static gboolean did_we_ask_for_password = FALSE(0); |
82 | |
83 | struct pam_closure |
84 | { |
85 | const char *username; |
86 | GSAuthMessageFunc cb_func; |
87 | gpointer cb_data; |
88 | int signal_fd; |
89 | int result; |
90 | }; |
91 | |
92 | typedef struct |
93 | { |
94 | struct pam_closure *closure; |
95 | GSAuthMessageStyle style; |
96 | const char *msg; |
97 | char **resp; |
98 | gboolean should_interrupt_stack; |
99 | } GsAuthMessageHandlerData; |
100 | |
101 | static GCond message_handled_condition; |
102 | static GMutex message_handler_mutex; |
103 | |
104 | GQuark |
105 | gs_auth_error_quark (void) |
106 | { |
107 | static GQuark quark = 0; |
108 | if (! quark) |
109 | { |
110 | quark = g_quark_from_static_string ("gs_auth_error"); |
111 | } |
112 | |
113 | return quark; |
114 | } |
115 | |
116 | void |
117 | gs_auth_set_verbose (gboolean enabled) |
118 | { |
119 | verbose_enabled = enabled; |
120 | } |
121 | |
122 | gboolean |
123 | gs_auth_get_verbose (void) |
124 | { |
125 | return verbose_enabled; |
126 | } |
127 | |
128 | static GSAuthMessageStyle |
129 | pam_style_to_gs_style (int pam_style) |
130 | { |
131 | GSAuthMessageStyle style; |
132 | |
133 | switch (pam_style) |
134 | { |
135 | case PAM_PROMPT_ECHO_ON2: |
136 | style = GS_AUTH_MESSAGE_PROMPT_ECHO_ON; |
137 | break; |
138 | case PAM_PROMPT_ECHO_OFF1: |
139 | style = GS_AUTH_MESSAGE_PROMPT_ECHO_OFF; |
140 | break; |
141 | case PAM_ERROR_MSG3: |
142 | style = GS_AUTH_MESSAGE_ERROR_MSG; |
143 | break; |
144 | case PAM_TEXT_INFO4: |
145 | style = GS_AUTH_MESSAGE_TEXT_INFO; |
146 | break; |
147 | default: |
148 | g_assert_not_reached ()do { (void) 0; __builtin_unreachable (); } while (0); |
149 | break; |
150 | } |
151 | |
152 | return style; |
153 | } |
154 | |
155 | static gboolean |
156 | auth_message_handler (GSAuthMessageStyle style, |
157 | const char *msg, |
158 | char **response, |
159 | gpointer data) |
160 | { |
161 | gboolean ret; |
162 | |
163 | ret = TRUE(!(0)); |
164 | *response = NULL((void*)0); |
165 | |
166 | switch (style) |
167 | { |
168 | case GS_AUTH_MESSAGE_PROMPT_ECHO_ON: |
169 | break; |
170 | case GS_AUTH_MESSAGE_PROMPT_ECHO_OFF: |
171 | if (msg != NULL((void*)0) && g_str_has_prefix (msg, _("Password:"))(__builtin_constant_p (gettext ("Password:"))? __extension__ ( { const char * const __str = (msg); const char * const __prefix = (gettext ("Password:")); gboolean __result = (0); if (__str == ((void*)0) || __prefix == ((void*)0)) __result = (g_str_has_prefix ) (__str, __prefix); else { const size_t __str_len = strlen ( ((__str) + !(__str))); const size_t __prefix_len = strlen ((( __prefix) + !(__prefix))); if (__str_len >= __prefix_len) __result = memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len ) == 0; } __result; }) : (g_str_has_prefix) (msg, gettext ("Password:" )) )) |
172 | { |
173 | did_we_ask_for_password = TRUE(!(0)); |
174 | } |
175 | break; |
176 | case GS_AUTH_MESSAGE_ERROR_MSG: |
177 | break; |
178 | case GS_AUTH_MESSAGE_TEXT_INFO: |
179 | break; |
180 | default: |
181 | g_assert_not_reached ()do { (void) 0; __builtin_unreachable (); } while (0); |
182 | } |
183 | |
184 | return ret; |
185 | } |
186 | |
187 | static gboolean |
188 | gs_auth_queued_message_handler (GsAuthMessageHandlerData *data) |
189 | { |
190 | gboolean res; |
191 | |
192 | if (gs_auth_get_verbose ()) |
193 | { |
194 | g_message ("Waiting for lock"); |
195 | } |
196 | |
197 | g_mutex_lock (&message_handler_mutex); |
198 | |
199 | if (gs_auth_get_verbose ()) |
200 | { |
201 | g_message ("Waiting for response"); |
202 | } |
203 | |
204 | res = data->closure->cb_func (data->style, |
205 | data->msg, |
206 | data->resp, |
207 | data->closure->cb_data); |
208 | |
209 | data->should_interrupt_stack = res == FALSE(0); |
210 | |
211 | g_cond_signal (&message_handled_condition); |
212 | g_mutex_unlock (&message_handler_mutex); |
213 | |
214 | if (gs_auth_get_verbose ()) |
215 | { |
216 | g_message ("Got response"); |
217 | } |
218 | |
219 | return FALSE(0); |
220 | } |
221 | |
222 | static gboolean |
223 | gs_auth_run_message_handler (struct pam_closure *c, |
224 | GSAuthMessageStyle style, |
225 | const char *msg, |
226 | char **resp) |
227 | { |
228 | GsAuthMessageHandlerData data; |
229 | |
230 | data.closure = c; |
231 | data.style = style; |
232 | data.msg = msg; |
233 | data.resp = resp; |
234 | data.should_interrupt_stack = TRUE(!(0)); |
235 | |
236 | g_mutex_lock (&message_handler_mutex); |
237 | |
238 | /* Queue the callback in the gui (the main) thread |
239 | */ |
240 | g_idle_add ((GSourceFunc) gs_auth_queued_message_handler, &data); |
241 | |
242 | if (gs_auth_get_verbose ()) |
243 | { |
244 | g_message ("Waiting for respose to message style %d: '%s'", style, msg); |
245 | } |
246 | |
247 | /* Wait for the response |
248 | */ |
249 | g_cond_wait (&message_handled_condition, |
250 | &message_handler_mutex); |
251 | g_mutex_unlock (&message_handler_mutex); |
252 | |
253 | if (gs_auth_get_verbose ()) |
254 | { |
255 | g_message ("Got respose to message style %d: interrupt:%d", style, data.should_interrupt_stack); |
256 | } |
257 | |
258 | return data.should_interrupt_stack == FALSE(0); |
259 | } |
260 | |
261 | static int |
262 | pam_conversation (int nmsgs, |
263 | const struct pam_message **msg, |
264 | struct pam_response **resp, |
265 | void *closure) |
266 | { |
267 | int replies = 0; |
268 | struct pam_response *reply = NULL((void*)0); |
269 | struct pam_closure *c = (struct pam_closure *) closure; |
270 | gboolean res; |
271 | int ret; |
272 | |
273 | reply = (struct pam_response *) calloc (nmsgs, sizeof (*reply)); |
274 | |
275 | if (reply == NULL((void*)0)) |
276 | { |
277 | return PAM_CONV_ERR19; |
278 | } |
279 | |
280 | res = TRUE(!(0)); |
281 | ret = PAM_SUCCESS0; |
282 | |
283 | for (replies = 0; replies < nmsgs && ret == PAM_SUCCESS0; replies++) |
284 | { |
285 | GSAuthMessageStyle style; |
286 | char *utf8_msg; |
287 | |
288 | style = pam_style_to_gs_style (msg [replies]->msg_style); |
289 | |
290 | utf8_msg = g_locale_to_utf8 (msg [replies]->msg, |
291 | -1, |
292 | NULL((void*)0), |
293 | NULL((void*)0), |
294 | NULL((void*)0)); |
295 | |
296 | /* if we couldn't convert text from locale then |
297 | * assume utf-8 and hope for the best */ |
298 | if (utf8_msg == NULL((void*)0)) |
299 | { |
300 | char *p; |
301 | char *q; |
302 | |
303 | utf8_msg = g_strdup (msg [replies]->msg)g_strdup_inline (msg [replies]->msg); |
304 | |
305 | p = utf8_msg; |
306 | while (*p != '\0' && !g_utf8_validate ((const char *)p, -1, (const char **)&q)) |
307 | { |
308 | *q = '?'; |
309 | p = q + 1; |
310 | } |
311 | } |
312 | |
313 | /* handle message locally first */ |
314 | auth_message_handler (style, |
315 | utf8_msg, |
316 | &reply [replies].resp, |
317 | NULL((void*)0)); |
318 | |
319 | if (c->cb_func != NULL((void*)0)) |
320 | { |
321 | if (gs_auth_get_verbose ()) |
322 | { |
323 | g_message ("Handling message style %d: '%s'", style, utf8_msg); |
324 | } |
325 | |
326 | /* blocks until the gui responds |
327 | */ |
328 | res = gs_auth_run_message_handler (c, |
329 | style, |
330 | utf8_msg, |
331 | &reply [replies].resp); |
332 | |
333 | if (gs_auth_get_verbose ()) |
334 | { |
335 | g_message ("Msg handler returned %d", res); |
336 | } |
337 | |
338 | /* If the handler returns FALSE - interrupt the PAM stack */ |
339 | if (res) |
340 | { |
341 | reply [replies].resp_retcode = PAM_SUCCESS0; |
342 | } |
343 | else |
344 | { |
345 | int i; |
346 | for (i = 0; i <= replies; i++) |
347 | { |
348 | free (reply [i].resp); |
349 | } |
350 | free (reply); |
351 | reply = NULL((void*)0); |
352 | ret = PAM_CONV_ERR19; |
353 | } |
354 | } |
355 | |
356 | g_free (utf8_msg); |
357 | } |
358 | |
359 | *resp = reply; |
360 | |
361 | return ret; |
362 | } |
363 | |
364 | static gboolean |
365 | close_pam_handle (int status) |
366 | { |
367 | |
368 | if (pam_handle != NULL((void*)0)) |
369 | { |
370 | int status2; |
371 | |
372 | status2 = pam_end (pam_handle, status); |
373 | pam_handle = NULL((void*)0); |
374 | |
375 | if (gs_auth_get_verbose ()) |
376 | { |
377 | g_message (" pam_end (...) ==> %d (%s)", |
378 | status2, |
379 | (status2 == PAM_SUCCESS0 ? "Success" : "Failure")); |
380 | } |
381 | } |
382 | |
383 | return TRUE(!(0)); |
384 | } |
385 | |
386 | static gboolean |
387 | create_pam_handle (const char *username, |
388 | const char *display, |
389 | struct pam_conv *conv, |
390 | int *status_code) |
391 | { |
392 | int status; |
393 | const char *service = PAM_SERVICE_NAME"cafe-screensaver"; |
394 | char *disp; |
395 | gboolean ret; |
396 | |
397 | if (pam_handle != NULL((void*)0)) |
398 | { |
399 | g_warning ("create_pam_handle: Stale pam handle around, cleaning up"); |
400 | close_pam_handle (PAM_SUCCESS0); |
401 | } |
402 | |
403 | /* init things */ |
404 | pam_handle = NULL((void*)0); |
405 | status = -1; |
Value stored to 'status' is never read | |
406 | disp = NULL((void*)0); |
407 | ret = TRUE(!(0)); |
408 | |
409 | /* Initialize a PAM session for the user */ |
410 | if ((status = pam_start (service, username, conv, &pam_handle)) != PAM_SUCCESS0) |
411 | { |
412 | pam_handle = NULL((void*)0); |
413 | g_warning (_("Unable to establish service %s: %s\n")gettext ("Unable to establish service %s: %s\n"), |
414 | service, |
415 | PAM_STRERROR (NULL, status)pam_strerror((((void*)0)), (status))); |
416 | |
417 | if (status_code != NULL((void*)0)) |
418 | { |
419 | *status_code = status; |
420 | } |
421 | |
422 | ret = FALSE(0); |
423 | goto out; |
424 | } |
425 | |
426 | if (gs_auth_get_verbose ()) |
427 | { |
428 | g_message ("pam_start (\"%s\", \"%s\", ...) ==> %d (%s)", |
429 | service, |
430 | username, |
431 | status, |
432 | PAM_STRERROR (pam_handle, status)pam_strerror((pam_handle), (status))); |
433 | } |
434 | |
435 | disp = g_strdup (display)g_strdup_inline (display); |
436 | if (disp == NULL((void*)0)) |
437 | { |
438 | disp = g_strdup (":0.0")g_strdup_inline (":0.0"); |
439 | } |
440 | |
441 | if ((status = pam_set_item (pam_handle, PAM_TTY3, disp)) != PAM_SUCCESS0) |
442 | { |
443 | g_warning (_("Can't set PAM_TTY=%s")gettext ("Can't set PAM_TTY=%s"), display); |
444 | |
445 | if (status_code != NULL((void*)0)) |
446 | { |
447 | *status_code = status; |
448 | } |
449 | |
450 | ret = FALSE(0); |
451 | goto out; |
452 | } |
453 | |
454 | ret = TRUE(!(0)); |
455 | g_cond_init (&message_handled_condition); |
456 | g_mutex_init (&message_handler_mutex); |
457 | |
458 | out: |
459 | if (status_code != NULL((void*)0)) |
460 | { |
461 | *status_code = status; |
462 | } |
463 | |
464 | g_free (disp); |
465 | |
466 | return ret; |
467 | } |
468 | |
469 | static void |
470 | set_pam_error (GError **error, |
471 | int status) |
472 | { |
473 | if (status == PAM_AUTH_ERR7 || status == PAM_USER_UNKNOWN10) |
474 | { |
475 | char *msg; |
476 | |
477 | if (did_we_ask_for_password) |
478 | { |
479 | msg = g_strdup (_("Incorrect password."))g_strdup_inline (gettext ("Incorrect password.")); |
480 | } |
481 | else |
482 | { |
483 | msg = g_strdup (_("Authentication failed."))g_strdup_inline (gettext ("Authentication failed.")); |
484 | } |
485 | |
486 | g_set_error (error, |
487 | GS_AUTH_ERRORgs_auth_error_quark (), |
488 | GS_AUTH_ERROR_AUTH_ERROR, |
489 | "%s", |
490 | msg); |
491 | g_free (msg); |
492 | } |
493 | else if (status == PAM_PERM_DENIED6) |
494 | { |
495 | g_set_error (error, |
496 | GS_AUTH_ERRORgs_auth_error_quark (), |
497 | GS_AUTH_ERROR_AUTH_DENIED, |
498 | "%s", |
499 | _("Not permitted to gain access at this time.")gettext ("Not permitted to gain access at this time.")); |
500 | } |
501 | else if (status == PAM_ACCT_EXPIRED13) |
502 | { |
503 | g_set_error (error, |
504 | GS_AUTH_ERRORgs_auth_error_quark (), |
505 | GS_AUTH_ERROR_AUTH_DENIED, |
506 | "%s", |
507 | _("No longer permitted to access the system.")gettext ("No longer permitted to access the system.")); |
508 | } |
509 | |
510 | } |
511 | |
512 | static int |
513 | gs_auth_thread_func (int auth_operation_fd) |
514 | { |
515 | static const int flags = 0; |
516 | int status; |
517 | int status2; |
518 | struct timespec timeout; |
519 | sigset_t set; |
520 | const void *p; |
521 | |
522 | timeout.tv_sec = 0; |
523 | timeout.tv_nsec = 1; |
524 | |
525 | set = block_sigchld (); |
526 | |
527 | status = pam_authenticate (pam_handle, flags); |
528 | |
529 | sigtimedwait (&set, NULL((void*)0), &timeout); |
530 | unblock_sigchld (); |
531 | |
532 | if (gs_auth_get_verbose ()) |
533 | { |
534 | g_message (" pam_authenticate (...) ==> %d (%s)", |
535 | status, |
536 | PAM_STRERROR (pam_handle, status)pam_strerror((pam_handle), (status))); |
537 | } |
538 | |
539 | if (status != PAM_SUCCESS0) |
540 | { |
541 | goto done; |
542 | } |
543 | |
544 | if ((status = pam_get_item (pam_handle, PAM_USER2, &p)) != PAM_SUCCESS0) |
545 | { |
546 | /* is not really an auth problem, but it will |
547 | pretty much look as such, it shouldn't really |
548 | happen */ |
549 | goto done; |
550 | } |
551 | |
552 | /* We don't actually care if the account modules fail or succeed, |
553 | * but we need to run them anyway because certain pam modules |
554 | * depend on side effects of the account modules getting run. |
555 | */ |
556 | status2 = pam_acct_mgmt (pam_handle, 0); |
557 | |
558 | if (gs_auth_get_verbose ()) |
559 | { |
560 | g_message ("pam_acct_mgmt (...) ==> %d (%s)\n", |
561 | status2, |
562 | PAM_STRERROR (pam_handle, status2)pam_strerror((pam_handle), (status2))); |
563 | } |
564 | |
565 | /* FIXME: should we handle these? */ |
566 | switch (status2) |
567 | { |
568 | case PAM_SUCCESS0: |
569 | break; |
570 | case PAM_NEW_AUTHTOK_REQD12: |
571 | break; |
572 | case PAM_AUTHINFO_UNAVAIL9: |
573 | break; |
574 | case PAM_ACCT_EXPIRED13: |
575 | break; |
576 | case PAM_PERM_DENIED6: |
577 | break; |
578 | default : |
579 | break; |
580 | } |
581 | |
582 | /* Each time we successfully authenticate, refresh credentials, |
583 | for Kerberos/AFS/DCE/etc. If this fails, just ignore that |
584 | failure and blunder along; it shouldn't matter. |
585 | |
586 | Note: this used to be PAM_REFRESH_CRED instead of |
587 | PAM_REINITIALIZE_CRED, but Jason Heiss <jheiss@ee.washington.edu> |
588 | says that the Linux PAM library ignores that one, and only refreshes |
589 | credentials when using PAM_REINITIALIZE_CRED. |
590 | */ |
591 | status2 = pam_setcred (pam_handle, PAM_REINITIALIZE_CRED0x0008U); |
592 | if (gs_auth_get_verbose ()) |
593 | { |
594 | g_message (" pam_setcred (...) ==> %d (%s)", |
595 | status2, |
596 | PAM_STRERROR (pam_handle, status2)pam_strerror((pam_handle), (status2))); |
597 | } |
598 | |
599 | done: |
600 | /* we're done, close the fd and wake up the main |
601 | * loop |
602 | */ |
603 | close (auth_operation_fd); |
604 | |
605 | return status; |
606 | } |
607 | |
608 | static gboolean |
609 | gs_auth_loop_quit (GIOChannel *source, |
610 | GIOCondition condition, |
611 | gboolean *thread_done) |
612 | { |
613 | *thread_done = TRUE(!(0)); |
614 | ctk_main_quit (); |
615 | return FALSE(0); |
616 | } |
617 | |
618 | static gboolean |
619 | gs_auth_pam_verify_user (pam_handle_t *handle, |
620 | int *status) |
621 | { |
622 | GThread *auth_thread; |
623 | GIOChannel *channel; |
624 | guint watch_id; |
625 | int auth_operation_fds[2]; |
626 | int auth_status; |
627 | gboolean thread_done; |
628 | |
629 | channel = NULL((void*)0); |
630 | watch_id = 0; |
631 | auth_status = PAM_AUTH_ERR7; |
632 | |
633 | /* This pipe gives us a set of fds we can hook into |
634 | * the event loop to be notified when our helper thread |
635 | * is ready to be reaped. |
636 | */ |
637 | if (pipe (auth_operation_fds) < 0) |
638 | { |
639 | goto out; |
640 | } |
641 | |
642 | if (fcntl (auth_operation_fds[0], F_SETFD2, FD_CLOEXEC1) < 0) |
643 | { |
644 | close (auth_operation_fds[0]); |
645 | close (auth_operation_fds[1]); |
646 | goto out; |
647 | } |
648 | |
649 | if (fcntl (auth_operation_fds[1], F_SETFD2, FD_CLOEXEC1) < 0) |
650 | { |
651 | close (auth_operation_fds[0]); |
652 | close (auth_operation_fds[1]); |
653 | goto out; |
654 | } |
655 | |
656 | channel = g_io_channel_unix_new (auth_operation_fds[0]); |
657 | |
658 | /* we use a recursive main loop to process ui events |
659 | * while we wait on a thread to handle the blocking parts |
660 | * of pam authentication. |
661 | */ |
662 | thread_done = FALSE(0); |
663 | watch_id = g_io_add_watch (channel, G_IO_ERR | G_IO_HUP, |
664 | (GIOFunc) gs_auth_loop_quit, &thread_done); |
665 | |
666 | auth_thread = g_thread_new ("auththread", |
667 | (GThreadFunc) gs_auth_thread_func, |
668 | GINT_TO_POINTER (auth_operation_fds[1])((gpointer) (glong) (auth_operation_fds[1]))); |
669 | |
670 | if (auth_thread == NULL((void*)0)) |
671 | { |
672 | goto out; |
673 | } |
674 | |
675 | ctk_main (); |
676 | |
677 | /* if the event loop was quit before the thread is done then we can't |
678 | * reap the thread without blocking on it finishing. The |
679 | * thread may not ever finish though if the pam module is blocking. |
680 | * |
681 | * The only time the event loop is going to stop when the thread isn't |
682 | * done, however, is if the dialog quits early (from, e.g., "cancel"), |
683 | * so we can just exit. An alternative option would be to switch to |
684 | * using pthreads directly and calling pthread_cancel. |
685 | */ |
686 | if (!thread_done) |
687 | { |
688 | raise (SIGTERM15); |
689 | } |
690 | |
691 | auth_status = GPOINTER_TO_INT (g_thread_join (auth_thread))((gint) (glong) (g_thread_join (auth_thread))); |
692 | |
693 | out: |
694 | if (watch_id != 0) |
695 | { |
696 | g_source_remove (watch_id); |
697 | watch_id = 0; |
698 | } |
699 | |
700 | if (channel != NULL((void*)0)) |
701 | { |
702 | g_io_channel_unref (channel); |
703 | } |
704 | |
705 | if (status) |
706 | { |
707 | *status = auth_status; |
708 | } |
709 | |
710 | return auth_status == PAM_SUCCESS0; |
711 | } |
712 | |
713 | gboolean |
714 | gs_auth_verify_user (const char *username, |
715 | const char *display, |
716 | GSAuthMessageFunc func, |
717 | gpointer data, |
718 | GError **error) |
719 | { |
720 | int status = -1; |
721 | struct pam_conv conv; |
722 | struct pam_closure c; |
723 | struct passwd *pwent; |
724 | |
725 | pwent = getpwnam (username); |
726 | if (pwent == NULL((void*)0)) |
727 | { |
728 | return FALSE(0); |
729 | } |
730 | |
731 | c.username = username; |
732 | c.cb_func = func; |
733 | c.cb_data = data; |
734 | |
735 | conv.conv = &pam_conversation; |
736 | conv.appdata_ptr = (void *) &c; |
737 | |
738 | /* Initialize PAM. */ |
739 | create_pam_handle (username, display, &conv, &status); |
740 | if (status != PAM_SUCCESS0) |
741 | { |
742 | goto done; |
743 | } |
744 | |
745 | pam_set_item (pam_handle, PAM_USER_PROMPT9, _("Username:")gettext ("Username:")); |
746 | |
747 | PAM_NO_DELAY(pam_handle)pam_fail_delay ((pam_handle), 1); |
748 | |
749 | did_we_ask_for_password = FALSE(0); |
750 | if (! gs_auth_pam_verify_user (pam_handle, &status)) |
751 | { |
752 | goto done; |
753 | } |
754 | |
755 | done: |
756 | if (status != PAM_SUCCESS0) |
757 | { |
758 | set_pam_error (error, status); |
759 | } |
760 | |
761 | close_pam_handle (status); |
762 | |
763 | return (status == PAM_SUCCESS0 ? TRUE(!(0)) : FALSE(0)); |
764 | } |
765 | |
766 | gboolean |
767 | gs_auth_init (void) |
768 | { |
769 | return TRUE(!(0)); |
770 | } |
771 | |
772 | gboolean |
773 | gs_auth_priv_init (void) |
774 | { |
775 | /* We have nothing to do at init-time. |
776 | However, we might as well do some error checking. |
777 | If "/etc/pam.d" exists and is a directory, but "/etc/pam.d/xlock" |
778 | does not exist, warn that PAM probably isn't going to work. |
779 | |
780 | This is a priv-init instead of a non-priv init in case the directory |
781 | is unreadable or something (don't know if that actually happens.) |
782 | */ |
783 | const char dir [] = "/etc/pam.d"; |
784 | const char file [] = "/etc/pam.d/" PAM_SERVICE_NAME"cafe-screensaver"; |
785 | const char file2 [] = "/etc/pam.conf"; |
786 | struct stat st; |
787 | |
788 | if (g_statstat (dir, &st) == 0 && st.st_mode & S_IFDIR0040000) |
789 | { |
790 | if (g_statstat (file, &st) != 0) |
791 | { |
792 | g_warning ("%s does not exist.\n" |
793 | "Authentication via PAM is unlikely to work.", |
794 | file); |
795 | } |
796 | } |
797 | else if (g_statstat (file2, &st) == 0) |
798 | { |
799 | FILE *f = g_fopenfopen (file2, "r"); |
800 | if (f) |
801 | { |
802 | gboolean ok = FALSE(0); |
803 | char buf[255]; |
804 | while (fgets (buf, sizeof(buf), f)) |
805 | { |
806 | if (strstr (buf, PAM_SERVICE_NAME"cafe-screensaver")) |
807 | { |
808 | ok = TRUE(!(0)); |
809 | break; |
810 | } |
811 | } |
812 | |
813 | fclose (f); |
814 | if (!ok) |
815 | { |
816 | g_warning ("%s does not list the `%s' service.\n" |
817 | "Authentication via PAM is unlikely to work.", |
818 | file2, PAM_SERVICE_NAME"cafe-screensaver"); |
819 | } |
820 | } |
821 | /* else warn about file2 existing but being unreadable? */ |
822 | } |
823 | else |
824 | { |
825 | g_warning ("Neither %s nor %s exist.\n" |
826 | "Authentication via PAM is unlikely to work.", |
827 | file2, file); |
828 | } |
829 | |
830 | /* Return true anyway, just in case. */ |
831 | return TRUE(!(0)); |
832 | } |