freebsd-dev/contrib/libpam/modules/pam_pwdb/pam_unix_pwupd.-c

273 lines
8.3 KiB
Plaintext
Raw Normal View History

/*
* $Id: pam_unix_pwupd.-c,v 1.4 1997/01/04 20:35:32 morgan Exp morgan $
*
* This file contains the routines to update the passwd databases.
*
* $Log: pam_unix_pwupd.-c,v $
* Revision 1.4 1997/01/04 20:35:32 morgan
* minor comment change
*
* Revision 1.3 1996/12/01 03:05:54 morgan
* debugging with _pam_macros.h
*
* Revision 1.2 1996/11/10 21:05:09 morgan
* pwdb conversion
*
*
*/
/* Implementation */
static int unix_update_db(pam_handle_t *pamh, int ctrl, const char *user,
const char *pass_old, const char *pass_new)
{
const struct pwdb *pw=NULL;
const struct pwdb_entry *pwe=NULL;
pwdb_flag flag;
int retval, i;
D(("called."));
/* obtain default user record */
retval = pwdb_locate("user", PWDB_DEFAULT, user, PWDB_ID_UNKNOWN, &pw);
if (retval == PWDB_PASS_PHRASE_REQD) {
retval = pwdb_set_entry(pw, "pass_phrase"
, pass_old, 1+strlen(pass_old)
, NULL, NULL, 0);
if (retval == PWDB_SUCCESS)
retval = pwdb_locate("user", pw->source, user
, PWDB_ID_UNKNOWN, &pw);
}
pass_old = NULL;
if ( retval != PWDB_SUCCESS ) {
_log_err(LOG_ALERT, "cannot identify user %s (uid=%d)"
, user, getuid() );
pass_new = NULL;
if (pw)
(void) pwdb_delete(&pw);
return PAM_USER_UNKNOWN;
}
/* check that we can update all of the default databases */
retval = pwdb_flags("user", pw->source, &flag);
if ( retval != PWDB_SUCCESS || ( pwdb_on(flag,PWDB_F_NOUPDATE) ) ) {
_log_err(LOG_ERR, "cannot update default database for user %s"
, user );
pass_new = NULL;
if (pw)
(void) pwdb_delete(&pw);
return PAM_PERM_DENIED;
}
/* If there was one, we delete the "last_change" entry */
retval = pwdb_get_entry(pw, "last_change", &pwe);
if (retval == PWDB_SUCCESS) {
(void) pwdb_entry_delete(&pwe);
pwdb_set_entry(pw, "last_change", NULL, -1, NULL, NULL, 0);
}
/*
* next check for pam.conf specified databases: shadow etc... [In
* other words, pam.conf indicates which database the password is
* to be subsequently placed in: this is password migration].
*/
if ( on(UNIX__SET_DB, ctrl) ) {
const char *db_token;
pwdb_type pt = _PWDB_MAX_TYPES;
if ( on(UNIX_UNIX, ctrl) ) {
db_token = "U"; /* XXX - should be macro */
pt = PWDB_UNIX;
} else if ( on(UNIX_SHADOW, ctrl) ) {
db_token = "x"; /* XXX - should be macro */
pt = PWDB_SHADOW;
} else if ( on(UNIX_RADIUS, ctrl) ) {
db_token = "R"; /* XXX - is this ok? */
pt = PWDB_RADIUS;
} else {
_log_err(LOG_ALERT
, "cannot determine database to use for authtok");
pass_new = NULL;
if (pw)
(void) pwdb_delete(&pw);
return PAM_ABORT; /* we're in trouble */
}
/*
* Attempt to update the indicated database (only)
*/
{
pwdb_type tpt[2];
tpt[0] = pt;
tpt[1] = _PWDB_MAX_TYPES;
/* Can we set entry in database? */
retval = pwdb_flags("user", tpt, &flag);
if (retval == PWDB_SUCCESS && !pwdb_on(flag,PWDB_F_NOUPDATE)) {
/* YES. This database is available.. */
/* Only update if it is not already in the default list */
for (i=0; pw->source[i] != _PWDB_MAX_TYPES
&& pw->source[i] != pt ; ++i);
if (pw->source[i] == _PWDB_MAX_TYPES) {
const struct pwdb *tpw=NULL;
/* copy database entry */
if ((retval = pwdb_new(&tpw, 10)) != PWDB_SUCCESS
|| (retval = pwdb_merge(tpw, pw, PWDB_TRUE))
!= PWDB_SUCCESS) {
_log_err(LOG_CRIT, "failed to obtain new pwdb: %s"
, pwdb_strerror(retval));
retval = PAM_ABORT;
} else
retval = PAM_SUCCESS;
/* set db_token */
if (retval == PAM_SUCCESS) {
retval = pwdb_set_entry(tpw, "defer_pass", db_token
, 1+strlen(db_token)
, NULL, NULL, 0);
if (retval != PWDB_SUCCESS) {
_log_err(LOG_ALERT, "set defer_pass -> %s"
, pwdb_strerror(retval));
retval = PAM_PERM_DENIED;
} else
retval = PAM_SUCCESS;
}
/* update specific database */
if (retval == PAM_SUCCESS) {
retval = pwdb_replace("user", tpt
, user, PWDB_ID_UNKNOWN, &tpw);
if (retval != PWDB_SUCCESS) {
const char *service=NULL;
(void) pam_get_item(pamh, PAM_SERVICE
, (const void **)&service);
_log_err(LOG_ALERT
, "(%s) specified database failed: %s"
, service
, pwdb_strerror(retval));
retval = PAM_PERM_DENIED;
} else {
retval = PAM_SUCCESS;
}
}
/* clean up temporary pwdb */
if (tpw)
(void) pwdb_delete(&tpw);
}
/* we can properly adopt new defer_pass */
if (retval == PAM_SUCCESS) {
/* failing here will mean we go back to former
password location */
(void) pwdb_set_entry(pw, "defer_pass", db_token
, 1+strlen(db_token), NULL, NULL, 0);
}
}
}
}
/*
* the password will now be placed in appropriate (perhaps original) db
*/
retval = pwdb_get_entry(pw, "uid", &pwe);
if (retval != PWDB_SUCCESS) {
_log_err(LOG_ALERT, "no uid!? (%s); %s", user, pwdb_strerror(retval));
pass_new = NULL;
if (pw)
(void) pwdb_delete(&pw);
return PAM_USER_UNKNOWN;
}
/* insert the passwd into the 'pw' structure */
retval = pwdb_set_entry(pw, "passwd", pass_new, 1+strlen(pass_new)
, NULL, NULL, 0);
pass_new = NULL;
if (retval != PWDB_SUCCESS) {
_log_err(LOG_ALERT, "set2 failed; %s", pwdb_strerror(retval));
if (pw)
(void) pwdb_delete(&pw);
return PAM_AUTHTOK_LOCK_BUSY;
}
retval = pwdb_replace("user", pw->source, user
, *((uid_t *)pwe->value), &pw);
if (retval != PWDB_SUCCESS) {
_log_err(LOG_ALERT, "user (%s/%d) update failed; %s"
, user, *((uid_t *)pwe->value), pwdb_strerror(retval));
if (pw)
(void) pwdb_delete(&pw);
(void) pwdb_entry_delete(&pwe);
return PAM_ABORT;
}
if (retval != PWDB_SUCCESS) {
_log_err(LOG_ALERT, "user (%s/%d) update failed; %s"
, user, *((uid_t *)pwe->value), pwdb_strerror(retval));
retval = PAM_ABORT;
} else {
/* password updated */
_log_err(LOG_INFO, "password for (%s/%d) changed by (%s/%d)"
, user, *((uid_t *)pwe->value), getlogin(), getuid());
retval = PAM_SUCCESS;
}
/* tidy up */
(void) pwdb_entry_delete(&pwe);
if (pw)
(void) pwdb_delete(&pw);
return retval;
}
/* ******************************************************************
* Copyright (c) Andrew Morgan <morgan@parc.power.net> 1996,1997.
* Copyright (c) Cristian Gafton, <gafton@redhat.com> 1996, 1997.
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, and the entire permission notice in its entirety,
* including the disclaimer of warranties.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* ALTERNATIVELY, this product may be distributed under the terms of
* the GNU Public License, in which case the provisions of the GPL are
* required INSTEAD OF the above restrictions. (This clause is
* necessary due to a potential bad interaction between the GPL and
* the restrictions contained in a BSD-style copyright.)
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/