1
/* GDM - The Gnome Display Manager
2
* Copyright (C) 1999, 2000 Martin K. Petersen <mkp@mkp.net>
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
#include <sys/types.h>
25
#include <security/pam_appl.h>
36
/* Configuration option variables */
37
extern gboolean GdmAllowRoot;
38
extern gboolean GdmAllowRemoteRoot;
39
extern gchar *GdmTimedLogin;
40
extern gchar *GdmUser;
41
extern gboolean GdmAllowRemoteAutoLogin;
42
extern gint GdmRetryDelay;
44
/* Evil, but this way these things are passed to the child session */
45
static pam_handle_t *pamh = NULL;
47
static GdmDisplay *cur_gdm_disp = NULL;
50
/* Internal PAM conversation function. Interfaces between the PAM
51
* authentication system and the actual greeter program */
54
gdm_verify_pam_conv (int num_msg, const struct pam_message **msg,
55
struct pam_response **resp,
60
struct pam_response *reply = NULL;
62
reply = malloc (sizeof (struct pam_response) * num_msg);
67
memset (reply, 0, sizeof (struct pam_response) * num_msg);
69
for (replies = 0; replies < num_msg; replies++) {
71
switch (msg[replies]->msg_style) {
73
case PAM_PROMPT_ECHO_ON:
74
/* PAM requested textual input with echo on */
75
s = gdm_slave_greeter_ctl (GDM_PROMPT, _((gchar *) msg[replies]->msg));
76
if (gdm_slave_greeter_check_interruption (s)) {
81
reply[replies].resp_retcode = PAM_SUCCESS;
82
reply[replies].resp = strdup (ve_sure_string (s));
86
case PAM_PROMPT_ECHO_OFF:
87
/* PAM requested textual input with echo off */
88
s = gdm_slave_greeter_ctl (GDM_NOECHO, _((gchar *) msg[replies]->msg));
89
if (gdm_slave_greeter_check_interruption (s)) {
94
reply[replies].resp_retcode = PAM_SUCCESS;
95
reply[replies].resp = strdup (ve_sure_string (s));
100
/* PAM sent a message that should displayed to the user */
101
gdm_slave_greeter_ctl_no_ret (GDM_ERRDLG, _((gchar *) msg[replies]->msg));
102
reply[replies].resp_retcode = PAM_SUCCESS;
103
reply[replies].resp = NULL;
106
/* PAM sent a message that should displayed to the user */
107
gdm_slave_greeter_ctl_no_ret (GDM_MSG, _((gchar *) msg[replies]->msg));
108
reply[replies].resp_retcode = PAM_SUCCESS;
109
reply[replies].resp = NULL;
113
/* PAM has been smoking serious crack */
125
static struct pam_conv pamc = {
126
&gdm_verify_pam_conv,
131
gdm_verify_standalone_pam_conv (int num_msg, const struct pam_message **msg,
132
struct pam_response **resp,
137
struct pam_response *reply = NULL;
139
reply = malloc (sizeof (struct pam_response) * num_msg);
144
memset (reply, 0, sizeof (struct pam_response) * num_msg);
146
for (replies = 0; replies < num_msg; replies++) {
148
switch (msg[replies]->msg_style) {
150
case PAM_PROMPT_ECHO_ON:
151
/* PAM requested textual input with echo on */
152
s = gdm_failsafe_question (cur_gdm_disp,
153
_((gchar *) msg[replies]->msg),
155
reply[replies].resp_retcode = PAM_SUCCESS;
156
reply[replies].resp = strdup (ve_sure_string (s));
160
case PAM_PROMPT_ECHO_OFF:
161
/* PAM requested textual input with echo off */
162
s = gdm_failsafe_question (cur_gdm_disp,
163
_((gchar *) msg[replies]->msg),
165
reply[replies].resp_retcode = PAM_SUCCESS;
166
reply[replies].resp = strdup (ve_sure_string (s));
171
/* PAM sent a message that should displayed to the user */
172
gdm_error_box (cur_gdm_disp,
173
GNOME_MESSAGE_BOX_ERROR,
174
_((gchar *) msg[replies]->msg));
175
reply[replies].resp_retcode = PAM_SUCCESS;
176
reply[replies].resp = NULL;
180
/* PAM sent a message that should displayed to the user */
181
gdm_error_box (cur_gdm_disp,
182
GNOME_MESSAGE_BOX_INFO,
183
_((gchar *) msg[replies]->msg));
184
reply[replies].resp_retcode = PAM_SUCCESS;
185
reply[replies].resp = NULL;
189
/* PAM has been smoking serious crack */
200
static struct pam_conv standalone_pamc = {
201
&gdm_verify_standalone_pam_conv,
205
/* Creates a pam handle for the auto login */
207
create_pamh (GdmDisplay *d,
210
struct pam_conv *conv,
216
gdm_error (_("Cannot setup pam handle with null login "
222
gdm_error ("create_pamh: Stale pamh around, cleaning up");
223
pam_end (pamh, PAM_SUCCESS);
227
/* Initialize a PAM session for the user */
228
if ((*pamerr = pam_start (service, login, conv, &pamh)) != PAM_SUCCESS) {
229
if (gdm_slave_should_complain ())
230
gdm_error (_("Can't find /etc/pam.d/%s!"), service);
234
/* Inform PAM of the user's tty */
235
if ((*pamerr = pam_set_item (pamh, PAM_TTY, display)) != PAM_SUCCESS) {
236
if (gdm_slave_should_complain ())
237
gdm_error (_("Can't set PAM_TTY=%s"), display);
241
/* gdm is requesting the login */
242
if ((*pamerr = pam_set_item (pamh, PAM_RUSER, GdmUser)) != PAM_SUCCESS) {
243
if (gdm_slave_should_complain ())
244
gdm_error (_("Can't set PAM_RUSER=%s"), GdmUser);
248
/* From the host of the display */
249
if ((*pamerr = pam_set_item (pamh, PAM_RHOST,
250
d->console ? "localhost" : d->hostname)) != PAM_SUCCESS) {
251
if (gdm_slave_should_complain ())
252
gdm_error (_("Can't set PAM_RHOST=%s"),
253
d->console ? "localhost" : d->hostname);
263
* @username: Name of user or NULL if we should ask
264
* @display: Name of display to register with the authentication system
265
* @local: boolean if local
267
* Provides a communication layer between the operating system's
268
* authentication functions and the gdmgreeter.
270
* Returns the user's login on success and NULL on failure.
274
gdm_verify_user (GdmDisplay *d,
275
const char *username,
276
const gchar *display,
281
struct passwd *pwent;
282
gboolean error_msg_given = FALSE;
283
gboolean credentials_set = FALSE;
284
gboolean started_timer = FALSE;
287
/* start the timer for timed logins */
288
if ( ! ve_string_empty (GdmTimedLogin) &&
289
(local || GdmAllowRemoteAutoLogin)) {
290
gdm_slave_greeter_ctl_no_ret (GDM_STARTTIMER, "");
291
started_timer = TRUE;
294
if (username == NULL) {
295
/* Ask gdmgreeter for the user's login. Just for good measure */
296
gdm_slave_greeter_ctl_no_ret (GDM_MSG, _("Please enter your username"));
297
login = gdm_slave_greeter_ctl (GDM_LOGIN, _("Username:"));
299
gdm_slave_greeter_check_interruption (login)) {
301
gdm_slave_greeter_ctl_no_ret (GDM_STOPTIMER, "");
306
login = g_strdup (username);
311
/* Initialize a PAM session for the user */
312
if ( ! create_pamh (d, "gdm", login, &pamc, display, &pamerr)) {
314
gdm_slave_greeter_ctl_no_ret (GDM_STOPTIMER, "");
318
#ifdef PAM_FAIL_DELAY
319
pam_fail_delay (pamh, GdmRetryDelay * 1000);
320
#endif /* PAM_FAIL_DELAY */
322
/* Start authentication session */
323
if ((pamerr = pam_authenticate (pamh, 0)) != PAM_SUCCESS) {
324
#ifndef PAM_FAIL_DELAY
325
sleep (GdmRetryDelay);
326
#endif /* PAM_FAIL_DELAY */
328
gdm_slave_greeter_ctl_no_ret (GDM_STOPTIMER, "");
329
if (gdm_slave_should_complain ())
330
gdm_error (_("Couldn't authenticate user"));
334
/* stop the timer for timed logins */
336
gdm_slave_greeter_ctl_no_ret (GDM_STOPTIMER, "");
338
pwent = getpwnam (login);
339
if ( ( ! GdmAllowRoot ||
340
( ! GdmAllowRemoteRoot && ! local) ) &&
342
pwent->pw_uid == 0) {
343
gdm_error (_("Root login disallowed on display '%s'"),
345
gdm_slave_greeter_ctl_no_ret (GDM_ERRBOX,
346
_("\nThe system administrator"
347
" is not allowed to login "
348
"from this screen"));
349
/*gdm_slave_greeter_ctl_no_ret (GDM_ERRDLG,
350
_("Root login disallowed"));*/
351
error_msg_given = TRUE;
355
/* Check if the user's account is healthy. */
356
pamerr = pam_acct_mgmt (pamh, 0);
360
case PAM_NEW_AUTHTOK_REQD :
361
if ((pamerr = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK)) != PAM_SUCCESS) {
362
gdm_error (_("Authentication token change failed for user %s"), login);
363
gdm_slave_greeter_ctl_no_ret (GDM_ERRBOX,
364
_("\nThe change of the authentication token failed. "
365
"Please try again later or contact the system administrator."));
366
error_msg_given = TRUE;
370
case PAM_ACCT_EXPIRED :
371
gdm_error (_("User %s no longer permitted to access the system"), login);
372
gdm_slave_greeter_ctl_no_ret (GDM_ERRBOX,
373
_("\nThe system administrator has disabled your account."));
374
error_msg_given = TRUE;
376
case PAM_PERM_DENIED :
377
gdm_error (_("User %s not permitted to gain access at this time"), login);
378
gdm_slave_greeter_ctl_no_ret (GDM_ERRBOX,
379
_("\nThe system administrator has disabled access to the system temporary."));
380
error_msg_given = TRUE;
383
if (gdm_slave_should_complain ())
384
gdm_error (_("Couldn't set acct. mgmt for %s"), login);
388
pwent = getpwnam (login);
389
if (/* paranoia */ pwent == NULL ||
390
! gdm_setup_gids (login, pwent->pw_gid)) {
391
gdm_error (_("Cannot set user group for %s"), login);
392
gdm_slave_greeter_ctl_no_ret (GDM_ERRBOX,
393
_("\nCannot set your user group, "
394
"you will not be able to log in, "
395
"please contact your system administrator."));
399
/* Set credentials */
400
pamerr = pam_setcred (pamh, PAM_ESTABLISH_CRED);
401
if (pamerr != PAM_SUCCESS) {
402
if (gdm_slave_should_complain ())
403
gdm_error (_("Couldn't set credentials for %s"), login);
407
credentials_set = TRUE;
409
/* Register the session */
410
pamerr = pam_open_session (pamh, 0);
411
if (pamerr != PAM_SUCCESS) {
412
if (gdm_slave_should_complain ())
413
gdm_error (_("Couldn't open session for %s"), login);
417
/* Workaround to avoid gdm messages being logged as PAM_pwdb */
419
openlog ("gdm", LOG_PID, LOG_DAEMON);
427
/* The verbose authentication is turned on, output the error
428
* message from the PAM subsystem */
429
if ( ! error_msg_given &&
430
gdm_slave_should_complain ()) {
431
/* I'm not sure yet if I should display this message for any other issues - heeten */
432
if (pamerr == PAM_AUTH_ERR ||
433
pamerr == PAM_USER_UNKNOWN) {
434
/* FIXME: Hmm, how are we sure that the login is username
435
* and password. That is the most common case but not
436
* neccessairly true, this message needs to be changed
437
* to allow for such cases */
438
auth_errmsg = g_strdup_printf
439
(_("\nIncorrect username or password. "
440
"Letters must be typed in the correct case. "
441
"Please be sure the Caps Lock key is not enabled"));
442
gdm_slave_greeter_ctl_no_ret (GDM_ERRBOX, auth_errmsg);
443
g_free (auth_errmsg);
445
gdm_slave_greeter_ctl_no_ret (GDM_ERRDLG, _("Authentication failed"));
450
/* Throw away the credentials */
452
pam_setcred (pamh, PAM_DELETE_CRED);
453
pam_end (pamh, pamerr);
457
/* Workaround to avoid gdm messages being logged as PAM_pwdb */
459
openlog ("gdm", LOG_PID, LOG_DAEMON);
469
* gdm_verify_setup_user:
470
* @login: The name of the user
471
* @display: The name of the display
473
* This is used for auto loging in. This just sets up the login
474
* session for this user
478
gdm_verify_setup_user (GdmDisplay *d, const gchar *login, const gchar *display)
481
struct passwd *pwent;
488
/* Initialize a PAM session for the user */
489
if ( ! create_pamh (d, "gdm-autologin", login, &standalone_pamc,
494
/* Start authentication session */
495
if ((pamerr = pam_authenticate (pamh, 0)) != PAM_SUCCESS) {
496
if (gdm_slave_should_complain ()) {
497
gdm_error (_("Couldn't authenticate user"));
498
gdm_error_box (cur_gdm_disp,
499
GNOME_MESSAGE_BOX_ERROR,
500
_("Authentication failed"));
505
/* Check if the user's account is healthy. */
506
pamerr = pam_acct_mgmt (pamh, 0);
510
case PAM_NEW_AUTHTOK_REQD :
511
/* XXX: this is for automatic and timed logins,
512
* we shouldn't be asking for new pw since we never
513
* authenticated the user. I suppose just ignoring
514
* this would be OK */
516
if ((pamerr = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK)) != PAM_SUCCESS) {
517
gdm_error (_("Authentication token change failed for user %s"), login);
518
gdm_error_box (cur_gdm_disp,
519
GNOME_MESSAGE_BOX_ERROR,
520
_("\nThe change of the authentication token failed. "
521
"Please try again later or cantact the system administrator."));
526
case PAM_ACCT_EXPIRED :
527
gdm_error (_("User %s no longer permitted to access the system"), login);
528
gdm_error_box (cur_gdm_disp,
529
GNOME_MESSAGE_BOX_ERROR,
530
_("\nThe system administrator has disabled your account."));
532
case PAM_PERM_DENIED :
533
gdm_error (_("User %s not permitted to gain access at this time"), login);
534
gdm_error_box (cur_gdm_disp,
535
GNOME_MESSAGE_BOX_ERROR,
536
_("\nThe system administrator has disabled your access to the system temporary."));
539
if (gdm_slave_should_complain ())
540
gdm_error (_("Couldn't set acct. mgmt for %s"), login);
544
pwent = getpwnam (login);
545
if (/* paranoia */ pwent == NULL ||
546
! gdm_setup_gids (login, pwent->pw_gid)) {
547
gdm_error (_("Cannot set user group for %s"), login);
548
gdm_error_box (cur_gdm_disp,
549
GNOME_MESSAGE_BOX_ERROR,
550
_("\nCannot set your user group, "
551
"you will not be able to log in, "
552
"please contact your system administrator."));
556
/* Register the session */
557
pamerr = pam_open_session (pamh, 0);
558
if (pamerr != PAM_SUCCESS) {
559
if (gdm_slave_should_complain ())
560
gdm_error (_("Couldn't open session for %s"), login);
564
/* Set credentials */
565
pamerr = pam_setcred (pamh, PAM_ESTABLISH_CRED);
566
if (pamerr != PAM_SUCCESS) {
567
if (gdm_slave_should_complain ())
568
gdm_error (_("Couldn't set credentials for %s"), login);
572
/* Workaround to avoid gdm messages being logged as PAM_pwdb */
574
openlog ("gdm", LOG_PID, LOG_DAEMON);
583
pam_end (pamh, pamerr);
586
/* Workaround to avoid gdm messages being logged as PAM_pwdb */
588
openlog ("gdm", LOG_PID, LOG_DAEMON);
597
* gdm_verify_cleanup:
599
* Unregister the user's session
603
gdm_verify_cleanup (GdmDisplay *d)
605
gid_t groups[1] = { 0 };
611
/* Close the users session */
612
pamerr = pam_close_session (pamh, 0);
614
/* Throw away the credentials */
615
pamerr = pam_setcred (pamh, PAM_DELETE_CRED);
618
pam_end (pamh, pamerr);
621
/* Workaround to avoid gdm messages being logged as PAM_pwdb */
623
openlog ("gdm", LOG_PID, LOG_DAEMON);
626
/* Clear the group setup */
628
/* this will get rid of any suplementary groups etc... */
629
setgroups (1, groups);
638
* Check that the authentication system is correctly configured.
639
* Not very smart, perhaps we should just whack this.
641
* Aborts daemon on error
645
gdm_verify_check (void)
647
/* FIXME: this is somewhat evil */
648
if (access (PAM_PREFIX "/pam.d/gdm", F_OK) != 0 &&
649
access ("/etc/pam.d/gdm", F_OK) != 0 &&
650
access (PAM_PREFIX "/pam.conf", F_OK) != 0 &&
651
access ("/etc/pam.conf", F_OK) != 0) {
653
s = g_strdup_printf (_("Can't find PAM configuration file for gdm. "
654
"I've tried %s, %s, %s and %s"),
655
PAM_PREFIX "/pam.d/gdm",
657
PAM_PREFIX "/pam.conf",
659
gdm_text_message_dialog (s);
660
gdm_fail ("gdm_verify_check: %s", s);
661
g_free (s); /* I'm an anal wanker */
667
gdm_verify_setup_env (GdmDisplay *d)
674
/* Migrate any PAM env. variables to the user's environment */
675
/* This leaks, oh well */
676
if ((pamenv = pam_getenvlist (pamh))) {
679
for (i = 0 ; pamenv[i] ; i++) {
680
putenv (g_strdup (pamenv[i]));