1 /* passwd.c --- verifying typed passwords with the OS.
2 * xscreensaver, Copyright (c) 1993-2004 Jamie Zawinski <jwz@jwz.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
17 #ifndef NO_LOCKING /* whole file */
27 # include <pwd.h> /* for getpwuid() */
34 #endif /* HAVE_SYSLOG */
36 #include <X11/Intrinsic.h>
38 #include "xscreensaver.h"
41 extern const char *blurb(void);
42 extern void check_for_leaks (const char *where);
54 #define countof(x) (sizeof((x))/sizeof(*(x)))
58 Bool (*init) (int argc, char **argv, Bool verbose_p);
59 Bool (*priv_init) (int argc, char **argv, Bool verbose_p);
60 Bool (*valid_p) (const char *typed_passwd, Bool verbose_p);
61 void (*try_unlock) (saver_info *si, Bool verbose_p,
62 Bool (*valid_p)(const char *typed_passwd, Bool verbose_p));
69 extern Bool kerberos_lock_init (int argc, char **argv, Bool verbose_p);
70 extern Bool kerberos_passwd_valid_p (const char *typed_passwd, Bool verbose_p);
73 extern Bool pam_priv_init (int argc, char **argv, Bool verbose_p);
74 extern void pam_try_unlock (saver_info *si, Bool verbose_p,
75 Bool (*valid_p)(const char *typed_passwd, Bool verbose_p));
77 #ifdef PASSWD_HELPER_PROGRAM
78 extern Bool ext_priv_init (int argc, char **argv, Bool verbose_p);
79 extern Bool ext_passwd_valid_p (const char *typed_passwd, Bool verbose_p);
81 extern Bool pwent_lock_init (int argc, char **argv, Bool verbose_p);
82 extern Bool pwent_priv_init (int argc, char **argv, Bool verbose_p);
83 extern Bool pwent_passwd_valid_p (const char *typed_passwd, Bool verbose_p);
85 Bool lock_priv_init (int argc, char **argv, Bool verbose_p);
86 Bool lock_init (int argc, char **argv, Bool verbose_p);
87 Bool passwd_valid_p (const char *typed_passwd, Bool verbose_p);
89 /* The authorization methods to try, in order.
90 Note that the last one (the pwent version) is actually two auth methods,
91 since that code tries shadow passwords, and then non-shadow passwords.
92 (It's all in the same file since the APIs are randomly nearly-identical.)
94 struct auth_methods methods[] = {
96 { "PAM", 0, pam_priv_init, 0, pam_try_unlock,
100 { "Kerberos", kerberos_lock_init, 0, kerberos_passwd_valid_p, 0,
103 # ifdef PASSWD_HELPER_PROGRAM
104 { "external", 0, ext_priv_init, ext_passwd_valid_p, 0,
107 { "normal", pwent_lock_init, pwent_priv_init, pwent_passwd_valid_p, 0,
113 lock_priv_init (int argc, char **argv, Bool verbose_p)
117 for (i = 0; i < countof(methods); i++)
119 if (!methods[i].priv_init)
120 methods[i].priv_initted_p = True;
122 methods[i].priv_initted_p = methods[i].priv_init (argc, argv,
125 if (methods[i].priv_initted_p)
128 fprintf (stderr, "%s: initialization of %s passwords failed.\n",
129 blurb(), methods[i].name);
136 lock_init (int argc, char **argv, Bool verbose_p)
140 for (i = 0; i < countof(methods); i++)
142 if (!methods[i].priv_initted_p) /* Bail if lock_priv_init failed. */
145 if (!methods[i].init)
146 methods[i].initted_p = True;
148 methods[i].initted_p = methods[i].init (argc, argv, verbose_p);
150 if (methods[i].initted_p)
153 fprintf (stderr, "%s: initialization of %s passwords failed.\n",
154 blurb(), methods[i].name);
160 /* A basic auth driver that simply prompts for a password then runs it through
161 * valid_p to determine whether the password is correct.
164 try_unlock_password(saver_info *si,
166 Bool (*valid_p)(const char *typed_passwd, Bool verbose_p))
168 struct auth_message message;
169 struct auth_response *response = NULL;
171 memset(&message, 0, sizeof(message));
174 fprintf(stderr, "%s: non-PAM password auth.\n", blurb());
176 /* Call the auth_conv function with "Password:", then feed
177 * the result into valid_p()
179 message.type = AUTH_MSGTYPE_PROMPT_NOECHO;
180 message.msg = "Password:";
182 si->unlock_cb(1, &message, &response, si);
187 if (valid_p (response->response, verbose_p))
188 si->unlock_state = ul_success; /* yay */
189 else if (si->unlock_state == ul_cancel ||
190 si->unlock_state == ul_time)
191 ; /* more specific failures ok */
193 si->unlock_state = ul_fail; /* generic failure */
195 if (response->response)
196 free(response->response);
201 /* Write a password failure to the system log.
204 do_syslog (saver_info *si, Bool verbose_p)
207 struct passwd *pw = getpwuid (getuid ());
208 char *d = DisplayString (si->dpy);
209 char *u = (pw && pw->pw_name ? pw->pw_name : "???");
217 # if defined(LOG_AUTHPRIV)
219 # elif defined(LOG_AUTH)
228 # define FMT "FAILED LOGIN %d ON DISPLAY \"%s\", FOR \"%s\""
231 fprintf (stderr, "%s: syslog: " FMT "\n", blurb(),
232 si->unlock_failures, d, u);
234 openlog (progname, opt, fac);
235 syslog (LOG_NOTICE, FMT, si->unlock_failures, d, u);
238 # endif /* HAVE_SYSLOG */
244 * Runs through each authentication driver calling its try_unlock function.
245 * Called xss_authenticate() because AIX beat us to the name authenticate().
248 xss_authenticate(saver_info *si, Bool verbose_p)
252 for (i = 0; i < countof(methods); i++)
254 if (!methods[i].initted_p)
257 if (si->cached_passwd != NULL && methods[i].valid_p)
258 si->unlock_state = (methods[i].valid_p(si->cached_passwd, verbose_p) == True)
259 ? ul_success : ul_fail;
260 else if (methods[i].try_unlock != NULL)
261 methods[i].try_unlock(si, verbose_p, methods[i].valid_p);
262 else if (methods[i].valid_p)
263 try_unlock_password(si, verbose_p, methods[i].valid_p);
264 else /* Ze goggles, zey do nozing! */
265 fprintf(stderr, "%s: authentication method %s does nothing.\n",
266 blurb(), methods[i].name);
268 check_for_leaks (methods[i].name);
270 if (si->unlock_state == ul_success)
272 /* If we successfully authenticated by method N, but attempting
273 to authenticate by method N-1 failed, mention that (since if
274 an earlier authentication method fails and a later one succeeds,
275 something screwy is probably going on.)
277 if (verbose_p && i > 0)
279 for (j = 0; j < i; j++)
280 if (methods[j].initted_p)
282 "%s: authentication via %s failed.\n",
283 blurb(), methods[j].name);
285 "%s: authentication via %s succeeded.\n",
286 blurb(), methods[i].name);
288 goto DONE; /* Successfully authenticated! */
293 fprintf(stderr, "%s: All authentication mechanisms failed.\n", blurb());
295 if (si->unlock_state == ul_fail)
297 si->unlock_failures++;
298 do_syslog (si, verbose_p);
302 if (si->auth_finished_cb)
303 si->auth_finished_cb (si);
306 #endif /* NO_LOCKING -- whole file */