summaryrefslogtreecommitdiffstats
path: root/driver/passwd.c
diff options
context:
space:
mode:
authorSimon Rettberg2021-04-06 14:43:39 +0200
committerSimon Rettberg2021-04-07 13:38:37 +0200
commit38886de0c3e9ea5729ef23e4c653fa2822f52e8f (patch)
tree9b799c8c968a92cc77746a95e0e8bdd90b6b13c3 /driver/passwd.c
parentMaybe not remove, but ... (diff)
downloadxscreensaver-openslx.tar.gz
xscreensaver-openslx.tar.xz
xscreensaver-openslx.zip
xscreensaver 6.00v28r1openslx
Diffstat (limited to 'driver/passwd.c')
-rw-r--r--driver/passwd.c319
1 files changed, 103 insertions, 216 deletions
diff --git a/driver/passwd.c b/driver/passwd.c
index 68e1a0b..11ca134 100644
--- a/driver/passwd.c
+++ b/driver/passwd.c
@@ -1,5 +1,5 @@
/* passwd.c --- verifying typed passwords with the OS.
- * xscreensaver, Copyright (c) 1993-2019 Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright © 1993-2021 Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@@ -14,8 +14,6 @@
# include "config.h"
#endif
-#ifndef NO_LOCKING /* whole file */
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -26,11 +24,7 @@
#include <sys/time.h>
#include <sys/stat.h>
-#ifndef VMS
-# include <pwd.h> /* for getpwuid() */
-#else /* VMS */
-# include "vms-pwd.h"
-#endif /* VMS */
+#include <pwd.h> /* for getpwuid() */
#ifdef HAVE_SYSLOG
# include <syslog.h>
@@ -41,8 +35,24 @@
#include "xscreensaver.h"
#include "auth.h"
+
+#ifdef NO_LOCKING
+
+Bool lock_init (void) { return 0; }
+Bool lock_priv_init (void) { return 0; }
+Bool xscreensaver_auth (void *closure,
+ Bool (*conv_fn) (void *closure,
+ int nmsgs,
+ const auth_message *msg,
+ auth_response **resp),
+ void (*finished_fn) (void *closure, Bool status))
+{
+ return False;
+}
+
+#else /* NO_LOCKING -- whole file */
+
extern const char *blurb(void);
-extern void check_for_leaks (const char *where);
/* blargh */
@@ -58,100 +68,39 @@ extern void check_for_leaks (const char *where);
struct auth_methods {
const char *name;
- Bool (*init) (int argc, char **argv, Bool verbose_p);
- Bool (*priv_init) (int argc, char **argv, Bool verbose_p);
- Bool (*valid_p) (const char *typed_passwd, Bool verbose_p);
- void (*try_unlock) (saver_info *si, Bool verbose_p,
- Bool (*valid_p)(const char *typed_passwd, Bool verbose_p));
+ Bool (*init) (void);
+ Bool (*priv_init) (void);
+ Bool (*valid_p) (void *closure, const char *plaintext);
+ Bool (*try_unlock) (void *closure,
+ Bool (*conv_fn) (void *closure,
+ int nmsgs,
+ const auth_message *msg,
+ auth_response **resp));
Bool initted_p;
Bool priv_initted_p;
};
-#ifdef HAVE_KERBEROS
-extern Bool kerberos_lock_init (int argc, char **argv, Bool verbose_p);
-extern Bool kerberos_passwd_valid_p (const char *typed_passwd, Bool verbose_p);
-#endif
-#ifdef HAVE_PAM
-extern Bool pam_priv_init (int argc, char **argv, Bool verbose_p);
-extern void pam_try_unlock (saver_info *si, Bool verbose_p,
- Bool (*valid_p)(const char *typed_passwd, Bool verbose_p));
-#endif
-#ifdef PASSWD_HELPER_PROGRAM
-extern Bool ext_priv_init (int argc, char **argv, Bool verbose_p);
-extern Bool ext_passwd_valid_p (const char *typed_passwd, Bool verbose_p);
-#endif
-extern Bool pwent_lock_init (int argc, char **argv, Bool verbose_p);
-extern Bool pwent_priv_init (int argc, char **argv, Bool verbose_p);
-extern Bool pwent_passwd_valid_p (const char *typed_passwd, Bool verbose_p);
-
-Bool lock_priv_init (int argc, char **argv, Bool verbose_p);
-Bool lock_init (int argc, char **argv, Bool verbose_p);
-Bool passwd_valid_p (const char *typed_passwd, Bool verbose_p);
-
-/* The authorization methods to try, in order.
- Note that the last one (the pwent version) is actually two auth methods,
- since that code tries shadow passwords, and then non-shadow passwords.
- (It's all in the same file since the APIs are randomly nearly-identical.)
+
+/* The authorization methods to try, in order of preference.
+ The first that initializes successfully is used and others are ignored.
*/
struct auth_methods methods[] = {
# ifdef HAVE_PAM
- { "PAM", 0, pam_priv_init, 0, pam_try_unlock,
- False, False },
+ { "PAM", 0, pam_priv_init, 0, pam_try_unlock, 0, },
# endif
# ifdef HAVE_KERBEROS
- { "Kerberos", kerberos_lock_init, 0, kerberos_passwd_valid_p, 0,
- False, False },
+ { "KRB", kerberos_lock_init, 0, kerberos_passwd_valid_p, 0, },
# endif
# ifdef PASSWD_HELPER_PROGRAM
- { "external", 0, ext_priv_init, ext_passwd_valid_p, 0,
- False, False },
+ { "EXT", 0, ext_priv_init, ext_passwd_valid_p, 0, },
# endif
- { "normal", pwent_lock_init, pwent_priv_init, pwent_passwd_valid_p, 0,
- False, False }
+ { "pwnam", pwent_lock_init, pwent_priv_init, pwent_passwd_valid_p, 0, }
};
-# ifdef HAVE_PROC_OOM
-/* On some recent Linux systems you can tell the kernel's OOM-killer to
- consider the possibility of maybe sometimes not killing you in low-memory
- situations. Because that would unlock the screen. And that would be bad.
-
- Linux >= 2.6.11: echo -17 > /proc/$$/oom_adj <-- ignoring this.
- Linux >= 2.6.37: echo -1000 > /proc/$$/oom_score_adj <-- trying this.
- */
-static void
-oom_assassin_immunity (Bool verbose_p)
-{
- char fn[1024];
- struct stat st;
- FILE *out;
- sprintf (fn, "/proc/%d/oom_score_adj", getpid());
- if (stat(fn, &st) != 0)
- {
- if (verbose_p)
- fprintf (stderr, "%s: OOM: %s does not exist\n", blurb(), fn);
- return;
- }
- out = fopen (fn, "w");
- if (!out)
- {
- if (verbose_p)
- {
- char b[2048];
- sprintf (b, "%s: OOM: unable to write %s\n", blurb(), fn);
- perror(b);
- }
- return;
- }
- fputs ("-1000\n", out);
- fclose (out);
-}
-# endif /* HAVE_PROC_OOM */
-
-
Bool
-lock_priv_init (int argc, char **argv, Bool verbose_p)
+lock_priv_init (void)
{
int i;
Bool any_ok = False;
@@ -160,26 +109,17 @@ lock_priv_init (int argc, char **argv, Bool verbose_p)
if (!methods[i].priv_init)
methods[i].priv_initted_p = True;
else
- methods[i].priv_initted_p = methods[i].priv_init (argc, argv,
- verbose_p);
+ methods[i].priv_initted_p = methods[i].priv_init();
if (methods[i].priv_initted_p)
any_ok = True;
- else if (verbose_p)
- fprintf (stderr, "%s: initialization of %s passwords failed.\n",
- blurb(), methods[i].name);
}
-
-# ifdef HAVE_PROC_OOM
- oom_assassin_immunity (verbose_p);
-# endif
-
return any_ok;
}
Bool
-lock_init (int argc, char **argv, Bool verbose_p)
+lock_init (void)
{
int i;
Bool any_ok = False;
@@ -191,70 +131,75 @@ lock_init (int argc, char **argv, Bool verbose_p)
if (!methods[i].init)
methods[i].initted_p = True;
else
- methods[i].initted_p = methods[i].init (argc, argv, verbose_p);
+ methods[i].initted_p = methods[i].init();
if (methods[i].initted_p)
any_ok = True;
else if (verbose_p)
- fprintf (stderr, "%s: initialization of %s passwords failed.\n",
+ fprintf (stderr, "%s: %s: passwords initialization failed\n",
blurb(), methods[i].name);
}
return any_ok;
}
-/* A basic auth driver that simply prompts for a password then runs it through
- * valid_p to determine whether the password is correct.
+/* For those auth methods that have a 'valid_p' function instead of a
+ 'try_unlock' function, this does a PAM-like conversation that first
+ prompts for a password and then tests it with the 'valid_p' function.
*/
-static void
-try_unlock_password(saver_info *si,
- Bool verbose_p,
- Bool (*valid_p)(const char *typed_passwd, Bool verbose_p))
+static Bool
+try_valid_p (void *closure,
+ const char *name,
+ Bool (*valid_p) (void *closure, const char *typed_passwd),
+ Bool (*conv_fn) (void *closure,
+ int nmsgs,
+ const auth_message *msg,
+ auth_response **resp))
{
- struct auth_message message;
- struct auth_response *response = NULL;
+ auth_message message;
+ auth_response *response = NULL;
+ Bool ok = False;
- memset(&message, 0, sizeof(message));
+ memset (&message, 0, sizeof(message));
if (verbose_p)
- fprintf(stderr, "%s: non-PAM password auth.\n", blurb());
+ fprintf (stderr, "%s: %s: non-PAM password auth\n", blurb(), name);
- /* Call the auth_conv function with "Password:", then feed
- * the result into valid_p()
- */
+ /* Call the auth_conv function with "Password:", then feed the result
+ into valid_p() */
message.type = AUTH_MSGTYPE_PROMPT_NOECHO;
message.msg = "Password:";
- si->unlock_cb(1, &message, &response, si);
+ ok = conv_fn (closure, 1, &message, &response);
+ if (!response || !response->response)
+ ok = False;
- if (!response)
- return;
+ if (ok)
+ ok = valid_p (closure, response->response);
- if (valid_p (response->response, verbose_p))
- si->unlock_state = ul_success; /* yay */
- else if (si->unlock_state == ul_cancel ||
- si->unlock_state == ul_time)
- ; /* more specific failures ok */
- else
- si->unlock_state = ul_fail; /* generic failure */
+ if (response)
+ {
+ if (response->response)
+ free (response->response);
+ free (response);
+ }
- if (response->response)
- free(response->response);
- free(response);
+ return ok;
}
/* Write a password failure to the system log.
*/
static void
-do_syslog (saver_info *si, Bool verbose_p)
+do_syslog (void)
{
# ifdef HAVE_SYSLOG
struct passwd *pw = getpwuid (getuid ());
- char *d = (si->dpy ? DisplayString (si->dpy) : 0);
+ char *d = getenv ("DISPLAY");
char *u = (pw && pw->pw_name ? pw->pw_name : "???");
int opt = 0;
int fac = 0;
+ int pri = LOG_NOTICE;
# ifdef LOG_PID
opt = LOG_PID;
@@ -270,115 +215,57 @@ do_syslog (saver_info *si, Bool verbose_p)
if (!d) d = "";
-# undef FMT
-# define FMT "FAILED LOGIN %d ON DISPLAY \"%s\", FOR \"%s\""
-
- if (verbose_p)
- fprintf (stderr, "%s: syslog: " FMT "\n", blurb(),
- si->unlock_failures, d, u);
-
openlog (progname, opt, fac);
- syslog (LOG_NOTICE, FMT, si->unlock_failures, d, u);
+ syslog (pri, "Failed login on display \"%s\" for \"%s\"", d, u);
closelog ();
# endif /* HAVE_SYSLOG */
}
-
-/**
- * Runs through each authentication driver calling its try_unlock function.
- * Called xss_authenticate() because AIX beat us to the name authenticate().
+/* Runs through each authentication driver calling its try_unlock function.
*/
-void
-xss_authenticate(saver_info *si, Bool verbose_p)
+Bool
+xscreensaver_auth (void *closure,
+ Bool (*conv_fn) (void *closure,
+ int nmsgs,
+ const auth_message *msg,
+ auth_response **resp),
+ void (*finished_fn) (void *closure, Bool status))
{
- int i, j;
-
- si->unlock_state = ul_read;
+ int i;
+ Bool ok = False;
for (i = 0; i < countof(methods); i++)
{
if (!methods[i].initted_p)
continue;
- if (si->cached_passwd != NULL && methods[i].valid_p)
- si->unlock_state = (methods[i].valid_p(si->cached_passwd, verbose_p) == True)
- ? ul_success : ul_fail;
- else if (methods[i].try_unlock != NULL)
- methods[i].try_unlock(si, verbose_p, methods[i].valid_p);
+ if (methods[i].try_unlock)
+ ok = methods[i].try_unlock (closure, conv_fn);
else if (methods[i].valid_p)
- try_unlock_password(si, verbose_p, methods[i].valid_p);
- else /* Ze goggles, zey do nozing! */
- fprintf(stderr, "%s: authentication method %s does nothing.\n",
- blurb(), methods[i].name);
-
- check_for_leaks (methods[i].name);
-
- /* If password authentication failed, but the password was NULL
- (meaning the user just hit RET) then treat that as "cancel".
- This means that if the password is literally NULL, it will
- work; but if not, then NULL passwords are treated as cancel.
- */
- if (si->unlock_state == ul_fail &&
- si->cached_passwd &&
- !*si->cached_passwd)
- {
- if (verbose_p)
- fprintf (stderr, "%s: assuming null password means cancel.\n",
- blurb());
- si->unlock_state = ul_cancel;
- }
-
- if (si->unlock_state == ul_success)
- {
- /* If we successfully authenticated by method N, but attempting
- to authenticate by method N-1 failed, mention that (since if
- an earlier authentication method fails and a later one succeeds,
- something screwy is probably going on.)
- */
- if (verbose_p && i > 0)
- {
- for (j = 0; j < i; j++)
- if (methods[j].initted_p)
- fprintf (stderr,
- "%s: authentication via %s failed.\n",
- blurb(), methods[j].name);
- fprintf (stderr,
- "%s: authentication via %s succeeded.\n",
- blurb(), methods[i].name);
- }
- goto DONE; /* Successfully authenticated! */
- }
- else if (si->unlock_state == ul_cancel ||
- si->unlock_state == ul_time)
- {
- /* If any auth method gets a cancel or timeout, don't try the
- next auth method! We're done! */
- if (verbose_p)
- fprintf (stderr, "%s: authentication via %s %s.\n",
- blurb(), methods[i].name,
- (si->unlock_state == ul_cancel
- ? "cancelled" : "timed out"));
- goto DONE;
- }
+ ok = try_valid_p (closure, methods[i].name, methods[i].valid_p,
+ conv_fn);
+ else
+ abort(); /* method must have one or the other function */
+
+ /* Only try the first method that initialized properly. That means that
+ if PAM initialized correctly, we will never try pwent or Kerberos.
+ If we did, then typing an incorrect password at PAM would result in a
+ second password prompt that would only go to pwent. There's no
+ sensible way to re-use the password typed the first time, if there
+ even was one. With fingerprint readers or OTP fobs, there might have
+ been 0, 2, or more passwords entered. */
+ break;
}
- if (verbose_p)
- fprintf(stderr, "%s: All authentication mechanisms failed.\n", blurb());
+ if (!ok)
+ do_syslog ();
- if (si->unlock_state == ul_fail)
- {
- /* Note the time of the first failure */
- if (si->unlock_failures == 0)
- si->unlock_failure_time = time((time_t *) 0);
- si->unlock_failures++;
- do_syslog (si, verbose_p);
- }
+ if (finished_fn)
+ finished_fn (closure, ok);
-DONE:
- if (si->auth_finished_cb)
- si->auth_finished_cb (si);
+ return ok;
}
#endif /* NO_LOCKING -- whole file */