X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=driver%2Fpasswd.c;h=066bc81f9c608d6a0178c5be12605b30556efaaf;hp=d331b3bb26d17e52f31ce0b4dbfd7025604374fd;hb=6b1c86cf395f59389e4ece4ea8f4bea2c332745b;hpb=ce3185de9d9705e259f2b60dd4b5509007fa17d4 diff --git a/driver/passwd.c b/driver/passwd.c index d331b3bb..066bc81f 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-1998 Jamie Zawinski + * xscreensaver, Copyright (c) 1993-2004 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -16,67 +16,30 @@ #ifndef NO_LOCKING /* whole file */ +#include #include +#include #ifdef HAVE_UNISTD_H # include #endif -#include -#include -#include #ifndef VMS -# include -# include +# include /* for getpwuid() */ #else /* VMS */ # include "vms-pwd.h" #endif /* VMS */ +#ifdef HAVE_SYSLOG +# include +#endif /* HAVE_SYSLOG */ -#ifdef __bsdi__ -# include -# if _BSDI_VERSION >= 199608 -# define BSD_AUTH -# endif -#endif /* __bsdi__ */ - - -#if defined(HAVE_SHADOW_PASSWD) /* passwds live in /etc/shadow */ - -# include -# define PWTYPE struct spwd * -# define PWPSLOT sp_pwdp -# define GETPW getspnam - -#elif defined(HAVE_ENHANCED_PASSWD) /* passwds live in /tcb/files/auth/ */ - /* M.Matsumoto */ -# include -# include +#include -# define PWTYPE struct pr_passwd * -# define PWPSLOT ufld.fd_encrypt -# define GETPW getprpwnam +#include "xscreensaver.h" +#include "auth.h" -#elif defined(HAVE_ADJUNCT_PASSWD) - -# include -# include -# include - -# define PWTYPE struct passwd_adjunct * -# define PWPSLOT pwa_passwd -# define GETPW getpwanam - -#elif defined(HAVE_HPUX_PASSWD) - -# include -# include - -# define PWTYPE struct s_passwd * -# define PWPSLOT pw_passwd -# define GETPW getspwnam -# define crypt bigcrypt - -#endif +extern const char *blurb(void); +extern void check_for_leaks (const char *where); /* blargh */ @@ -87,154 +50,257 @@ #define True 1 #define False 0 +#undef countof +#define countof(x) (sizeof((x))/sizeof(*(x))) -extern char *progname; +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 initted_p; + Bool priv_initted_p; +}; -static char *encrypted_root_passwd = 0; -static char *encrypted_user_passwd = 0; -#ifdef VMS -# define ROOT "SYSTEM" -#else -# define ROOT "root" +#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.) + */ +struct auth_methods methods[] = { +# ifdef HAVE_PAM + { "PAM", 0, pam_priv_init, 0, pam_try_unlock, + False, False }, +# endif +# ifdef HAVE_KERBEROS + { "Kerberos", kerberos_lock_init, 0, kerberos_passwd_valid_p, 0, + False, False }, +# endif +# ifdef PASSWD_HELPER_PROGRAM + { "external", 0, ext_priv_init, ext_passwd_valid_p, 0, + False, False }, +# endif + { "normal", pwent_lock_init, pwent_priv_init, pwent_passwd_valid_p, 0, + False, False } +}; - -#ifndef VMS - -static char * -user_name (void) +Bool +lock_priv_init (int argc, char **argv, Bool verbose_p) { - /* I think that just checking $USER here is not the best idea. */ - - const char *u = 0; - - /* It has been reported that getlogin() returns the wrong user id on some - very old SGI systems... And I've seen it return the string "rlogin" - sometimes! Screw it, using getpwuid() should be enough... - */ -/* u = (char *) getlogin (); - */ - - /* getlogin() fails if not attached to a terminal; in that case, use - getpwuid(). (Note that in this case, we're not doing shadow stuff, since - all we're interested in is the name, not the password. So that should - still work. Right?) */ - if (!u || !*u) + int i; + Bool any_ok = False; + for (i = 0; i < countof(methods); i++) { - struct passwd *p = getpwuid (getuid ()); - u = (p ? p->pw_name : 0); + 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); + + 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); } - - return (u ? strdup(u) : 0); + return any_ok; } -#else /* VMS */ -static char * -user_name (void) +Bool +lock_init (int argc, char **argv, Bool verbose_p) { - char *u = getenv("USER"); - return (u ? strdup(u) : 0); + int i; + Bool any_ok = False; + for (i = 0; i < countof(methods); i++) + { + if (!methods[i].priv_initted_p) /* Bail if lock_priv_init failed. */ + continue; + + if (!methods[i].init) + methods[i].initted_p = True; + else + methods[i].initted_p = methods[i].init (argc, argv, verbose_p); + + if (methods[i].initted_p) + any_ok = True; + else if (verbose_p) + fprintf (stderr, "%s: initialization of %s passwords failed.\n", + blurb(), methods[i].name); + } + return any_ok; } -#endif /* VMS */ - -static Bool -passwd_known_p (const char *pw) +/* A basic auth driver that simply prompts for a password then runs it through + * valid_p to determine whether the password is correct. + */ +static void +try_unlock_password(saver_info *si, + Bool verbose_p, + Bool (*valid_p)(const char *typed_passwd, Bool verbose_p)) { - return (pw && - pw[0] != '*' && /* This would be sensible... */ - strlen(pw) > 4); /* ...but this is what Solaris does. */ -} + struct auth_message message; + struct auth_response *response = NULL; + memset(&message, 0, sizeof(message)); -static char * -get_encrypted_passwd(const char *user) -{ - if (user && *user) - { -#ifdef PWTYPE - { /* First check the shadow passwords. */ - PWTYPE p = GETPW((char *) user); - if (p && passwd_known_p (p->PWPSLOT)) - return strdup(p->PWPSLOT); - } -#endif - { /* Check non-shadow passwords too. */ - struct passwd *p = getpwnam(user); - if (p && passwd_known_p (p->pw_passwd)) - return strdup(p->pw_passwd); - } - } + if (verbose_p) + fprintf(stderr, "%s: non-PAM password auth.\n", blurb()); - fprintf (stderr, "%s: couldn't get password of \"%s\"\n", - blurb(), (user ? user : "(null)")); + /* Call the auth_conv function with "Password:", then feed + * the result into valid_p() + */ + message.type = AUTH_MSGTYPE_PROMPT_NOECHO; + message.msg = "Password:"; - return 0; -} + si->unlock_cb(1, &message, &response, si); + if (!response) + return; + 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 */ -/* This has to be called before we've changed our effective user ID, - because it might need priveleges to get at the encrypted passwords. - Returns false if we weren't able to get any passwords, and therefore, - locking isn't possible. (It will also have written to stderr.) - */ + if (response->response) + free(response->response); + free(response); +} -#ifndef VMS -Bool -lock_init (int argc, char **argv) +/* Write a password failure to the system log. + */ +static void +do_syslog (saver_info *si, Bool verbose_p) { - char *u; - -#ifdef HAVE_ENHANCED_PASSWD - set_auth_parameters(argc, argv); - check_auth_parameters(); -#endif /* HAVE_DEC_ENHANCED */ - - u = user_name(); - encrypted_user_passwd = get_encrypted_passwd(u); - encrypted_root_passwd = get_encrypted_passwd(ROOT); - if (u) free (u); - - if (encrypted_user_passwd) - return True; - else - return False; +# ifdef HAVE_SYSLOG + struct passwd *pw = getpwuid (getuid ()); + char *d = DisplayString (si->dpy); + char *u = (pw && pw->pw_name ? pw->pw_name : "???"); + int opt = 0; + int fac = 0; + +# ifdef LOG_PID + opt = LOG_PID; +# endif + +# if defined(LOG_AUTHPRIV) + fac = LOG_AUTHPRIV; +# elif defined(LOG_AUTH) + fac = LOG_AUTH; +# else + fac = LOG_DAEMON; +# endif + + 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); + closelog (); + +# endif /* HAVE_SYSLOG */ } -/* This can be called at any time, and says whether the typed password - belongs to either the logged in user (real uid, not effective); or - to root. + +/** + * Runs through each authentication driver calling its try_unlock function. + * Called xss_authenticate() because AIX beat us to the name authenticate(). */ -Bool -passwd_valid_p (const char *typed_passwd) +void +xss_authenticate(saver_info *si, Bool verbose_p) { - char *s = 0; /* note that on some systems, crypt() may return null */ + int i, j; - if (encrypted_user_passwd && - (s = (char *) crypt (typed_passwd, encrypted_user_passwd)) && - !strcmp (s, encrypted_user_passwd)) - return True; + 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); + 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 (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! */ + } + } - /* do not allow root to have a null password. */ - else if (typed_passwd[0] && - encrypted_root_passwd && - (s = (char *) crypt (typed_passwd, encrypted_root_passwd)) && - !strcmp (s, encrypted_root_passwd)) - return True; + if (verbose_p) + fprintf(stderr, "%s: All authentication mechanisms failed.\n", blurb()); - else - return False; -} + if (si->unlock_state == ul_fail) + { + si->unlock_failures++; + do_syslog (si, verbose_p); + } -#else /* VMS */ -Bool lock_init (int argc, char **argv) { return True; } -#endif /* VMS */ +DONE: + if (si->auth_finished_cb) + si->auth_finished_cb (si); +} #endif /* NO_LOCKING -- whole file */