diff options
Diffstat (limited to 'contrib/libpam/modules/pam_unix/pam_unix_auth.c')
-rw-r--r-- | contrib/libpam/modules/pam_unix/pam_unix_auth.c | 347 |
1 files changed, 132 insertions, 215 deletions
diff --git a/contrib/libpam/modules/pam_unix/pam_unix_auth.c b/contrib/libpam/modules/pam_unix/pam_unix_auth.c index 95f13d0abdc69..f08ea515b4d48 100644 --- a/contrib/libpam/modules/pam_unix/pam_unix_auth.c +++ b/contrib/libpam/modules/pam_unix/pam_unix_auth.c @@ -1,8 +1,7 @@ -/* $Header: /home/morgan/pam/Linux-PAM-0.59/modules/pam_unix/RCS/pam_unix_auth.c,v 1.1 1996/11/09 19:44:35 morgan Exp morgan $ */ - /* * Copyright Alexander O. Yuriev, 1996. All rights reserved. * NIS+ support by Thorsten Kukuk <kukuk@weber.uni-paderborn.de> + * Copyright Jan Rêkorajski, 1999. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,217 +34,145 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ - -/* - * $Log: pam_unix_auth.c,v $ - * - * Revision 1.9 1996/05/26 04:13:04 morgan - * added static support - * - * Revision 1.8 1996/05/21 03:51:58 morgan - * added "const" to rcsid[] definition - * - * Revision 1.7 1996/04/19 03:25:57 alex - * minor corrections. - * - * Revision 1.6 1996/04/17 01:05:05 alex - * _pam_auth_unix() cleaned up - non-authentication code is made into funcs - * and mostly moved out to support.c. - * - * Revision 1.5 1996/04/16 21:12:46 alex - * unix authentication works on Bach again. This is a tranitional stage. - * I really don't like that _pam_unix_auth() grew into a monster that does - * prompts etc etc. They should go into other functions. - * - * Revision 1.4 1996/04/07 08:06:12 morgan - * tidied up a little - * - * Revision 1.3 1996/04/07 07:34:07 morgan - * added conversation support. Now the module is capable of obtaining a - * username and a password all by itself. - * - * Revision 1.2 1996/03/29 02:31:19 morgan - * Marek Michalkiewicz's small patches for shadow support. - * - * Revision 1.1 1996/03/09 09:10:57 morgan - * Initial revision - * - */ -#ifdef linux -# define _GNU_SOURCE -# include <features.h> -#endif +/* #define DEBUG */ + +#include <security/_pam_aconf.h> -#include <stdlib.h> #include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> #include <string.h> -#define __USE_BSD #include <unistd.h> -#include <pwd.h> +#include <fcntl.h> +#include <ctype.h> #include <sys/types.h> +#include <sys/stat.h> -#ifndef NDEBUG - -#include <syslog.h> - -#endif /* NDEBUG */ - -#ifdef HAVE_SHADOW_H - -#include <shadow.h> - -#endif /* HAVE_SHADOW_H */ - -#ifndef LINUX - -#include <security/pam_appl.h> +/* indicate the following groups are defined */ -#endif /* LINUX */ +#define PAM_SM_AUTH #define _PAM_EXTERN_FUNCTIONS +#include <security/_pam_macros.h> #include <security/pam_modules.h> -static const char rcsid[] = "$Id: pam_unix_auth.c,v 1.1 1996/11/09 19:44:35 morgan Exp morgan $ pam_unix authentication functions. alex@bach.cis.temple.edu"; - -/* Define function phototypes */ - -extern char *crypt(const char *key, const char *salt); /* This should have - been in unistd.h - but it is not */ -extern int converse( pam_handle_t *pamh, - int nargs, - struct pam_message **message, - struct pam_response **response ); - -extern int _set_auth_tok( pam_handle_t *pamh, - int flags, int argc, - const char **argv ); - -static int _pam_auth_unix( pam_handle_t *pamh, - int flags, int argc, - const char **argv ); +#ifndef LINUX_PAM +#include <security/pam_appl.h> +#endif /* LINUX_PAM */ -static int _pam_set_credentials_unix ( pam_handle_t *pamh, - int flags, - int argc, - const char ** argv ) ; +#include "support.h" +/* + * PAM framework looks for these entry-points to pass control to the + * authentication module. + */ /* Fun starts here :) - * - * _pam_auth_unix() actually performs UNIX/shadow authentication + + * pam_sm_authenticate() performs UNIX/shadow authentication * - * First, if shadow support is available, attempt to perform - * authentication using shadow passwords. If shadow is not - * available, or user does not have a shadow password, fallback - * onto a normal UNIX authentication + * First, if shadow support is available, attempt to perform + * authentication using shadow passwords. If shadow is not + * available, or user does not have a shadow password, fallback + * onto a normal UNIX authentication */ -static int _pam_auth_unix( pam_handle_t *pamh, - int flags, - int argc, - const char **argv ) +#define _UNIX_AUTHTOK "-UN*X-PASS" + +#define AUTH_RETURN \ +{ \ + if (on(UNIX_LIKE_AUTH, ctrl) && ret_data) { \ + D(("recording return code for next time [%d]", \ + retval)); \ + pam_set_data(pamh, "unix_setcred_return", \ + (void *) retval, NULL); \ + } \ + D(("done. [%s]", pam_strerror(pamh, retval))); \ + return retval; \ +} + +PAM_EXTERN int pam_sm_authenticate(pam_handle_t * pamh, int flags + ,int argc, const char **argv) { - int retval; - struct passwd *pw; - const char *name; - char *p, *pp; - const char *salt; + unsigned int ctrl; + int retval, *ret_data = NULL; + const char *name, *p; -#ifdef HAVE_SHADOW_H + D(("called.")); - struct spwd *sp; + ctrl = _set_ctrl(pamh, flags, NULL, argc, argv); -#endif + /* Get a few bytes so we can pass our return value to + pam_sm_setcred(). */ + ret_data = malloc(sizeof(int)); /* get the user'name' */ - if ( (retval = pam_get_user( pamh, &name, "login: ") ) != PAM_SUCCESS ) - return retval; - - /* - * at some point we will have to make this module pay - * attention to arguments, like 'pam_first_pass' etc... - */ - - pw = getpwnam ( name ); + retval = pam_get_user(pamh, &name, "login: "); + if (retval == PAM_SUCCESS) { + /* + * Various libraries at various times have had bugs related to + * '+' or '-' as the first character of a user name. Don't take + * any chances here. Require that the username starts with an + * alphanumeric character. + */ + if (name == NULL || !isalnum(*name)) { + _log_err(LOG_ERR, pamh, "bad username [%s]", name); + retval = PAM_USER_UNKNOWN; + AUTH_RETURN + } + if (retval == PAM_SUCCESS && on(UNIX_DEBUG, ctrl)) + D(("username [%s] obtained", name)); + } else { + D(("trouble reading username")); + if (retval == PAM_CONV_AGAIN) { + D(("pam_get_user/conv() function is not ready yet")); + /* it is safe to resume this function so we translate this + * retval to the value that indicates we're happy to resume. + */ + retval = PAM_INCOMPLETE; + } + AUTH_RETURN + } - /* For NIS+, root cannot get password for lesser user */ - if (pw) { - uid_t save_euid, save_uid; + /* if this user does not have a password... */ - save_uid = getuid (); - save_euid = geteuid(); - if (setreuid (0,pw->pw_uid) >= 0) { - pw = getpwnam ( name ); - setreuid (save_uid,save_euid); - } + if (_unix_blankpasswd(ctrl, name)) { + D(("user '%s' has blank passwd", name)); + name = NULL; + retval = PAM_SUCCESS; + AUTH_RETURN } - - if ( pw && (!pw->pw_passwd || pw->pw_passwd[0] == '\0') && - !(flags & PAM_DISALLOW_NULL_AUTHTOK)) { - return PAM_SUCCESS; + /* get this user's authentication token */ + + retval = _unix_read_password(pamh, ctrl, NULL, "Password: ", NULL + ,_UNIX_AUTHTOK, &p); + if (retval != PAM_SUCCESS) { + if (retval != PAM_CONV_AGAIN) { + _log_err(LOG_CRIT, pamh, "auth could not identify password for [%s]" + ,name); + } else { + D(("conversation function is not ready yet")); + /* + * it is safe to resume this function so we translate this + * retval to the value that indicates we're happy to resume. + */ + retval = PAM_INCOMPLETE; + } + name = NULL; + AUTH_RETURN } - pam_get_item( pamh, PAM_AUTHTOK, (void*) &p ); - - if ( !p ) - { - retval = _set_auth_tok( pamh, flags, argc, argv ); - if ( retval != PAM_SUCCESS ) - return retval; - } - - /* - We have to call pam_get_item() again because value of p should - change - */ - - pam_get_item( pamh, PAM_AUTHTOK, (void*) &p ); + D(("user=%s, password=[%s]", name, p)); + /* verify the password of this user */ + retval = _unix_verify_password(pamh, name, p, ctrl); + name = p = NULL; - if (pw) - { - -#ifdef HAVE_SHADOW_H - - /* - * Support for shadow passwords on Linux and SVR4-based - * systems. Shadow passwords are optional on Linux - if - * there is no shadow password, use the non-shadow one. - */ - - sp = getspnam( name ); - if (sp && (!strcmp(pw->pw_passwd,"x"))) - { - /* TODO: check if password has expired etc. */ - salt = sp->sp_pwdp; - } - else -#endif - salt = pw->pw_passwd; - } - else - return PAM_USER_UNKNOWN; - - /* The 'always-encrypt' method does not make sense in PAM - because the framework requires return of a different - error code for non-existant users -- alex */ - - if ( ( !pw->pw_passwd ) && ( !p ) ) - if ( flags && PAM_DISALLOW_NULL_AUTHTOK ) - return PAM_SUCCESS; - else - return PAM_AUTH_ERR; - - pp = crypt(p, salt); - - if ( strcmp( pp, salt ) == 0 ) - return PAM_SUCCESS; - - return PAM_AUTH_ERR; + AUTH_RETURN } + /* * The only thing _pam_set_credentials_unix() does is initialization of * UNIX group IDs. @@ -255,45 +182,35 @@ static int _pam_auth_unix( pam_handle_t *pamh, * warned you. -- AOY */ -static int _pam_set_credentials_unix ( pam_handle_t *pamh, - int flags, - int argc, - const char **argv ) - -{ /* FIX ME: incorrect error code */ - - return PAM_SUCCESS; /* This is a wrong result code. From what I - remember from reafing one of the guides - there's an error-level saying 'N/A func' - -- AOY - */ -} - -/* - * PAM framework looks for these entry-points to pass control to the - * authentication module. - */ - -PAM_EXTERN -int pam_sm_authenticate( pam_handle_t *pamh, - int flags, - int argc, - const char **argv ) -{ - return _pam_auth_unix( pamh, flags, argc, argv ); -} - -PAM_EXTERN -int pam_sm_setcred( pam_handle_t *pamh, - int flags, - int argc, - const char **argv) +PAM_EXTERN int pam_sm_setcred(pam_handle_t * pamh, int flags + ,int argc, const char **argv) { - return _pam_set_credentials_unix ( pamh, flags, argc, argv ) ; + unsigned int ctrl; + int retval; + + D(("called.")); + + /* FIXME: it shouldn't be necessary to parse the arguments again. The + only argument we need is UNIX_LIKE_AUTH: if it was set, + pam_get_data will succeed. If it wasn't, it will fail, and we + return PAM_SUCCESS. -SRL */ + ctrl = _set_ctrl(pamh, flags, NULL, argc, argv); + retval = PAM_SUCCESS; + + if (on(UNIX_LIKE_AUTH, ctrl)) { + int *pretval = NULL; + + D(("recovering return code from auth call")); + pam_get_data(pamh, "unix_setcred_return", (const void **) pretval); + if(pretval) { + retval = *pretval; + free(pretval); + D(("recovered data indicates that old retval was %d", retval)); + } + } + return retval; } - -/* static module data */ #ifdef PAM_STATIC struct pam_module _pam_unix_auth_modstruct = { "pam_unix_auth", |