/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <macros.h>
#include <priv.h>
#include "ns_sldap.h"
#include <nss_dbdefs.h>
#include <nsswitch.h>
#include <pwd.h>
#include <shadow.h>
#include <syslog.h>
#include "passwdutil.h"
#include "utils.h"
return (PWU_NOMEM);
{ \
char nb[MAX_INT_LEN]; \
return (PWU_NOMEM); \
}
{ \
if (p[i] == NULL) \
return (PWU_NOMEM); \
i++; \
}
void **buf);
char **auth_user, int *privileged);
/*
* ldap function pointer table, used by passwdutil_init to initialize
* the global Repository-OPerations table "rops"
*/
NULL, /* checkhistory */
NULL, /* lock */
NULL /* unlock */
};
/*
*/
typedef struct {
} ldapbuf_t;
/*
* The following define's are taken from
*/
/* passwd attributes filters */
/* shadow attributes filters */
/*
* Frees up an ldapbuf_t
*/
static void
{
int i;
if (p == NULL)
return;
if (p->passwd) {
}
if (p->pwd)
if (p->spwd)
if (p->pattrs) {
for (i = 0; i < p->npattrs; i++) {
}
}
}
if (p->sattrs) {
for (i = 0; i < p->nsattrs; i++) {
}
}
}
}
/*
* int ldap_user_to_authenticate(user, rep, auth_user, privileged)
*
* If the Shadow Update functionality is enabled, then we check to
* see if the caller has 0 as the euid or has all zone privs. If so,
* the caller would be able to modify shadow(4) data stored on the
* LDAP server. Otherwise, when LDAP Shadow Update is not enabled,
* we can't determine whether the user is "privileged" in the LDAP
* sense. The operation should be attempted and will succeed if the
* user had privileges. For our purposes, we say that the user is
* password attributes.
*/
int
char **auth_user, int *privileged)
{
return (PWU_NOT_FOUND);
return (PWU_NOT_FOUND);
/*
* the privilege escalation model is euid == 0 || all zone privs
*/
if (__ns_ldap_is_shadow_update_enabled()) {
if (!priv) {
}
/*
* priv can change anyone's password,
* only authorized user isn't prompted.
*/
*privileged = 0; /* for proper prompting */
if (priv) {
if (repos_authorized()) {
*privileged = 1;
return (res);
return (res);
}
}
return (PWU_DENIED);
}
/* changing our own, not privileged */
*privileged = 0;
} else {
*privileged = 1;
/*
* specific case for authorized user
* we want 'user' to be authenticated.
*/
if (repos_authorized()) {
} else {
}
} else {
/* hmm. can't find name of current user...??? */
} else {
(int)uid);
}
}
}
return (res);
}
/*
* int ldap_getattr(name, item, rep)
*
* retrieve attributes specified in "item" for user "name".
*/
/*ARGSUSED*/
int
{
attrlist *w;
int res;
if (res != PWU_SUCCESS)
return (res);
switch (w->type) {
case ATTR_NAME:
break;
case ATTR_COMMENT:
break;
case ATTR_GECOS:
break;
case ATTR_HOMEDIR:
break;
case ATTR_SHELL:
break;
case ATTR_PASSWD:
break;
case ATTR_AGE:
break;
case ATTR_REP_NAME:
break;
/* integer values */
case ATTR_UID:
break;
case ATTR_GID:
break;
case ATTR_LSTCHG:
if (ldapbuf->shadow_update_enabled)
else
break;
case ATTR_MIN:
if (ldapbuf->shadow_update_enabled)
else
break;
case ATTR_MAX:
if (ldapbuf->shadow_update_enabled)
else
break;
case ATTR_WARN:
if (ldapbuf->shadow_update_enabled)
else
break;
case ATTR_INACT:
if (ldapbuf->shadow_update_enabled)
else
break;
case ATTR_EXPIRE:
if (ldapbuf->shadow_update_enabled)
else
break;
case ATTR_FLAG:
if (ldapbuf->shadow_update_enabled)
break;
case ATTR_FAILED_LOGINS:
break;
default:
break;
}
}
out:
return (res);
}
/*
* int ldap_getpwnam(name, items, rep, buf)
*
* There is no need to get the old values from the ldap
* server, as the update will update each item individually.
* Therefore, we only allocate a buffer that will be used by
* _update and _putpwnam to hold the attributes to update.
*
* Only when we're about to update a password, we need to retrieve
* the old password since it contains salt-information.
*/
/*ARGSUSED*/
int
void **buf)
{
/*
* [sp]attrs is treated as NULL terminated
*/
return (PWU_NOMEM);
goto out;
goto out;
if (res != PWU_SUCCESS)
goto out;
if (res != PWU_SUCCESS)
goto out;
else {
goto out;
} else
}
/* remember if shadow update is enabled */
return (PWU_SUCCESS);
out:
return (res);
}
/*
* new_attr(name, value)
*
* create a new LDAP attribute to be sent to the server
*/
{
return (NULL);
}
}
return (tmp);
}
/*
* max_present(list)
*
* returns '1' if a ATTR_MAX with value != -1 is present. (in other words:
* if password aging is to be turned on).
*/
static int
{
return (1);
else
return (0);
}
/*
* attr_addmod(attrs, idx, item, val)
*
* Adds or updates attribute 'item' in ldap_attrs list to value
* update idx if item is added
*/
static int
{
int i;
/* stringize the value or abort */
return (-1);
/* check for existence and modify existing */
for (i = 0; i < *idx; i++) {
return (-1);
return (0);
}
}
/* else add */
return (-1);
return (-1);
(*idx)++;
return (0);
}
/*
* ldap_update(items, rep, buf)
*
* create LDAP attributes in 'buf' for each attribute in 'items'.
*/
/*ARGSUSED*/
int
{
attrlist *p;
int pidx = 0;
int sidx = 0;
char *salt;
int len;
int count;
int aging_needed = 0;
int aging_set = 0;
int disable_aging;
/*
* if sp_max==0 and shadow update is enabled:
* disable passwd aging after updating the password
*/
switch (p->type) {
case ATTR_PASSWD:
/*
* There is a special case for ldap: if the
* password is to be deleted (-d to passwd),
* p->data.val_s will be NULL.
*/
if (!ldapbuf->shadow_update_enabled)
return (PWU_CHANGE_NOT_ALLOWED);
cryptlen =
sizeof ("{crypt}" NS_LDAP_NO_UNIX_PASSWORD);
return (PWU_NOMEM);
"{crypt}" NS_LDAP_NO_UNIX_PASSWORD);
} else { /* not deleting password */
return (PWU_NOMEM);
/* algorithm problem? */
"passwdutil: crypt_gensalt "
"%m");
return (PWU_UPDATE_FAILED);
}
sizeof (LOCKSTRING)-1) == 0)) {
/* append new password hash */
return (PWU_NOMEM);
}
"{crypt}%s%s",
LOCKSTRING, pwd);
} else {
sizeof ("{crypt}");
return (PWU_NOMEM);
}
"{crypt}%s", pwd);
}
}
/*
* If not managing passwordAccount,
* insert the new password in the
* passwd attr array and break.
*/
if (!ldapbuf->shadow_update_enabled) {
break;
}
/*
* Managing passwordAccount, insert the
* new password, along with lastChange and
* shadowFlag, in the shadow attr array.
*/
return (PWU_NOMEM);
return (PWU_NOMEM);
aging_needed = 1;
break;
/*
* For server policy, don't crypt the password,
* send the password as is to the server and
* let the LDAP server do its own password
* encryption
*/
break;
case ATTR_COMMENT:
/* XX correct? */
break;
case ATTR_GECOS:
if (!ldapbuf->shadow_update_enabled) {
} else {
}
break;
case ATTR_HOMEDIR:
if (!ldapbuf->shadow_update_enabled) {
} else {
}
break;
case ATTR_SHELL:
if (!ldapbuf->shadow_update_enabled) {
} else {
}
break;
/* We don't update NAME, UID, GID */
case ATTR_NAME:
case ATTR_UID:
case ATTR_GID:
/* Unsupported item */
case ATTR_AGE:
break;
case ATTR_LOCK_ACCOUNT:
case ATTR_LOCK_FAILED_LOGINS:
if (!ldapbuf->shadow_update_enabled)
break; /* not managing passwordAccount */
if (p->type == ATTR_LOCK_FAILED_LOGINS &&
return (PWU_CHANGE_NOT_ALLOWED);
}
sizeof (LOCKSTRING)-1)) != 0) {
sizeof ("{crypt}");
return (PWU_NOMEM);
}
} else {
return (PWU_NO_CHANGE);
}
return (PWU_NOMEM);
return (PWU_NOMEM);
break;
case ATTR_UNLOCK_ACCOUNT:
if (!ldapbuf->shadow_update_enabled)
break; /* not managing passwordAccount */
sizeof (LOCKSTRING)-1) == 0) {
len = (sizeof ("{crypt}") -
sizeof (LOCKSTRING)) +
if (len == sizeof ("{crypt}")) {
return (PWU_NO_CHANGE);
}
return (PWU_NOMEM);
}
return (PWU_NOMEM);
}
return (PWU_NOMEM);
}
}
break;
case ATTR_NOLOGIN_ACCOUNT:
if (!ldapbuf->shadow_update_enabled)
break; /* not managing passwordAccount */
return (PWU_NO_CHANGE);
}
/* Locked accounts stay locked on transition to NP */
sizeof (LOCKSTRING) - 1) == 0)) {
} else {
"{crypt}" NOLOGINSTRING);
}
return (PWU_NOMEM);
}
return (PWU_NOMEM);
}
break;
case ATTR_EXPIRE_PASSWORD:
if (!ldapbuf->shadow_update_enabled)
break; /* not managing passwordAccount */
NUM_TO_STR(val, 0);
break;
case ATTR_LSTCHG:
if (!ldapbuf->shadow_update_enabled)
break; /* not managing passwordAccount */
break;
case ATTR_MIN:
if (!ldapbuf->shadow_update_enabled)
break; /* not managing passwordAccount */
max_present(p->next) == 0)
return (PWU_AGING_DISABLED);
aging_set = 1;
break;
case ATTR_MAX:
if (!ldapbuf->shadow_update_enabled)
break; /* not managing passwordAccount */
/* Turn off aging. Reset min and warn too */
} else {
/* Turn account aging on */
/*
* minage was not set with command-
* line option: set to zero
*/
NUM_TO_STR(val, 0);
val);
}
/*
* If aging was turned off, we update lstchg.
* We take care not to update lstchg if the
* user has no password, otherwise the user
* might not be required to provide a password
* the next time [s]he logs in.
*
* Also, if lstchg != -1 (i.e., not set)
* we keep the old value.
*/
return (PWU_NOMEM);
return (PWU_NOMEM);
}
}
aging_set = 1;
break;
case ATTR_WARN:
if (!ldapbuf->shadow_update_enabled)
break; /* not managing passwordAccount */
return (PWU_AGING_DISABLED);
break;
case ATTR_INACT:
if (!ldapbuf->shadow_update_enabled)
break; /* not managing passwordAccount */
break;
case ATTR_EXPIRE:
if (!ldapbuf->shadow_update_enabled)
break; /* not managing passwordAccount */
break;
case ATTR_FLAG:
/* __set_authtoken_attr() blocks this */
if (!ldapbuf->shadow_update_enabled)
break; /* not managing passwordAccount */
break;
case ATTR_INCR_FAILED_LOGINS:
if (!ldapbuf->shadow_update_enabled) {
break; /* not managing passwordAccount */
}
return (PWU_NO_CHANGE);
}
break;
case ATTR_RST_FAILED_LOGINS:
if (!ldapbuf->shadow_update_enabled) {
break; /* not managing passwordAccount */
}
break;
default:
break;
}
}
/*
* If the ldap client is configured with shadow update enabled,
* then what should the new aging values look like?
*
* There are a number of different conditions
*
* a) aging is already configured: don't touch it
*
* b) disable_aging is set: disable aging
*
* c) aging is not configured: turn on default aging;
*
* b) and c) of course only if aging_needed and !aging_set.
* (i.e., password changed, and aging values not changed)
*/
/* a) aging not yet configured */
if (aging_needed && !aging_set) {
if (disable_aging) {
/* b) turn off aging */
return (PWU_NOMEM);
return (PWU_NOMEM);
-1) < 0)
return (PWU_NOMEM);
} else {
/* c) */
return (PWU_NOMEM);
return (PWU_NOMEM);
return (PWU_NOMEM);
}
}
}
return (rc);
}
/*
* ldap_to_pwu_code(error, pwd_status)
*
* translation from LDAP return values and PWU return values
*/
int
{
switch (error) {
case NS_LDAP_SUCCESS: return (PWU_SUCCESS);
case NS_LDAP_OP_FAILED: return (PWU_DENIED);
case NS_LDAP_NOTFOUND: return (PWU_NOT_FOUND);
case NS_LDAP_MEMORY: return (PWU_NOMEM);
case NS_LDAP_CONFIG: return (PWU_NOT_FOUND);
case NS_LDAP_INTERNAL:
switch (pwd_status) {
case NS_PASSWD_EXPIRED:
return (PWU_DENIED);
return (PWU_CHANGE_NOT_ALLOWED);
case NS_PASSWD_TOO_SHORT:
return (PWU_PWD_TOO_SHORT);
case NS_PASSWD_INVALID_SYNTAX:
return (PWU_PWD_INVALID);
case NS_PASSWD_IN_HISTORY:
return (PWU_PWD_IN_HISTORY);
case NS_PASSWD_WITHIN_MIN_AGE:
return (PWU_WITHIN_MIN_AGE);
default:
return (PWU_SYSTEM_ERROR);
}
default: return (PWU_SYSTEM_ERROR);
}
}
int
{
int ldaprc;
int authstried = 0;
return (NS_LDAP_MEMORY); /* map to PWU_NOMEM */
/* for admin shadow update, dn and pwd will be set later in libsldap */
if ((flags & NS_LDAP_UPDATE_SHADOW) == 0) {
/* Fill in the user name and password */
goto out;
}
/* get host certificate path, if one is configured */
if (ldaprc != NS_LDAP_SUCCESS)
goto out;
/* Load the service specific authentication method */
&errorp);
if (ldaprc != NS_LDAP_SUCCESS)
goto out;
/*
* if authpp is null, there is no serviceAuthenticationMethod
* try default authenticationMethod
*/
&errorp);
if (ldaprc != NS_LDAP_SUCCESS)
goto out;
}
/*
* if authpp is still null, then can not authenticate, syslog
* error message and return error
*/
"passwdutil: no legal LDAP authentication method configured");
goto out;
}
/*
* Walk the array and try all authentication methods in order except
* for "none".
*/
continue;
authstried++;
(const ns_ldap_attr_t * const *)attrs,
if (ldaprc == NS_LDAP_SUCCESS) {
goto out;
}
/*
* if change not allowed due to configuration, indicate so
* to the caller
*/
if (ldaprc == NS_LDAP_CONFIG &&
goto out;
}
/*
* other errors might need to be added to this list, for
* the current supported mechanisms this is sufficient
*/
if ((ldaprc == NS_LDAP_INTERNAL) &&
goto out;
}
/*
* If there is error related to password policy,
* return it to caller
*/
if ((ldaprc == NS_LDAP_INTERNAL) &&
goto out;
} else
/* we don't really care about the error, just clean it up */
if (errorp)
(void) __ns_ldap_freeError(&errorp);
}
if (authstried == 0) {
"passwdutil: no legal LDAP authentication method configured");
goto out;
}
out:
if (credp)
(void) __ns_ldap_freeCred(&credp);
if (authpp)
(void) __ns_ldap_freeParam((void ***)&authpp);
if (errorp)
(void) __ns_ldap_freeError(&errorp);
return (result);
}
/*
* ldap_putpwnam(name, oldpw, rep, buf)
*
* update the LDAP server with the attributes contained in 'buf'.
*/
/*ARGSUSED*/
int
{
int res;
int pwd_status;
return (PWU_NOT_FOUND);
/*
* convert name of user whose attributes we are changing
* to a distinguished name
*/
if (res != NS_LDAP_SUCCESS)
goto out;
/* update shadow via ldap_cachemgr if it is enabled */
if (ldapbuf->shadow_update_enabled &&
/*
* flag NS_LDAP_UPDATE_SHADOW indicates the shadow update
* should be done via ldap_cachemgr
*/
goto out;
}
/*
* The LDAP server checks whether we are permitted to perform
* the requested change. We need to send the name of the user
* who is executing this piece of code, together with his
* current password to the server.
* password, this will simply be the OLD password that is to
* be changed.
* Specific case if the user who is executing this piece
* of code is root. We will then issue the LDAP request
* with the DN of the user we want to change the passwd of.
*/
/*
* create a dn for the user who is executing this code
*/
if (uid == 0) {
goto out;
}
/*
* User executing this code is not known to the LDAP
* server. This operation is to be denied
*/
goto out;
}
if (res != NS_LDAP_SUCCESS)
goto out;
&pwd_status, 0);
} else
out:
}