X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=driver%2Fpasswd-pam.c;h=0d14e262313ea8471661d85632d71f78860c110e;hp=e29ff9c71fa6745f793f79e61cdd43739933edd0;hb=278c59e14c53fd412b734e699bd4f314f766f804;hpb=551b3de3f619c04c2dd1971ee9b3f02e270c28c9 diff --git a/driver/passwd-pam.c b/driver/passwd-pam.c index e29ff9c7..0d14e262 100644 --- a/driver/passwd-pam.c +++ b/driver/passwd-pam.c @@ -10,6 +10,26 @@ * documentation. No representations are made about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. + * + * Some PAM resources: + * + * PAM home page: + * http://www.us.kernel.org/pub/linux/libs/pam/ + * + * PAM FAQ: + * http://www.us.kernel.org/pub/linux/libs/pam/FAQ + * + * PAM Application Developers' Guide: + * http://www.us.kernel.org/pub/linux/libs/pam/Linux-PAM-html/pam_appl.html + * + * PAM Mailing list archives: + * http://www.linuxhq.com/lnxlists/linux-pam/ + * + * Compatibility notes, especially between Linux and Solaris: + * http://www.contrib.andrew.cmu.edu/u/shadow/pam.html + * + * The Open Group's PAM API documentation: + * http://www.opengroup.org/onlinepubs/8329799/pam_start.htm */ #ifdef HAVE_CONFIG_H @@ -63,9 +83,23 @@ struct pam_closure { /* We handle delays ourself.*/ /* Don't set this to 0 (Linux bug workaround.) */ # define PAM_NO_DELAY(pamh) pam_fail_delay ((pamh), 1) -# else /* !HAVE_PAM_FAIL_DELAY */ +#else /* !HAVE_PAM_FAIL_DELAY */ # define PAM_NO_DELAY(pamh) /* */ -# endif /* !HAVE_PAM_FAIL_DELAY */ +#endif /* !HAVE_PAM_FAIL_DELAY */ + + +/* On SunOS 5.6, and on Linux with PAM 0.64, pam_strerror() takes two args. + On some other Linux systems with some other version of PAM (e.g., + whichever Debian release comes with a 2.2.5 kernel) it takes one arg. + I can't tell which is more "recent" or "correct" behavior, so configure + figures out which is in use for us. Shoot me! + */ +#ifdef PAM_STRERROR_TWO_ARGS +# define PAM_STRERROR(pamh, status) pam_strerror((pamh), (status)) +#else /* !PAM_STRERROR_TWO_ARGS */ +# define PAM_STRERROR(pamh, status) pam_strerror((status)) +#endif /* !PAM_STRERROR_TWO_ARGS */ + /* PAM sucks in that there is no way to tell whether a particular service is configured at all. That is, there is no way to tell the difference @@ -113,6 +147,13 @@ struct pam_closure { */ +/* On SunOS 5.6, the `pam_conv.appdata_ptr' slot seems to be ignored, and + the `closure' argument to pc.conv always comes in as random garbage. + So we get around this by using a global variable instead. Shoot me! + */ +static void *suns_pam_implementation_blows = 0; + + /* 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. @@ -139,6 +180,10 @@ pam_passwd_valid_p (const char *typed_passwd, Bool verbose_p) pc.conv = &pam_conversation; pc.appdata_ptr = (void *) &c; + /* On SunOS 5.6, the `appdata_ptr' slot seems to be ignored, and the + `closure' argument to pc.conv always comes in as random garbage. */ + suns_pam_implementation_blows = (void *) &c; + /* Initialize PAM. */ @@ -146,7 +191,7 @@ pam_passwd_valid_p (const char *typed_passwd, Bool verbose_p) if (verbose_p) fprintf (stderr, "%s: pam_start (\"%s\", \"%s\", ...) ==> %d (%s)\n", blurb(), service, c.user, - status, pam_strerror (pamh, status)); + status, PAM_STRERROR (pamh, status)); if (status != PAM_SUCCESS) goto DONE; /* #### We should set PAM_TTY to the display we're using, but we @@ -159,7 +204,7 @@ pam_passwd_valid_p (const char *typed_passwd, Bool verbose_p) status = pam_set_item (pamh, PAM_TTY, strdup(tty)); if (verbose_p) fprintf (stderr, "%s: pam_set_item (p, PAM_TTY, \"%s\") ==> %d (%s)\n", - blurb(), tty, status, pam_strerror(pamh, status)); + blurb(), tty, status, PAM_STRERROR(pamh, status)); } /* Try to authenticate as the current user. @@ -168,7 +213,7 @@ pam_passwd_valid_p (const char *typed_passwd, Bool verbose_p) status = pam_authenticate (pamh, 0); if (verbose_p) fprintf (stderr, "%s: pam_authenticate (...) ==> %d (%s)\n", - blurb(), status, pam_strerror(pamh, status)); + blurb(), status, PAM_STRERROR(pamh, status)); if (status == PAM_SUCCESS) /* Win! */ goto DONE; @@ -178,14 +223,14 @@ pam_passwd_valid_p (const char *typed_passwd, Bool verbose_p) status = pam_set_item (pamh, PAM_USER, strdup(c.user)); if (verbose_p) fprintf (stderr, "%s: pam_set_item(p, PAM_USER, \"%s\") ==> %d (%s)\n", - blurb(), c.user, status, pam_strerror(pamh, status)); + blurb(), c.user, status, PAM_STRERROR(pamh, status)); if (status != PAM_SUCCESS) goto DONE; PAM_NO_DELAY(pamh); status = pam_authenticate (pamh, 0); if (verbose_p) fprintf (stderr, "%s: pam_authenticate (...) ==> %d (%s)\n", - blurb(), status, pam_strerror(pamh, status)); + blurb(), status, PAM_STRERROR(pamh, status)); DONE: if (user) free (user); @@ -203,22 +248,60 @@ pam_passwd_valid_p (const char *typed_passwd, Bool verbose_p) Bool -pam_lock_init (int argc, char **argv, Bool verbose_p) +pam_priv_init (int argc, char **argv, Bool verbose_p) { /* We have nothing to do at init-time. However, we might as well do some error checking. If "/etc/pam.d" exists and is a directory, but "/etc/pam.d/xlock" does not exist, warn that PAM probably isn't going to work. + + This is a priv-init instead of a non-priv init in case the directory + is unreadable or something (don't know if that actually happens.) */ - const char dir[] = "/etc/pam.d"; - const char file[] = "/etc/pam.d/" PAM_SERVICE_NAME; + const char dir[] = "/etc/pam.d"; + const char file[] = "/etc/pam.d/" PAM_SERVICE_NAME; + const char file2[] = "/etc/pam.conf"; struct stat st; + if (stat (dir, &st) == 0 && st.st_mode & S_IFDIR) - if (stat (file, &st) != 0) + { + if (stat (file, &st) != 0) + fprintf (stderr, + "%s: warning: %s does not exist.\n" + "%s: password authentication via PAM is unlikely to work.\n", + blurb(), file, blurb()); + } + else if (stat (file2, &st) == 0) + { + FILE *f = fopen (file2, "r"); + if (f) + { + Bool ok = False; + char buf[255]; + while (fgets (buf, sizeof(buf), f)) + if (strstr (buf, PAM_SERVICE_NAME)) + { + ok = True; + break; + } + fclose (f); + if (!ok) + { + fprintf (stderr, + "%s: warning: %s does not list the `%s' service.\n" + "%s: password authentication via PAM is unlikely to work.\n", + blurb(), file2, PAM_SERVICE_NAME, blurb()); + } + } + /* else warn about file2 existing but being unreadable? */ + } + else + { fprintf (stderr, - "%s: warning: %s does not exist.\n" + "%s: warning: neither %s nor %s exist.\n" "%s: password authentication via PAM is unlikely to work.\n", - blurb(), file, blurb()); + blurb(), file2, file, blurb()); + } /* Return true anyway, just in case. */ return True; @@ -249,6 +332,10 @@ pam_conversation (int nmsgs, struct pam_response *reply = 0; struct pam_closure *c = (struct pam_closure *) closure; + /* On SunOS 5.6, the `closure' argument always comes in as random garbage. */ + c = (struct pam_closure *) suns_pam_implementation_blows; + + reply = (struct pam_response *) calloc (nmsgs, sizeof (*reply)); if (!reply) return PAM_CONV_ERR;