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 */
26 #include <X11/Intrinsic.h>
30 extern const char *blurb(void);
31 extern void check_for_leaks (const char *where);
43 #define countof(x) (sizeof((x))/sizeof(*(x)))
47 Bool (*init) (int argc, char **argv, Bool verbose_p);
48 Bool (*priv_init) (int argc, char **argv, Bool verbose_p);
49 Bool (*valid_p) (const char *typed_passwd, Bool verbose_p);
50 void (*try_unlock) (saver_info *si, Bool verbose_p,
51 Bool (*valid_p)(const char *typed_passwd, Bool verbose_p));
58 extern Bool kerberos_lock_init (int argc, char **argv, Bool verbose_p);
59 extern Bool kerberos_passwd_valid_p (const char *typed_passwd, Bool verbose_p);
62 extern Bool pam_priv_init (int argc, char **argv, Bool verbose_p);
63 extern void pam_try_unlock (saver_info *si, Bool verbose_p,
64 Bool (*valid_p)(const char *typed_passwd, Bool verbose_p));
66 #ifdef PASSWD_HELPER_PROGRAM
67 extern Bool ext_priv_init (int argc, char **argv, Bool verbose_p);
68 extern Bool ext_passwd_valid_p (const char *typed_passwd, Bool verbose_p);
70 extern Bool pwent_lock_init (int argc, char **argv, Bool verbose_p);
71 extern Bool pwent_priv_init (int argc, char **argv, Bool verbose_p);
72 extern Bool pwent_passwd_valid_p (const char *typed_passwd, Bool verbose_p);
74 Bool lock_priv_init (int argc, char **argv, Bool verbose_p);
75 Bool lock_init (int argc, char **argv, Bool verbose_p);
76 Bool passwd_valid_p (const char *typed_passwd, Bool verbose_p);
78 /* The authorization methods to try, in order.
79 Note that the last one (the pwent version) is actually two auth methods,
80 since that code tries shadow passwords, and then non-shadow passwords.
81 (It's all in the same file since the APIs are randomly nearly-identical.)
83 struct auth_methods methods[] = {
85 { "PAM", 0, pam_priv_init, 0, pam_try_unlock,
89 { "Kerberos", kerberos_lock_init, 0, kerberos_passwd_valid_p, 0,
92 # ifdef PASSWD_HELPER_PROGRAM
93 { "external", 0, ext_priv_init, ext_passwd_valid_p, 0,
96 { "normal", pwent_lock_init, pwent_priv_init, pwent_passwd_valid_p, 0,
102 lock_priv_init (int argc, char **argv, Bool verbose_p)
106 for (i = 0; i < countof(methods); i++)
108 if (!methods[i].priv_init)
109 methods[i].priv_initted_p = True;
111 methods[i].priv_initted_p = methods[i].priv_init (argc, argv,
114 if (methods[i].priv_initted_p)
117 fprintf (stderr, "%s: initialization of %s passwords failed.\n",
118 blurb(), methods[i].name);
125 lock_init (int argc, char **argv, Bool verbose_p)
129 for (i = 0; i < countof(methods); i++)
131 if (!methods[i].priv_initted_p) /* Bail if lock_priv_init failed. */
134 if (!methods[i].init)
135 methods[i].initted_p = True;
137 methods[i].initted_p = methods[i].init (argc, argv, verbose_p);
139 if (methods[i].initted_p)
142 fprintf (stderr, "%s: initialization of %s passwords failed.\n",
143 blurb(), methods[i].name);
149 /* A basic auth driver that simply prompts for a password then runs it through
150 * valid_p to determine whether the password is correct.
153 try_unlock_password(saver_info *si,
155 Bool (*valid_p)(const char *typed_passwd, Bool verbose_p))
157 struct auth_message message;
158 struct auth_response *response = NULL;
160 memset(&message, 0, sizeof(message));
162 /* Call the auth_conv function with "Password:", then feed
163 * the result into valid_p()
165 message.type = AUTH_MSGTYPE_PROMPT_NOECHO;
166 message.msg = "Password:";
168 si->unlock_cb(1, &message, &response, si);
173 si->unlock_state = valid_p(response->response, verbose_p) ? ul_success : ul_fail;
175 if (response->response)
176 free(response->response);
182 * Runs through each authentication driver calling its try_unlock function.
183 * Called xss_authenticate() because AIX beat us to the name authenticate().
186 xss_authenticate(saver_info *si, Bool verbose_p)
190 for (i = 0; i < countof(methods); i++)
192 if (!methods[i].initted_p)
195 if (si->cached_passwd != NULL && methods[i].valid_p)
196 si->unlock_state = (methods[i].valid_p(si->cached_passwd, verbose_p) == True)
197 ? ul_success : ul_fail;
198 else if (methods[i].try_unlock != NULL)
199 methods[i].try_unlock(si, verbose_p, methods[i].valid_p);
200 else if (methods[i].valid_p)
201 try_unlock_password(si, verbose_p, methods[i].valid_p);
202 else /* Ze goggles, zey do nozing! */
203 fprintf(stderr, "%s: authentication method %s does nothing.\n",
204 blurb(), methods[i].name);
206 check_for_leaks (methods[i].name);
208 if (si->unlock_state == ul_success)
210 /* If we successfully authenticated by method N, but attempting
211 to authenticate by method N-1 failed, mention that (since if
212 an earlier authentication method fails and a later one succeeds,
213 something screwy is probably going on.)
215 if (verbose_p && i > 0)
217 for (j = 0; j < i; j++)
218 if (methods[j].initted_p)
220 "%s: authentication via %s failed.\n",
221 blurb(), methods[j].name);
223 "%s: authentication via %s succeeded.\n",
224 blurb(), methods[i].name);
226 goto DONE; /* Successfully authenticated! */
231 fprintf(stderr, "%s: All authentication mechanisms failed.\n", blurb());
234 if (si->auth_finished_cb)
235 si->auth_finished_cb (si);
238 #endif /* NO_LOCKING -- whole file */